diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..c544bf6b3a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Lineendings +*.sln eol=crlf +*.vcproj eol=crlf +*.vcxproj* eol=crlf +*.patch eol=lf + +# Whitespace rules +# strict (no trailing, no tabs) +*.cpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol +*.h whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol + +# normal (no trailing) +*.sql whitespace=trailing-space,space-before-tab,cr-at-eol +*.txt whitespace=trailing-space,space-before-tab,cr-at-eol + +# special files which must ignore whitespace +*.patch whitespace=-trailing-space diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..a07f67a582 --- /dev/null +++ b/.gitignore @@ -0,0 +1,93 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git-ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +# Normal rules +# +.* +*.o +*.o.* +*.a +*.so +*.so.dbg +*.bin +*.gz + +# +# Top-level generic files +# +tags +TAGS +INSTALL + +!.gitignore +!.gitattributes + +Makefile.in +Makefile + +# +# Editors / debuggers / other output files +# +*~ +*.bak +*.orig +callgrind.out.* + +# +# Git stuff +# +# stgit directories +patches-* + +# +# System-internal temporary files +# +revision.h + +# +# VS binaries output +# +*.sln +bin/* +VC100/* +VC90/* + +# +# VS temporary files +# +*.ncb +*.suo +*.sdf +*.opensdf +*.sln.cache +*.vsp +ipch +*.user + +*__Win32_Debug* +*__x64_Debug* +*__Win32_Release* +*__x64_Release* + +# +# CMake temporary files +# +CMakeFiles +CMakeCache.txt +cmake_install.cmake + +# +# OS specific +# +# MacOS +.DS_Store + +# +# Special exceptions +# diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..1260c0741b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,151 @@ +# +# Copyright (C) 2005-2012 MaNGOS +# Copyright (C) 2011-2014 MangosR2 +# +# This program is free software; you can redistribute it and/or modify +# 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 +# + +set(LIBRARY_NAME mangosscriptR2) + +file(GLOB_RECURSE mangosscript_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp *.h) + +source_group("Other" + REGULAR_EXPRESSION .* +) + +foreach(SRC ${mangosscript_SRCS}) + get_filename_component(PTH ${SRC} PATH) + if(PTH) + if(NOT XCODE) # FIXME: Xcode Generator has bug with nested dirs + string(REPLACE "/" "\\\\" PTH ${PTH}) + endif() + source_group(${PTH} FILES ${SRC}) + endif() +endforeach(SRC) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/base + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/src/shared + ${CMAKE_SOURCE_DIR}/src/framework + ${CMAKE_SOURCE_DIR}/src/game + ${CMAKE_SOURCE_DIR}/dep/include + ${CMAKE_SOURCE_DIR}/dep/include/g3dlite + ${CMAKE_BINARY_DIR} + ${ACE_INCLUDE_DIR} + ${MYSQL_INCLUDE_DIR} +) + +if(PCH) + include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +add_library(${LIBRARY_NAME} SHARED + ${mangosscript_SRCS} +) + +if(WIN32) + SET_TARGET_PROPERTIES(mangosd PROPERTIES + ENABLE_EXPORTS TRUE) + + target_link_libraries(${LIBRARY_NAME} + mangosd + ${ACE_LIBRARIES} +# debug ${WIN_DEBUGLIBS} + ) +endif() + +add_dependencies(${LIBRARY_NAME} revision.h) +add_dependencies(${LIBRARY_NAME} shared) + +# seems as need only for linking +#add_dependencies(${LIBRARY_NAME} game) + +if(NOT ACE_USE_EXTERNAL) + add_dependencies(${LIBRARY_NAME} ACE_Project) +# add_dependencies(${LIBRARY_NAME} ace) +endif() + +if(UNIX) + set(mangosscript_LINK_FLAGS "-pthread") + if(APPLE) + set(mangosscript_LINK_FLAGS "-framework Carbon ${mangosscript_LINK_FLAGS}") + # Needed for the linking because of the missing symbols + set(mangosscript_LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup ${mangosscript_LINK_FLAGS}") + endif() + + if(APPLE) + set(mangosscript_PROPERTIES INSTALL_NAME_DIR "${LIBS_DIR}") + else() + set(mangosscript_PROPERTIES INSTALL_RPATH ${LIBS_DIR}) + endif() + + # Run out of build tree + set(mangosscript_PROPERTIES + ${mangosscript_PROPERTIES} + BUILD_WITH_INSTALL_RPATH OFF + ) + + set_target_properties(${LIBRARY_NAME} PROPERTIES + LINK_FLAGS ${mangosscript_LINK_FLAGS} + ${mangosscript_PROPERTIES} + ) +endif() + +# Because size for linker is to big - seriously ?! +if(WIN32) + set_target_properties(${LIBRARY_NAME} PROPERTIES + LINK_FLAGS_DEBUG "/DEBUG /INCREMENTAL:NO" + ) +endif() + +## libtool settings +# API versioning +# Link against dependencies +# How to increase version info: +# - only bug fixes implemented: +# bump the version to LTMANGOS_CURRENT:LTMANGOS_REVISION+1:LTMANGOS_AGE +# - augmented the interface: +# bump the version to LTMANGOS_CURRENT+1:0:LTMANGOS_AGE+1 +# - broken old interface: +# bump the version to LTMANGOS_CURRENT+1:0:0 +# set(LTMANGOS_CURRENT 0) +# set(LTMANGOS_REVISION 0) +# set(LTMANGOS_AGE 0) +# set_target_properties(script PROPERTIES LINK_FLAGS +# "-version-info ${LTMANGOS_CURRENT}:${LTMANGOS_REVISION}:${LTMANGOS_AGE}" +# ) + +# Generate precompiled header +if(PCH) + if(MSVC OR XCODE) + if(MSVC) + set(mangosscriptR2_pch "${CMAKE_CURRENT_SOURCE_DIR}/include/precompiled.cpp") + endif() + add_native_precompiled_header(${LIBRARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/include/precompiled.h) + elseif(CMAKE_COMPILER_IS_GNUCXX) + add_precompiled_header(${LIBRARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/include/precompiled.h) + endif() +endif() + +# LIBRARY = dyld / so, RUNTIME = dll +install(TARGETS ${LIBRARY_NAME} + LIBRARY DESTINATION ${LIBS_DIR} + RUNTIME DESTINATION ${LIBS_DIR} +) + +install(FILES scriptdev2.conf.dist.in DESTINATION ${CONF_DIR} RENAME scriptdev2.conf.dist) diff --git a/FEATURES.txt b/FEATURES.txt new file mode 100644 index 0000000000..4c79ecff80 --- /dev/null +++ b/FEATURES.txt @@ -0,0 +1,125 @@ +Classic Instances +================= + +The Deadmines +Ragefire Chasm +Wailing Caverns +Shadowfang Keep +The Stockade +Blackfathom Deeps +Gnomeregan +Scarlet Monastery +Razorfen Kraul +Maraudon +Uldaman +Scholomance +Razorfen Downs +Dire Maul +Zul'Farrak +Stratholme +Sunken Temple +Blackrock Depths +Blackrock Spire +Zul'Gurub +Ruins of Ahn'Qiraj +Temple of Ahn'Qiraj +Blackwing Lair +Molten Core + +The Burning Crusade Instances +============================= + +Hellfire Citadel: Hellfire Ramparts +Hellfire Citadel: The Blood Furnace +Hellfire Citadel: The Shattered Halls +Coilfang Reservoir: The Slave Pens +Coilfang Reservoir: The Underbog +Coilfang Reservoir: The Steamvault +Auchindoun: Mana-Tombs +Auchindoun: Auchenai Crypts +Auchindoun: Sethekk Halls +Auchindoun: Shadow Labyrinth +Caverns of Time: Old Hillsbrad Foothills +Caverns of Time: The Black Morass +Tempest Keep: The Arcatraz +Tempest Keep: The Botanica +Tempest Keep: The Mechanar +Zul'Aman +Magisters' Terrace +Gruul's Lair +Hellfire Citadel: Magtheridon's Lair +Coilfang Reservoir: Serpentshrine Cavern +Tempest Keep: The Eye +Caverns of Time: Hyjal Summit +Karazhan +Sunwell Plateau +Black Temple + +Wrath of the Lich King Instances +================================ + +Utgarde Keep: Utgarde Keep +Utgarde Keep: Utgarde Pinnacle +The Nexus: The Nexus +The Nexus: The Oculus +Azjol-Nerub: Azjol-Nerub +Azjol-Nerub: Ahn'kahet: The Old Kingdom +Drak'Tharon Keep +The Violet Hold +Gundrak +Caverns of Time: The Culling of Stratholme +Ulduar: Halls of Stone +Ulduar: Halls of Lightning +Crusaders' Coliseum: Trial of the Champion +Icecrown Citadel: The Forge of Souls +Icecrown Citadel: Pit of Saron +Icecrown Citadel: Halls of Reflection +Vault of Archavon +Crusaders' Coliseum: Trial of the Crusader RSA version. Fully implemented. +The Nexus: The Eye of Eternity +Icecrown Citadel +Naxxramas +Wyrmrest Temple: The Obsidian Sanctum +Onyxia's Lair +Ulduar SD2 instance controller + +The Ruby Sanctum RSA version. Fully implemented. + +Cataclysm Instances +=================== + +Abyssal Maw: Throne of the Tides NYI +Blackrock Caverns NYI +The Vortex Pinnacle NYI +The Stonecore NYI +Grim Batol NYI +Lost City of the Tol'vir NYI +Zul'Aman NYI +Well of Eternity NYI +Halls of Origination NYI +End Time NYI +Hour of Twilight NYI +Zul'Gurub NYI +Baradin Hold NYI +Blackwing Descent NYI +Dragon Soul NYI +Firelands NYI +Throne of the Four Winds NYI +The Bastion of Twilight NYI + +Mists of Pandaria Instances +=========================== + +Scarlet Halls NYI +Scarlet Monastery NYI +Scholomance NYI +Temple of the Jade Serpent NYI +Stormstout Brewery NYI +Shado-Pan Monastery NYI +Mogu'shan Palace NYI +Siege of Niuzao Temple NYI +Gate of the Setting Sun NYI +Terrace of Endless Spring NYI +Heart of Fear NYI +Mogu'shan Vaults NYI +Siege of Orgrimmar NYI +Throne of Thunder NYI diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 5067f66202..0000000000 --- a/Makefile.am +++ /dev/null @@ -1,613 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse -SUBDIRS = sql - -BUILT_SOURCES = revision.h -CLEANFILES = revision.h -## CPP flags for includes, defines, etc. -AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../shared/ -I$(srcdir)/../../framework/ -I$(srcdir)/../../game/ -I$(srcdir)/include/ -I$(srcdir)/base/ -DSYSCONFDIR=\"$(sysconfdir)/\" - -## Build MaNGOS script library as shared library. -# libmangosscript shared library will later be reused by world server daemon. -lib_LTLIBRARIES = libmangosscript.la -libmangosscript_la_SOURCES = \ -ScriptMgr.cpp \ -ScriptMgr.h \ -config.h \ -base/escort_ai.cpp \ -base/escort_ai.h \ -base/follower_ai.cpp \ -base/follower_ai.h \ -base/guard_ai.cpp \ -base/guard_ai.h \ -include/precompiled.cpp \ -include/precompiled.h \ -include/sc_creature.cpp \ -include/sc_creature.h \ -include/sc_gossip.h \ -include/sc_grid_searchers.cpp \ -include/sc_grid_searchers.h \ -include/sc_instance.cpp \ -include/sc_instance.h \ -scripts/battlegrounds/battleground.cpp \ -scripts/eastern_kingdoms/alterac_mountains.cpp \ -scripts/eastern_kingdoms/arathi_highlands.cpp \ -scripts/eastern_kingdoms/blasted_lands.cpp \ -scripts/eastern_kingdoms/boss_kruul.cpp \ -scripts/eastern_kingdoms/burning_steppes.cpp \ -scripts/eastern_kingdoms/dun_morogh.cpp \ -scripts/eastern_kingdoms/eastern_plaguelands.cpp \ -scripts/eastern_kingdoms/elwynn_forest.cpp \ -scripts/eastern_kingdoms/eversong_woods.cpp \ -scripts/eastern_kingdoms/ghostlands.cpp \ -scripts/eastern_kingdoms/hinterlands.cpp \ -scripts/eastern_kingdoms/ironforge.cpp \ -scripts/eastern_kingdoms/isle_of_queldanas.cpp \ -scripts/eastern_kingdoms/loch_modan.cpp \ -scripts/eastern_kingdoms/redridge_mountains.cpp \ -scripts/eastern_kingdoms/searing_gorge.cpp \ -scripts/eastern_kingdoms/silvermoon_city.cpp \ -scripts/eastern_kingdoms/silverpine_forest.cpp \ -scripts/eastern_kingdoms/stormwind_city.cpp \ -scripts/eastern_kingdoms/stranglethorn_vale.cpp \ -scripts/eastern_kingdoms/swamp_of_sorrows.cpp \ -scripts/eastern_kingdoms/tirisfal_glades.cpp \ -scripts/eastern_kingdoms/undercity.cpp \ -scripts/eastern_kingdoms/western_plaguelands.cpp \ -scripts/eastern_kingdoms/westfall.cpp \ -scripts/eastern_kingdoms/wetlands.cpp \ -scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp \ -scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h \ -scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp \ -scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp \ -scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp \ -scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h \ -scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp \ -scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp \ -scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp \ -scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp \ -scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp \ -scripts/eastern_kingdoms/deadmines/deadmines.cpp \ -scripts/eastern_kingdoms/deadmines/deadmines.h \ -scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp \ -scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp \ -scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp \ -scripts/eastern_kingdoms/gnomeregan/gnomeregan.h \ -scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp \ -scripts/eastern_kingdoms/karazhan/boss_curator.cpp \ -scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp \ -scripts/eastern_kingdoms/karazhan/boss_midnight.cpp \ -scripts/eastern_kingdoms/karazhan/boss_moroes.cpp \ -scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp \ -scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp \ -scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp \ -scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp \ -scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp \ -scripts/eastern_kingdoms/karazhan/bosses_opera.cpp \ -scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp \ -scripts/eastern_kingdoms/karazhan/karazhan.cpp \ -scripts/eastern_kingdoms/karazhan/karazhan.h \ -scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp \ -scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp \ -scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp \ -scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp \ -scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp \ -scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp \ -scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h \ -scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp \ -scripts/eastern_kingdoms/molten_core/boss_garr.cpp \ -scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp \ -scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp \ -scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp \ -scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp \ -scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp \ -scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp \ -scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp \ -scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp \ -scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp \ -scripts/eastern_kingdoms/molten_core/molten_core.cpp \ -scripts/eastern_kingdoms/molten_core/molten_core.h \ -scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp \ -scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h \ -scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp \ -scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp \ -scripts/eastern_kingdoms/scholomance/boss_doctor_theolen_krastinov.cpp \ -scripts/eastern_kingdoms/scholomance/boss_illucia_barov.cpp \ -scripts/eastern_kingdoms/scholomance/boss_instructor_malicia.cpp \ -scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp \ -scripts/eastern_kingdoms/scholomance/boss_kormok.cpp \ -scripts/eastern_kingdoms/scholomance/boss_lord_alexei_barov.cpp \ -scripts/eastern_kingdoms/scholomance/boss_lorekeeper_polkelt.cpp \ -scripts/eastern_kingdoms/scholomance/boss_ras_frostwhisper.cpp \ -scripts/eastern_kingdoms/scholomance/boss_the_ravenian.cpp \ -scripts/eastern_kingdoms/scholomance/boss_vectus.cpp \ -scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp \ -scripts/eastern_kingdoms/scholomance/scholomance.h \ -scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp \ -scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp \ -scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h \ -scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp \ -scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp \ -scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp \ -scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp \ -scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp \ -scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp \ -scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp \ -scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp \ -scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp \ -scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp \ -scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp \ -scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp \ -scripts/eastern_kingdoms/stratholme/stratholme.cpp \ -scripts/eastern_kingdoms/stratholme/stratholme.h \ -scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp \ -scripts/eastern_kingdoms/sunken_temple/sunken_temple.h \ -scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp \ -scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp \ -scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp \ -scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp \ -scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h \ -scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp \ -scripts/eastern_kingdoms/uldaman/uldaman.cpp \ -scripts/eastern_kingdoms/uldaman/uldaman.h \ -scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp \ -scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp \ -scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp \ -scripts/eastern_kingdoms/zulaman/boss_janalai.cpp \ -scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp \ -scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp \ -scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp \ -scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp \ -scripts/eastern_kingdoms/zulaman/zulaman.cpp \ -scripts/eastern_kingdoms/zulaman/zulaman.h \ -scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_marli.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp \ -scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp \ -scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp \ -scripts/eastern_kingdoms/zulgurub/zulgurub.h \ -scripts/examples/example_creature.cpp \ -scripts/examples/example_escort.cpp \ -scripts/examples/example_gossip_codebox.cpp \ -scripts/examples/example_misc.cpp \ -scripts/kalimdor/ashenvale.cpp \ -scripts/kalimdor/azshara.cpp \ -scripts/kalimdor/azuremyst_isle.cpp \ -scripts/kalimdor/bloodmyst_isle.cpp \ -scripts/kalimdor/boss_azuregos.cpp \ -scripts/kalimdor/darkshore.cpp \ -scripts/kalimdor/desolace.cpp \ -scripts/kalimdor/dustwallow_marsh.cpp \ -scripts/kalimdor/felwood.cpp \ -scripts/kalimdor/feralas.cpp \ -scripts/kalimdor/moonglade.cpp \ -scripts/kalimdor/mulgore.cpp \ -scripts/kalimdor/orgrimmar.cpp \ -scripts/kalimdor/silithus.cpp \ -scripts/kalimdor/stonetalon_mountains.cpp \ -scripts/kalimdor/tanaris.cpp \ -scripts/kalimdor/teldrassil.cpp \ -scripts/kalimdor/the_barrens.cpp \ -scripts/kalimdor/thousand_needles.cpp \ -scripts/kalimdor/thunder_bluff.cpp \ -scripts/kalimdor/ungoro_crater.cpp \ -scripts/kalimdor/winterspring.cpp \ -scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h \ -scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp \ -scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h \ -scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp \ -scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp \ -scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp \ -scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp \ -scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp \ -scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp \ -scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h \ -scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp \ -scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp \ -scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp \ -scripts/kalimdor/caverns_of_time/hyjal/hyjal.h \ -scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp \ -scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h \ -scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp \ -scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp \ -scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp \ -scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp \ -scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp \ -scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp \ -scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h \ -scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp \ -scripts/kalimdor/maraudon/boss_landslide.cpp \ -scripts/kalimdor/maraudon/boss_noxxion.cpp \ -scripts/kalimdor/maraudon/boss_princess_theradras.cpp \ -scripts/kalimdor/onyxias_lair/boss_onyxia.cpp \ -scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp \ -scripts/kalimdor/onyxias_lair/onyxias_lair.h \ -scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp \ -scripts/kalimdor/razorfen_downs/razorfen_downs.cpp \ -scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp \ -scripts/kalimdor/razorfen_kraul/razorfen_kraul.h \ -scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp \ -scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h \ -scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp \ -scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h \ -scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp \ -scripts/kalimdor/wailing_caverns/wailing_caverns.h \ -scripts/kalimdor/zulfarrak/boss_zumrah.cpp \ -scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp \ -scripts/kalimdor/zulfarrak/zulfarrak.cpp \ -scripts/kalimdor/zulfarrak/zulfarrak.h \ -scripts/northrend/borean_tundra.cpp \ -scripts/northrend/dalaran.cpp \ -scripts/northrend/dragonblight.cpp \ -scripts/northrend/grizzly_hills.cpp \ -scripts/northrend/icecrown.cpp \ -scripts/northrend/sholazar_basin.cpp \ -scripts/northrend/storm_peaks.cpp \ -scripts/northrend/howling_fjord.cpp \ -scripts/northrend/zuldrak.cpp \ -scripts/northrend/azjol-nerub/ahnkahet/boss_jedoga.cpp \ -scripts/northrend/azjol-nerub/ahnkahet/boss_nadox.cpp \ -scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp \ -scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp \ -scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h \ -scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp \ -scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h \ -scripts/northrend/azjol-nerub/azjol-nerub/boss_anubarak.cpp \ -scripts/northrend/azjol-nerub/azjol-nerub/boss_hadronox.cpp \ -scripts/northrend/azjol-nerub/azjol-nerub/boss_krikthir.cpp \ -scripts/northrend/azjol-nerub/azjol-nerub/instance_azjol-nerub.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_anubarak_trial.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_faction_champions.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_jaraxxus.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_northrend_beasts.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_twin_valkyr.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/instance_trial_of_the_crusader.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.cpp \ -scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.h \ -scripts/northrend/draktharon_keep/boss_novos.cpp \ -scripts/northrend/draktharon_keep/boss_tharonja.cpp \ -scripts/northrend/draktharon_keep/boss_trollgore.cpp \ -scripts/northrend/draktharon_keep/draktharon_keep.h \ -scripts/northrend/draktharon_keep/instance_draktharon_keep.cpp \ -scripts/northrend/gundrak/boss_colossus.cpp \ -scripts/northrend/gundrak/boss_eck.cpp \ -scripts/northrend/gundrak/boss_galdarah.cpp \ -scripts/northrend/gundrak/boss_moorabi.cpp \ -scripts/northrend/gundrak/boss_sladran.cpp \ -scripts/northrend/gundrak/gundrak.h \ -scripts/northrend/gundrak/instance_gundrak.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falryn.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_lich_king.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_marwyn.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_gafrost.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_krick_and_ick.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.h \ -scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_bronjahm.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp \ -scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.h \ -scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/blood_prince_council.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_blood_queen_lanathel.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_deathbringer_saurfang.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_festergut.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lady_deathwhisper.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lord_marrowgar.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_professor_putricide.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_rotface.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_sindragosa.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_the_lich_king.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/boss_valithria_dreamwalker.cpp \ -scripts/northrend/icecrown_citadel/icecrown_citadel/gunship_battle.cpp \ -scripts/northrend/naxxramas/boss_anubrekhan.cpp \ -scripts/northrend/naxxramas/boss_faerlina.cpp \ -scripts/northrend/naxxramas/boss_four_horsemen.cpp \ -scripts/northrend/naxxramas/boss_gluth.cpp \ -scripts/northrend/naxxramas/boss_gothik.cpp \ -scripts/northrend/naxxramas/boss_grobbulus.cpp \ -scripts/northrend/naxxramas/boss_heigan.cpp \ -scripts/northrend/naxxramas/boss_kelthuzad.cpp \ -scripts/northrend/naxxramas/boss_loatheb.cpp \ -scripts/northrend/naxxramas/boss_maexxna.cpp \ -scripts/northrend/naxxramas/boss_noth.cpp \ -scripts/northrend/naxxramas/boss_patchwerk.cpp \ -scripts/northrend/naxxramas/boss_razuvious.cpp \ -scripts/northrend/naxxramas/boss_sapphiron.cpp \ -scripts/northrend/naxxramas/boss_thaddius.cpp \ -scripts/northrend/naxxramas/naxxramas.h \ -scripts/northrend/naxxramas/instance_naxxramas.cpp \ -scripts/northrend/nexus/nexus/boss_anomalus.cpp \ -scripts/northrend/nexus/nexus/boss_keristrasza.cpp \ -scripts/northrend/nexus/nexus/boss_ormorok.cpp \ -scripts/northrend/nexus/nexus/boss_telestra.cpp \ -scripts/northrend/nexus/nexus/nexus.h \ -scripts/northrend/nexus/nexus/instance_nexus.cpp \ -scripts/northrend/obsidian_sanctum/boss_sartharion.cpp \ -scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp \ -scripts/northrend/obsidian_sanctum/obsidian_sanctum.h \ -scripts/northrend/ruby_sanctum/boss_halion.cpp \ -scripts/northrend/ruby_sanctum/boss_baltharus.cpp \ -scripts/northrend/ruby_sanctum/boss_saviana.cpp \ -scripts/northrend/ruby_sanctum/boss_zarithian.cpp \ -scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp \ -scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp \ -scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp \ -scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp \ -scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h \ -scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp \ -scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp \ -scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp \ -scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp \ -scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h \ -scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp \ -scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp \ -scripts/northrend/ulduar/ulduar/boss_algalon.cpp \ -scripts/northrend/ulduar/ulduar/boss_auriaya.cpp \ -scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp \ -scripts/northrend/ulduar/ulduar/boss_freya.cpp \ -scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp \ -scripts/northrend/ulduar/ulduar/boss_hodir.cpp \ -scripts/northrend/ulduar/ulduar/boss_ignis.cpp \ -scripts/northrend/ulduar/ulduar/boss_kologarn.cpp \ -scripts/northrend/ulduar/ulduar/boss_mimiron.cpp \ -scripts/northrend/ulduar/ulduar/boss_razorscale.cpp \ -scripts/northrend/ulduar/ulduar/boss_thorim.cpp \ -scripts/northrend/ulduar/ulduar/boss_xt_002.cpp \ -scripts/northrend/ulduar/ulduar/boss_yogg_saron.cpp \ -scripts/northrend/ulduar/ulduar/instance_ulduar.cpp \ -scripts/northrend/ulduar/ulduar/ulduar.cpp \ -scripts/northrend/ulduar/ulduar/ulduar.h \ -scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar.cpp \ -scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp \ -scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_and_dalronn.cpp \ -scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp \ -scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp \ -scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h \ -scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp \ -scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp \ -scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp \ -scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp \ -scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_utgarde_pinnacle.cpp \ -scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h \ -scripts/northrend/violet_hold/instance_violet_hold.cpp \ -scripts/northrend/violet_hold/violet_hold.cpp \ -scripts/northrend/violet_hold/violet_hold.h \ -scripts/outland/blades_edge_mountains.cpp \ -scripts/outland/boss_doomlord_kazzak.cpp \ -scripts/outland/boss_doomwalker.cpp \ -scripts/outland/hellfire_peninsula.cpp \ -scripts/outland/nagrand.cpp \ -scripts/outland/netherstorm.cpp \ -scripts/outland/shadowmoon_valley.cpp \ -scripts/outland/shattrath_city.cpp \ -scripts/outland/terokkar_forest.cpp \ -scripts/outland/zangarmarsh.cpp \ -scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp \ -scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp \ -scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp \ -scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp \ -scripts/outland/auchindoun/sethekk_halls/boss_tailonking_ikiss.cpp \ -scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp \ -scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h \ -scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp \ -scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp \ -scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp \ -scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp \ -scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp \ -scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h \ -scripts/outland/black_temple/black_temple.cpp \ -scripts/outland/black_temple/black_temple.h \ -scripts/outland/black_temple/boss_bloodboil.cpp \ -scripts/outland/black_temple/boss_illidan.cpp \ -scripts/outland/black_temple/boss_mother_shahraz.cpp \ -scripts/outland/black_temple/boss_reliquary_of_souls.cpp \ -scripts/outland/black_temple/boss_shade_of_akama.cpp \ -scripts/outland/black_temple/boss_supremus.cpp \ -scripts/outland/black_temple/boss_teron_gorefiend.cpp \ -scripts/outland/black_temple/boss_warlord_najentus.cpp \ -scripts/outland/black_temple/illidari_council.cpp \ -scripts/outland/black_temple/instance_black_temple.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/boss_fathomlord_karathress.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/boss_hydross_the_unstable.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/boss_lady_vashj.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/boss_leotheras_the_blind.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/boss_morogrim_tidewalker.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/boss_the_lurker_below.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/instance_serpent_shrine.cpp \ -scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h \ -scripts/outland/coilfang_reservoir/steam_vault/boss_hydromancer_thespia.cpp \ -scripts/outland/coilfang_reservoir/steam_vault/boss_mekgineer_steamrigger.cpp \ -scripts/outland/coilfang_reservoir/steam_vault/boss_warlord_kalithresh.cpp \ -scripts/outland/coilfang_reservoir/steam_vault/instance_steam_vault.cpp \ -scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h \ -scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp \ -scripts/outland/gruuls_lair/boss_gruul.cpp \ -scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp \ -scripts/outland/gruuls_lair/gruuls_lair.h \ -scripts/outland/gruuls_lair/instance_gruuls_lair.cpp \ -scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h \ -scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp \ -scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp \ -scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp \ -scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp \ -scripts/outland/hellfire_citadel/hellfire_ramparts/boss_nazan_and_vazruden.cpp \ -scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp \ -scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp \ -scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h \ -scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp \ -scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp \ -scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp \ -scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h \ -scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp \ -scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp \ -scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp \ -scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp \ -scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h \ -scripts/outland/tempest_keep/arcatraz/arcatraz.cpp \ -scripts/outland/tempest_keep/arcatraz/arcatraz.h \ -scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp \ -scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp \ -scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp \ -scripts/outland/tempest_keep/botanica/boss_laj.cpp \ -scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp \ -scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp \ -scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp \ -scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp \ -scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp \ -scripts/outland/tempest_keep/the_eye/the_eye.cpp \ -scripts/outland/tempest_keep/the_eye/the_eye.h \ -scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp \ -scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp \ -scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp \ -scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp \ -scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp \ -scripts/outland/tempest_keep/the_mechanar/mechanar.h \ -scripts/world/areatrigger_scripts.cpp \ -scripts/world/boss_emeriss.cpp \ -scripts/world/boss_lethon.cpp \ -scripts/world/boss_taerar.cpp \ -scripts/world/boss_ysondre.cpp \ -scripts/world/go_scripts.cpp \ -scripts/world/guards.cpp \ -scripts/world/item_scripts.cpp \ -scripts/world/mob_generic_creature.cpp \ -scripts/world/npc_professions.cpp \ -scripts/world/npcs_special.cpp \ -scripts/world/spell_scripts.cpp \ -system/ScriptLoader.cpp \ -system/ScriptLoader.h \ -system/system.cpp \ -system/system.h \ -revision.h - - -## magic to include revision data in SD2 version string -revision.h: FORCE - $(top_builddir)/src/tools/genrevision/genrevision $(srcdir) - -FORCE: - -## libtool settings -# API versioning -# Link against dependencies -# How to increase version info: -# - only bug fixes implemented: -# bump the version to LTMANGOS_CURRENT:LTMANGOS_REVISION+1:LTMANGOS_AGE -# - augmented the interface: -# bump the version to LTMANGOS_CURRENT+1:0:LTMANGOS_AGE+1 -# - broken old interface: -# bump the version to LTMANGOS_CURRENT+1:0:0 -LTMANGOS_CURRENT = 0 -LTMANGOS_REVISION = 0 -LTMANGOS_AGE = 0 -libmangosscript_la_LIBFLAGS = -version-info $(LTMANGOS_CURRENT):$(LTMANGOS_REVISION):$(LTMANGOS_AGE) - -## Additional files to include when running 'make dist' -# Scripts defaults. -EXTRA_DIST = \ - Scripts/sc_default.cpp \ - Scripts/sc_defines.cpp \ - Scripts/sc_defines.h \ - scriptdev2.conf.dist - -## Additional files to install -sysconf_DATA = \ - scriptdev2.conf.dist - -install-data-hook: - @list='$(sysconf_DATA)'; for p in $$list; do \ - dest=`echo $$p | sed -e s/.dist//`; \ - if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ - echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ - else \ - echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest"; \ - $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest; \ - fi; \ - done - -clean-local: - rm -f $(sysconf_DATA) diff --git a/README b/README new file mode 100644 index 0000000000..389391345c --- /dev/null +++ b/README @@ -0,0 +1,112 @@ +@package RSA scripts for ScriptDev2 +@version 0.4a +@revision (current) +@copyright (c) 2009-2013 /dev/rsa +@license GNU Public License + +This program is free software; you can redistribute it and/or modify +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 + +Attention please! My project now will only support cmake compile +No special VC configs provided. + +In this repository you will find these scripts and more: + +- many scripts from Insider42 +-- Alots and Alots of Quests Fixes +- Ulduar (from Xfurry, partially rewrite by rsa) +- Trial of the Champion (by Syntec, big rewrite by rsa) +- Violet hold (by Przemratajczak Repo, big rewrite by rsa) +- Ahn'kahet (renewed, by Tassadar with my corrects) +- Draktaron (by Tassadar) +- Culling of Stratholme (by MaxXx2021 && FallenAngelX) +- Obsidian Sanctum (by michalpolko) +- Azjol-Nerub (by MaxXx2021) +- Forge of souls (by Maxxx2021 and rsa) +- Halls of reflection (by Maxxx2021 and rsa) +- Vault of Archavon (by Insider42) +- Trial of the Crusader (by rsa) +- Icecrown Citadel (by rsa) +- Ruby Sanctum (by rsa, partially from notagain) +- npc_arena_honor (by tempura) +- NPC special (partially by rsa, thanks for all) +- Nexus (rewrite by Janu , instance rewite by fallenangelX) +- Oculus (originally from TC with MaxXx2021, rsa, FallenangelX and traponinet Rewrites) +- Eye of Eternity(originally from Tassadar with PSZ and rsa modifications) +- All DK Starting Area Quest (by fallenangelX,ancient,rsa,cklegg, traponinet and klimbo) +- Sunwell_Plateau (by FallenangelX , Xfurry and Official SD2) -- Currently in progress +- simple scripts from Xfurry + +Thanks to: +- Vladimir Mangos - MaNGOS project; +- Insider42 - for your work; +- MaxXx2021 aka Mioka - for your scripts; +- Tassadar; +- notagain - base placeholders and spell research for Ruby sanctum; +- griffonheart (original texts/sounds for TOC); +- Cristy (re-translation to english); +- Selector - Faction champions base script, testing, bugreports; +- Boxa - changes for Windows compilers and bugreports; +- Wowka321 - core support; +- Dron01, Lordronn, Vinolentus - bugreports and valuable advice; +- gladden, ghostart - bugreports; +- Schmoozerd - instances, script codes +- all - testing. + +Ladies and gentlemen, and friends! If you want to compile my scripts with a compiler different from the GNU C, then the config files, projects or whatever else you need to create your own! I do only cmake compile. +And please do not send me a compilation error. So what lies in my repository, absolute accuracy compiles fine and works on live servers. + +Уважаемые дамы и господа, а также товарищи! Если Вы хотите скомпилировать мои скрипты с помощью компилятора, отличного от GNU C, то конфиг-файлы, проекты или что там еще Вам придется создавать самостоятельно! Я делаю только cmake compile. +И пожалуйста, не присылайте мне ошибки компиляции. То что лежит в моем репозитории, абсолютно точно компилируется нормально и работает на живых серверах. + +== ScriptDev2 README == + + 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 + +== Welcome to ScriptDev2 == + +ScriptDev2 is a script library, an extention of the scripting capabilities +that comes with MaNGOS ( http://www.getmangos.com ), written in C++ and is +compatible with Windows and Linux. SQL needed for database support both +MySQL and PostgreSQL. + +This script library provides unique scripts for NPCs, gameobjects, events +and other that need unique implementation. + +Once ScriptDev2 is compiled it is automatically run by MaNGOS on server +startup. + +For further information on ScriptDev2, please visit our project web site +at http://www.scriptdev2.com/ + +Documentation on various development related topics can be found in the +../doc/ sub directory as well as on the web site. + +The required SQL files for creating the database backend are included in +the ../sql/ sub directory. If you are updating from an older ScriptDev2 +version, make sure to take a look at the SQL files provided in the +../sql/updates/ sub directory. diff --git a/ScriptMgr.cpp b/ScriptMgr.cpp index 5a01c7c232..79475fec1f 100644 --- a/ScriptMgr.cpp +++ b/ScriptMgr.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2012 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -11,29 +11,50 @@ #include "ProgressBar.h" #include "../system/ScriptLoader.h" #include "../system/system.h" +#include "../../../game/ScriptMgr.h" +#include "World.h" + +typedef std::vector SDScriptVec; +typedef std::map SDScriptMap; int num_sc_scripts; -Script *m_scripts[MAX_SCRIPTS]; +SDScriptVec *m_scripts = NULL; +SDScriptMap *m_scriptStorage = NULL; // Not registered scripts storage Config SD2Config; +/********************************************************************** ++additions for windows compiler +**********************************************************************/ +#ifdef _WIN32 +World::World(){} +World::~World(){} +#endif +/***********************************************************************/ + +QueryResult* strSD2Pquery(char* str) +{ + return SD2Database.Query(str); +} + void FillSpellSummary(); void LoadDatabase() { + std::string strSD2DBinfo = SD2Config.GetStringDefault("ScriptDev2DatabaseInfo", ""); 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; } - //Initialize connection to DB + // Initialize connection to DB if (SD2Database.Initialize(strSD2DBinfo.c_str())) { - outstring_log("SD2: ScriptDev2 database at %s initialized.", strSD2DBinfo.c_str()); - outstring_log(""); + outstring_log("SD2: ScriptDev2 database initialized."); + //outstring_log(""); pSystemMgr.LoadVersion(); pSystemMgr.LoadScriptTexts(); @@ -43,37 +64,47 @@ 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 ScriptsFree() +void FreeScriptLibrary() { // Free Spell Summary - delete []SpellSummary; + delete[] SpellSummary; // Free resources before library unload - for(int i=0; ibegin(); itr != m_scripts->end(); ++itr) + delete *itr; + + delete m_scripts; + + for (SDScriptMap::const_iterator itr = m_scriptStorage->begin(); itr != m_scriptStorage->end(); ++itr) + delete itr->second; + + delete m_scriptStorage; num_sc_scripts = 0; + + SD2Database.HaltDelayThread(); + + setScriptLibraryErrorFile(NULL, NULL); } MANGOS_DLL_EXPORT -void ScriptsInit() +void InitScriptLibrary() { - //ScriptDev2 startup - outstring_log(""); + // ScriptDev2 startup + // outstring_log(""); outstring_log(" MMM MMM MM"); outstring_log("M MM M M M M"); outstring_log("MM M M M"); @@ -81,122 +112,139 @@ void ScriptsInit() outstring_log(" MM M M MMMM"); outstring_log("MM M M M "); outstring_log(" MMM MMM http://www.scriptdev2.com"); - outstring_log(""); + outstring_log("R2 modifications included (https://github.com/mangosR2/scriptdev2)"); + outstring_log(SD2_VERSION); - //Get configuration file + // 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); - //Check config file version + // 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(""); + // outstring_log(""); - //Load database (must be called after SD2Config.SetSource). + // Load database (must be called after SD2Config.SetSource). LoadDatabase(); outstring_log("SD2: Loading C++ scripts"); - barGoLink bar(1); + BarGoLink bar(1); bar.step(); - outstring_log(""); + // outstring_log(""); - for(int i=0; iat(i)) + script_error_log("No script found for ScriptName '%s'.", GetScriptName(i)); + } + outstring_log(">> Loaded %i C++ Scripts.", num_sc_scripts); } //********************************* //*** Functions used globally *** -void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) +/** + * Function that does script text + * + * @param iTextEntry Entry of the text, stored in SD2-database + * @param pSource Source of the text + * @param pTarget Can be NULL (depending on CHAT_TYPE of iTextEntry). Possible target for the text + */ +void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget/*=NULL*/) { 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 %s attempts to process text entry %i, but text entry must be negative.", + pSource->GetGuidStr().c_str(), iTextEntry); return; } - const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); + DoDisplayText(pSource, iTextEntry, pTarget); + // TODO - maybe add some call-stack like error output if above function returns false +} - if (!pData) +/** + * Function that either simulates or does script text for a map + * + * @param iTextEntry Entry of the text, stored in SD2-database, only type CHAT_TYPE_ZONE_YELL supported + * @param uiCreatureEntry Id of the creature of whom saying will be simulated + * @param pMap Given Map on which the map-wide text is displayed + * @param pCreatureSource Can be NULL. If pointer to Creature is given, then the creature does the map-wide text + * @param pTarget Can be NULL. Possible target for the text + */ +void DoOrSimulateScriptTextForMap(int32 iTextEntry, uint32 uiCreatureEntry, Map* pMap, Creature* pCreatureSource /*=NULL*/, Unit* pTarget /*=NULL*/) +{ + if (!pMap) { - 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); - + script_error_log("DoOrSimulateScriptTextForMap entry %i, invalid Map pointer.", 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 (iTextEntry >= 0) + { + 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; + } - if (pData->uiSoundId) + CreatureInfo const* pInfo = GetCreatureTemplateStore(uiCreatureEntry); + if (!pInfo) { - if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) - pSource->PlayDirectSound(pData->uiSoundId); - else - error_log("SD2: DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); + script_error_log("DoOrSimulateScriptTextForMap has invalid source entry %u for map %u.", uiCreatureEntry, pMap->GetId()); + return; } - if (pData->uiEmote) + MangosStringLocale const* pData = GetMangosStringData(iTextEntry); + if (!pData) { - 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()); + script_error_log("DoOrSimulateScriptTextForMap with source entry %u for map %u could not find text entry %i.", uiCreatureEntry, pMap->GetId(), iTextEntry); + return; } - switch(pData->uiType) + debug_log("SD2: DoOrSimulateScriptTextForMap: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", + iTextEntry, pData->SoundId, pData->Type, pData->LanguageId, pData->Emote); + + if (pData->Type != CHAT_TYPE_ZONE_YELL) { - case CHAT_TYPE_SAY: - pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); - break; - case CHAT_TYPE_YELL: - pSource->MonsterYell(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); - break; - case CHAT_TYPE_TEXT_EMOTE: - pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0); - break; - case CHAT_TYPE_BOSS_EMOTE: - pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0, true); - break; - case CHAT_TYPE_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); - 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->GetGUID(), 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 ? pTarget->GetGUID() : 0); - break; + script_error_log("DoSimulateScriptTextForMap entry %i has not supported chat type %u.", iTextEntry, pData->Type); + return; } + + if (pData->SoundId) + pMap->PlayDirectSoundToMap(pData->SoundId); + + if (pCreatureSource) // If provided pointer for sayer, use direct version + pMap->MonsterYellToMap(pCreatureSource->GetObjectGuid(), iTextEntry, pData->LanguageId, pTarget); + else // Simulate yell + pMap->MonsterYellToMap(pInfo, iTextEntry, pData->LanguageId, pTarget); } //********************************* @@ -204,60 +252,86 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) void Script::RegisterSelf(bool bReportError) { - int id = GetScriptId(Name.c_str()); - if (id != 0) + if (uint32 id = GetScriptId(Name)) { - m_scripts[id] = this; + m_scripts->at(id) = this; ++num_sc_scripts; } else { if (bReportError) - error_log("SD2: Script registering but ScriptName %s is not assigned in database. Script will not be used.", (this)->Name.c_str()); + script_error_log("Script registering but ScriptName %s is not assigned in database. Script will not be used.", Name); - delete this; + m_scriptStorage->insert(std::make_pair(Name, this)); } } +//********************************* +//******** AutoScript ************* + +Script* AutoScript::newScript(char const* scriptName, bool reportError /*=true*/) +{ + Register(); // register last added script (if any) + + m_script = new Script(scriptName); + m_reportError = reportError; + return m_script; +} + +Script* AutoScript::newScript(char const* scriptName, TGetAI getAIPtr, bool reportError /*= true*/) +{ + newScript(scriptName, reportError); + m_script->GetAI = getAIPtr; + return m_script; +} + +void AutoScript::Register() +{ + if (!m_script) + return; + m_script->RegisterSelf(m_reportError); + m_script = NULL; +} + //******************************** //*** Functions to be Exported *** MANGOS_DLL_EXPORT -char const* ScriptsVersion() +char const* GetScriptLibraryVersion() { - if (!strSD2Version.empty()) - { - strSD2Version.append(_FULLVERSION); - return strSD2Version.c_str(); - } - - return _FULLVERSION; + return strSD2Version.c_str(); } MANGOS_DLL_EXPORT bool GossipHello(Player* pPlayer, Creature* pCreature) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!pCreature) + return false; - if (!tmpscript || !tmpscript->pGossipHello) + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); + + if (!pTempScript || !pTempScript->pGossipHello) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipHello(pPlayer, pCreature); + return pTempScript->pGossipHello(pPlayer, pCreature); } MANGOS_DLL_EXPORT -bool GOGossipHello(Player *pPlayer, GameObject *pGo) +bool GOGossipHello(Player* pPlayer, GameObject* pGo) { - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + if (!pGo) + return false; - if (!tmpscript || !tmpscript->pGOGossipHello) + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); + + if (!pTempScript || !pTempScript->pGossipHelloGO) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOGossipHello(pPlayer, pGo); + return pTempScript->pGossipHelloGO(pPlayer, pGo); } MANGOS_DLL_EXPORT @@ -265,29 +339,37 @@ bool GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 { debug_log("SD2: Gossip selection, sender: %u, action: %u", uiSender, uiAction); - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!pCreature) + return false; + + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); - if (!tmpscript || !tmpscript->pGossipSelect) + if (!pTempScript || !pTempScript->pGossipSelect) return false; - pPlayer->PlayerTalkClass->ClearMenus(); +// pPlayer->PlayerTalkClass->ClearMenus(); +// this expression is wrong, where 'return false' from script's GossipSelect +// not return menu ID (cleared in this string) and not allow to work with database-based menus - return tmpscript->pGossipSelect(pPlayer, pCreature, uiSender, uiAction); + return pTempScript->pGossipSelect(pPlayer, pCreature, uiSender, uiAction); } MANGOS_DLL_EXPORT -bool GOGossipSelect(Player *pPlayer, GameObject *pGo, uint32 sender, uint32 action) +bool GOGossipSelect(Player* pPlayer, GameObject* pGo, uint32 uiSender, uint32 uiAction) { - debug_log("SD2: GO Gossip selection, sender: %u, action: %u", sender, action); + debug_log("SD2: GO Gossip selection, sender: %u, action: %u", uiSender, uiAction); + + if (!pGo) + return false; - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); - if (!tmpscript || !tmpscript->pGOGossipSelect) + if (!pTempScript || !pTempScript->pGossipSelectGO) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOGossipSelect(pPlayer, pGo, sender, action); + return pTempScript->pGossipSelectGO(pPlayer, pGo, uiSender, uiAction); } MANGOS_DLL_EXPORT @@ -295,269 +377,302 @@ bool GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, { debug_log("SD2: Gossip selection with code, sender: %u, action: %u", uiSender, uiAction); - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!pCreature) + return false; + + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); - if (!tmpscript || !tmpscript->pGossipSelectWithCode) + if (!pTempScript || !pTempScript->pGossipSelectWithCode) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelectWithCode(pPlayer, pCreature, uiSender, uiAction, sCode); + return pTempScript->pGossipSelectWithCode(pPlayer, pCreature, uiSender, uiAction, sCode); } MANGOS_DLL_EXPORT -bool GOGossipSelectWithCode(Player *pPlayer, GameObject *pGo, uint32 sender, uint32 action, const char* sCode) +bool GOGossipSelectWithCode(Player* pPlayer, GameObject* pGo, uint32 uiSender, uint32 uiAction, const char* sCode) { - debug_log("SD2: GO Gossip selection with code, sender: %u, action: %u", sender, action); + debug_log("SD2: GO Gossip selection with code, sender: %u, action: %u", uiSender, uiAction); + + if (!pGo) + return false; - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); - if (!tmpscript || !tmpscript->pGOGossipSelectWithCode) + if (!pTempScript || !pTempScript->pGossipSelectGOWithCode) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOGossipSelectWithCode(pPlayer, pGo, sender, action, sCode); + return pTempScript->pGossipSelectGOWithCode(pPlayer, pGo, uiSender, uiAction, sCode); } MANGOS_DLL_EXPORT bool QuestAccept(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!pCreature) + return false; - if (!tmpscript || !tmpscript->pQuestAccept) + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); + + if (!pTempScript || !pTempScript->pQuestAcceptNPC) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestAccept(pPlayer, pCreature, pQuest); + return pTempScript->pQuestAcceptNPC(pPlayer, pCreature, pQuest); } MANGOS_DLL_EXPORT -bool QuestSelect(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool QuestRewarded(Player* pPlayer, Creature* pCreature, Quest const* pQuest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!pCreature) + return false; - if (!tmpscript || !tmpscript->pQuestSelect) + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); + + if (!pTempScript || !pTempScript->pQuestRewardedNPC) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestSelect(pPlayer, pCreature, pQuest); + return pTempScript->pQuestRewardedNPC(pPlayer, pCreature, pQuest); } MANGOS_DLL_EXPORT -bool QuestComplete(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +uint32 GetNPCDialogStatus(Player* pPlayer, Creature* pCreature) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); - if (!tmpscript || !tmpscript->pQuestComplete) - return false; + if (!pTempScript || !pTempScript->pDialogStatusNPC) + return DIALOG_STATUS_UNDEFINED; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestComplete(pPlayer, pCreature, pQuest); + return pTempScript->pDialogStatusNPC(pPlayer, pCreature); } MANGOS_DLL_EXPORT -bool ChooseReward(Player* pPlayer, Creature* pCreature, const Quest* pQuest, uint32 opt) +uint32 GetGODialogStatus(Player* pPlayer, GameObject* pGo) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - - if (!tmpscript || !tmpscript->pChooseReward) + if (!pGo) return false; + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); + + if (!pTempScript || !pTempScript->pDialogStatusGO) + return DIALOG_STATUS_UNDEFINED; + pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pChooseReward(pPlayer, pCreature, pQuest, opt); + return pTempScript->pDialogStatusGO(pPlayer, pGo); } MANGOS_DLL_EXPORT -uint32 NPCDialogStatus(Player* pPlayer, Creature* pCreature) +bool ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!pItem) + return false; + + Script* pTempScript = m_scripts->at(pItem->GetProto()->ScriptId); - if (!tmpscript || !tmpscript->pNPCDialogStatus) - return 100; + if (!pTempScript || !pTempScript->pQuestAcceptItem) + return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pNPCDialogStatus(pPlayer, pCreature); + return pTempScript->pQuestAcceptItem(pPlayer, pItem, pQuest); } MANGOS_DLL_EXPORT -uint32 GODialogStatus(Player* pPlayer, GameObject* pGo) +bool GOUse(Player* pPlayer, GameObject* pGo) { - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + if (!pGo) + return false; - if (!tmpscript || !tmpscript->pGODialogStatus) - return 100; + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); - pPlayer->PlayerTalkClass->ClearMenus(); + if (!pTempScript || !pTempScript->pGOUse) + return false; - return tmpscript->pGODialogStatus(pPlayer, pGo); + return pTempScript->pGOUse(pPlayer, pGo); } MANGOS_DLL_EXPORT -bool ItemHello(Player* pPlayer, Item *_Item, const Quest* pQuest) +bool GOQuestAccept(Player* pPlayer, GameObject* pGo, const Quest* pQuest) { - Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId]; + if (!pGo) + return false; + + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); - if (!tmpscript || !tmpscript->pItemHello) + if (!pTempScript || !pTempScript->pQuestAcceptGO) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemHello(pPlayer,_Item, pQuest); + return pTempScript->pQuestAcceptGO(pPlayer, pGo, pQuest); } MANGOS_DLL_EXPORT -bool ItemQuestAccept(Player* pPlayer, Item *_Item, const Quest* pQuest) +bool GOQuestRewarded(Player* pPlayer, GameObject* pGo, Quest const* pQuest) { - Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId]; + if (!pGo) + return false; + + Script* pTempScript = m_scripts->at(pGo->GetGOInfo()->ScriptId); - if (!tmpscript || !tmpscript->pItemQuestAccept) + if (!pTempScript || !pTempScript->pQuestRewardedGO) return false; pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemQuestAccept(pPlayer,_Item, pQuest); + return pTempScript->pQuestRewardedGO(pPlayer, pGo, pQuest); } MANGOS_DLL_EXPORT -bool GOHello(Player* pPlayer, GameObject* pGo) +bool AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) { - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + Script* pTempScript = m_scripts->at(GetAreaTriggerScriptId(atEntry->id)); - if (!tmpscript || !tmpscript->pGOHello) + if (!pTempScript || !pTempScript->pAreaTrigger) return false; - return tmpscript->pGOHello(pPlayer, pGo); + return pTempScript->pAreaTrigger(pPlayer, atEntry); } MANGOS_DLL_EXPORT -bool GOQuestAccept(Player* pPlayer, GameObject* pGo, const Quest* pQuest) +bool NpcSpellClick(Player* pPlayer, Creature* pClickedCreature, uint32 uiSpellId) { - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + Script* pTempScript = m_scripts->at(pClickedCreature->GetScriptId()); - if (!tmpscript || !tmpscript->pGOQuestAccept) + if (!pTempScript || !pTempScript->pNpcSpellClick) return false; - pPlayer->PlayerTalkClass->ClearMenus(); - - return tmpscript->pGOQuestAccept(pPlayer, pGo, pQuest); + return pTempScript->pNpcSpellClick(pPlayer, pClickedCreature, uiSpellId); } MANGOS_DLL_EXPORT -bool GOChooseReward(Player* pPlayer, GameObject* pGo, const Quest* pQuest, uint32 opt) +bool ProcessEvent(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) { - Script *tmpscript = m_scripts[pGo->GetGOInfo()->ScriptId]; + Script* pTempScript = m_scripts->at(GetEventIdScriptId(uiEventId)); - if (!tmpscript || !tmpscript->pGOChooseReward) + if (!pTempScript || !pTempScript->pProcessEventId) return false; - pPlayer->PlayerTalkClass->ClearMenus(); - - return tmpscript->pGOChooseReward(pPlayer, pGo, pQuest,opt); + // bIsStart may be false, when event is from taxi node events (arrival=false, departure=true) + return pTempScript->pProcessEventId(uiEventId, pSource, pTarget, bIsStart); } MANGOS_DLL_EXPORT -bool AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) +CreatureAI* GetCreatureAI(Creature* pCreature) { - Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)]; + if (!pCreature) + return NULL; - if (!tmpscript || !tmpscript->pAreaTrigger) - return false; + Script* pTempScript = m_scripts->at(pCreature->GetScriptId()); - return tmpscript->pAreaTrigger(pPlayer, atEntry); + if (!pTempScript || !pTempScript->GetAI) + return NULL; + + return pTempScript->GetAI(pCreature); } MANGOS_DLL_EXPORT -bool ProcessEventId(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) { - Script *tmpscript = m_scripts[GetEventIdScriptId(uiEventId)]; - if (!tmpscript || !tmpscript->pProcessEventId) + if (!pItem) return false; - // bIsStart may be false, when event is from taxi node events (arrival=false, departure=true) - return tmpscript->pProcessEventId(uiEventId, pSource, pTarget, bIsStart); -} - -MANGOS_DLL_EXPORT -CreatureAI* GetAI(Creature* pCreature) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + Script* pTempScript = m_scripts->at(pItem->GetProto()->ScriptId); - if (!tmpscript || !tmpscript->GetAI) - return NULL; + if (!pTempScript || !pTempScript->pItemUse) + return false; - return tmpscript->GetAI(pCreature); + return pTempScript->pItemUse(pPlayer, pItem, targets); } MANGOS_DLL_EXPORT -bool ItemUse(Player* pPlayer, Item* _Item, SpellCastTargets const& targets) +bool EffectDummyCreature(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid) { - Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId]; + if (!pTarget) + return false; + + Script* pTempScript = m_scripts->at(pTarget->GetScriptId()); - if (!tmpscript || !tmpscript->pItemUse) + if (!pTempScript || !pTempScript->pEffectDummyNPC) return false; - return tmpscript->pItemUse(pPlayer,_Item,targets); + return pTempScript->pEffectDummyNPC(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT -bool EffectDummyCreature(Unit *pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature *pCreatureTarget) +bool EffectDummyGameObject(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget, ObjectGuid originalCasterGuid) { - Script *tmpscript = m_scripts[pCreatureTarget->GetScriptId()]; + if (!pTarget) + return false; + + Script* pTempScript = m_scripts->at(pTarget->GetGOInfo()->ScriptId); - if (!tmpscript || !tmpscript->pEffectDummyCreature) + if (!pTempScript || !pTempScript->pEffectDummyGO) return false; - return tmpscript->pEffectDummyCreature(pCaster, spellId, effIndex, pCreatureTarget); + return pTempScript->pEffectDummyGO(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT -bool EffectDummyGameObj(Unit *pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject *pGameObjTarget) +bool EffectDummyItem(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget, ObjectGuid originalCasterGuid) { - Script *tmpscript = m_scripts[pGameObjTarget->GetGOInfo()->ScriptId]; + if (!pTarget) + return false; - if (!tmpscript || !tmpscript->pEffectDummyGameObj) + Script* pTempScript = m_scripts->at(pTarget->GetProto()->ScriptId); + + if (!pTempScript || !pTempScript->pEffectDummyItem) return false; - return tmpscript->pEffectDummyGameObj(pCaster, spellId, effIndex, pGameObjTarget); + return pTempScript->pEffectDummyItem(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT -bool EffectDummyItem(Unit *pCaster, uint32 spellId, SpellEffectIndex effIndex, Item *pItemTarget) +bool EffectScriptEffectCreature(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid) { - Script *tmpscript = m_scripts[pItemTarget->GetProto()->ScriptId]; + Script* pTempScript = m_scripts->at(pTarget->GetScriptId()); - if (!tmpscript || !tmpscript->pEffectDummyItem) + if (!pTempScript || !pTempScript->pEffectScriptEffectNPC) return false; - return tmpscript->pEffectDummyItem(pCaster, spellId, effIndex, pItemTarget); + return pTempScript->pEffectScriptEffectNPC(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT -bool EffectAuraDummy(const Aura* pAura, bool apply) +bool AuraDummy(Aura const* pAura, bool bApply) { - Script *tmpscript = m_scripts[((Creature*)pAura->GetTarget())->GetScriptId()]; + Script* pTempScript = m_scripts->at(((Creature*)pAura->GetTarget())->GetScriptId()); - if (!tmpscript || !tmpscript->pEffectAuraDummy) + if (!pTempScript || !pTempScript->pEffectAuraDummy) return false; - return tmpscript->pEffectAuraDummy(pAura, apply); + return pTempScript->pEffectAuraDummy(pAura, bApply); } MANGOS_DLL_EXPORT -InstanceData* CreateInstanceData(Map *map) +InstanceData* CreateInstanceData(Map* pMap) { - if (!map->IsDungeon()) - return NULL; + Script* pTempScript = m_scripts->at(pMap->GetScriptId()); - Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()]; - if (!tmpscript || !tmpscript->GetInstanceData) + if (!pTempScript || !pTempScript->GetInstanceData) return NULL; - return tmpscript->GetInstanceData(map); + return pTempScript->GetInstanceData(pMap); +} + +Script* GetScriptByName(std::string scriptName) +{ + SDScriptMap::const_iterator itr = m_scriptStorage->find(scriptName); + if (itr != m_scriptStorage->end()) + return itr->second; + else + return NULL; } diff --git a/ScriptMgr.h b/ScriptMgr.h index c2b4ab7261..29ae23659f 100644 --- a/ScriptMgr.h +++ b/ScriptMgr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2012 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,6 +7,7 @@ #include "Common.h" #include "DBCStructure.h" +#include "Database/DatabaseEnv.h" class Player; class Creature; @@ -21,59 +22,136 @@ class Unit; class WorldObject; class Aura; class Object; +class ObjectGuid; -#define MAX_SCRIPTS 5000 //72 bytes each (approx 351kb) -#define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid) +// ********************************************************* +// ************** Some defines used globally *************** + +// Basic defines +#define VISIBLE_RANGE (166.0f) // MAX visible range (size of grid) #define DEFAULT_TEXT "" +/* Escort Factions + * TODO: find better namings and definitions. + * N=Neutral, A=Alliance, H=Horde. + * NEUTRAL or FRIEND = Hostility to player surroundings (not a good definition) + * ACTIVE or PASSIVE = Hostility to environment surroundings. + */ +enum EscortFaction +{ + FACTION_ESCORT_A_NEUTRAL_PASSIVE = 10, + FACTION_ESCORT_H_NEUTRAL_PASSIVE = 33, + FACTION_ESCORT_N_NEUTRAL_PASSIVE = 113, + + FACTION_ESCORT_A_NEUTRAL_ACTIVE = 231, + FACTION_ESCORT_H_NEUTRAL_ACTIVE = 232, + FACTION_ESCORT_N_NEUTRAL_ACTIVE = 250, + + FACTION_ESCORT_N_FRIEND_PASSIVE = 290, + FACTION_ESCORT_N_FRIEND_ACTIVE = 495, + + FACTION_ESCORT_A_PASSIVE = 774, + FACTION_ESCORT_H_PASSIVE = 775, + + FACTION_ESCORT_N_ACTIVE = 1986, + FACTION_ESCORT_H_ACTIVE = 2046 +}; + +// ********************************************************* +// ************* Some structures used globally ************* + struct Script { - Script() : - pGossipHello(NULL), pGOGossipHello(NULL), pGossipSelect(NULL), pGOGossipSelect(NULL), - pGossipSelectWithCode(NULL), pGOGossipSelectWithCode(NULL), - pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), - pChooseReward(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pProcessEventId(NULL), pItemQuestAccept(NULL), - pQuestAccept(NULL), pGOQuestAccept(NULL), pGOChooseReward(NULL), pItemUse(NULL), - pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), pEffectAuraDummy(NULL), - GetAI(NULL), GetInstanceData(NULL) + Script(char const* scriptName = NULL) : Name(scriptName), + pGossipHello(NULL), pGossipHelloGO(NULL), pGossipSelect(NULL), pGossipSelectGO(NULL), + pGossipSelectWithCode(NULL), pGossipSelectGOWithCode(NULL), + pDialogStatusNPC(NULL), pDialogStatusGO(NULL), + pQuestAcceptNPC(NULL), pQuestAcceptGO(NULL), pQuestAcceptItem(NULL), + pQuestRewardedNPC(NULL), pQuestRewardedGO(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; + char const* Name; - //Methods to be scripted bool (*pGossipHello )(Player*, Creature*); - bool (*pGOGossipHello )(Player*, GameObject*); - bool (*pQuestAccept )(Player*, Creature*, const Quest*); + bool (*pGossipHelloGO )(Player*, GameObject*); bool (*pGossipSelect )(Player*, Creature*, uint32, uint32); - bool (*pGOGossipSelect )(Player*, GameObject*, uint32, uint32); + bool (*pGossipSelectGO )(Player*, GameObject*, uint32, uint32); bool (*pGossipSelectWithCode )(Player*, Creature*, uint32, uint32, const char*); - bool (*pGOGossipSelectWithCode )(Player*, GameObject*, uint32, uint32, const char*); - bool (*pQuestSelect )(Player*, Creature*, const Quest*); - bool (*pQuestComplete )(Player*, Creature*, const Quest*); - uint32 (*pNPCDialogStatus )(Player*, Creature*); - uint32 (*pGODialogStatus )(Player*, GameObject*); - bool (*pChooseReward )(Player*, Creature*, const Quest*, uint32); - bool (*pItemHello )(Player*, Item*, const Quest*); - bool (*pGOHello )(Player*, GameObject*); + 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 (*pItemQuestAccept )(Player*, Item*, const Quest*); - bool (*pGOQuestAccept )(Player*, GameObject*, const Quest*); - bool (*pGOChooseReward )(Player*, GameObject*, const Quest*, uint32); - bool (*pItemUse )(Player*, Item*, SpellCastTargets const&); - bool (*pEffectDummyCreature )(Unit*, uint32, SpellEffectIndex, Creature*); - bool (*pEffectDummyGameObj )(Unit*, uint32, SpellEffectIndex, GameObject*); - bool (*pEffectDummyItem )(Unit*, uint32, SpellEffectIndex, Item*); + 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*); + CreatureAI* (*GetAI )(Creature*); + InstanceData* (*GetInstanceData )(Map*); void RegisterSelf(bool bReportError = true); }; -//Generic scripting text function +// ********************************************************* +// ******************* AutoScript ************************** + +typedef CreatureAI* (*TGetAI)(Creature*); +typedef InstanceData* (*TGetInstanceData)(Map*); + +class AutoScript +{ + private: + Script* m_script; + bool m_reportError; + + void Register(); + + public: + AutoScript() : m_script(NULL), m_reportError(true) {} + AutoScript(char const* scriptName, bool reportError = true) : m_script(NULL) { newScript(scriptName, reportError); } + AutoScript(char const* scriptName, TGetAI getAIPtr, bool reportError = true) : m_script(NULL) { newScript(scriptName, reportError); m_script->GetAI = getAIPtr; } + AutoScript(char const* scriptName, TGetInstanceData getIDPtr, bool reportError = true) : m_script(NULL) { newScript(scriptName, reportError); m_script->GetInstanceData = getIDPtr; } + + ~AutoScript() { Register(); } + + Script* newScript(char const* scriptName, bool reportError = true); + Script* newScript(char const* scriptName, TGetAI getAIPtr, bool reportError = true); + + Script* operator -> () + { + MANGOS_ASSERT(m_script != NULL && "AutoScript: use newScript() before!"); + return m_script; + } +}; + +// ********************************************************* +// ************* Some functions used globally ************** + +// Generic scripting text function void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget = NULL); +void DoOrSimulateScriptTextForMap(int32 iTextEntry, uint32 uiCreatureEntry, Map* pMap, Creature* pCreatureSource = NULL, Unit* pTarget = NULL); + +//DB query +QueryResult* strSD2Pquery(char*); + +// Not registered scripts storage +Script* GetScriptByName(std::string scriptName); + +// ********************************************************* +// **************** Internal hook mechanics **************** #if COMPILER == COMPILER_GNU #define FUNC_PTR(name,callconvention,returntype,parameters) typedef returntype(*name)parameters __attribute__ ((callconvention)); diff --git a/VC100/100ScriptDev2.vcxproj b/VC100/100ScriptDev2.vcxproj deleted file mode 100644 index 1f5932b8dc..0000000000 --- a/VC100/100ScriptDev2.vcxproj +++ /dev/null @@ -1,785 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - ScriptDev2 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96} - ScriptDev2 - Win32Proj - - - - DynamicLibrary - MultiByte - - - DynamicLibrary - MultiByte - - - DynamicLibrary - MultiByte - - - DynamicLibrary - MultiByte - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - ..\..\..\..\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 - - - mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) - ..\..\..\..\win\VC100\mangosd__Win32_Debug;..\..\..\..\win\VC100\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 - - - mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) - ..\..\..\..\win\VC100\mangosd__x64_Debug;..\..\..\..\win\VC100\framework__x64_Debug;..\..\..\..\dep\lib\x64_Debug\;%(AdditionalLibraryDirectories) - true - Windows - false - - - $(OutDir)mangosscript.lib - MachineX64 - - - - - /MP %(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 - - - mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) - ..\..\..\..\win\VC100\mangosd__Win32_Release;..\..\..\..\win\VC100\framework__Win32_Release;..\..\..\..\dep\lib\win32_release\;%(AdditionalLibraryDirectories) - true - Windows - true - true - false - - - $(OutDir)mangosscript.lib - - - - - X64 - - - /MP %(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 - - - mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) - ..\..\..\..\win\VC100\mangosd__x64_Release;..\..\..\..\win\VC100\framework__x64_Release;..\..\..\..\dep\lib\x64_release\;%(AdditionalLibraryDirectories) - true - Windows - true - true - false - - - $(OutDir)mangosscript.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Extracting revision - cd "$(SolutionDir)" -"$(SolutionDir)..\..\..\win\VC100\genrevision__Win32_$(Configuration)\genrevision.exe" - - .svn/entries;%(AdditionalInputs) - revision.h;%(Outputs) - Extracting revision - cd "$(SolutionDir)" -"$(SolutionDir)..\..\..\win\VC100\genrevision__Win32_$(Configuration)\genrevision.exe" - - .svn/entries;%(AdditionalInputs) - revision.h;%(Outputs) - Extracting revision - cd "$(SolutionDir)" -"$(SolutionDir)..\..\..\win\VC100\genrevision__Win32_$(Configuration)\genrevision.exe" - - .svn/entries;%(AdditionalInputs) - revision.h;%(Outputs) - Extracting revision - cd "$(SolutionDir)" -"$(SolutionDir)..\..\..\win\VC100\genrevision__Win32_$(Configuration)\genrevision.exe" - - .svn/entries;%(AdditionalInputs) - revision.h;%(Outputs) - - - - - - - \ No newline at end of file diff --git a/VC100/100ScriptDev2.vcxproj.filters b/VC100/100ScriptDev2.vcxproj.filters deleted file mode 100644 index 76c2b8fe41..0000000000 --- a/VC100/100ScriptDev2.vcxproj.filters +++ /dev/null @@ -1,1908 +0,0 @@ - - - - - {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 - - - 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 - - - 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_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 - - - 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\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\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_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\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 - - - scripts\eastern_kingdoms\scholomance - - - scripts\eastern_kingdoms\scholomance - - - scripts\eastern_kingdoms\scholomance - - - scripts\eastern_kingdoms\scholomance - - - 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\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 - - - 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\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\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\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\caverns_of_time\old_hillsbrad - - - scripts\kalimdor\caverns_of_time\old_hillsbrad - - - scripts\kalimdor\caverns_of_time\old_hillsbrad - - - scripts\kalimdor\maraudon - - - scripts\kalimdor\maraudon - - - scripts\kalimdor\maraudon - - - 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\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\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\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_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\nexus - - - scripts\northrend\nexus\nexus - - - scripts\northrend\nexus\nexus - - - scripts\northrend\nexus\nexus - - - scripts\northrend\nexus\nexus - - - 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\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\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\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\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\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\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\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\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 - - - scripts\world - - - scripts\world - - - include - - - include - - - include - - - include - - - system - - - system - - - - scripts\northrend\ruby_sanctum - - - scripts\northrend\ruby_sanctum - - - scripts\northrend\ruby_sanctum - - - scripts\northrend\ruby_sanctum - - - - - base - - - base - - - base - - - scripts\eastern_kingdoms\blackrock_depths - - - scripts\eastern_kingdoms\blackrock_depths - - - 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_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\onyxias_lair - - - 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\pit_of_saron - - - scripts\northrend\naxxramas - - - scripts\northrend\nexus\nexus - - - scripts\northrend\obsidian_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\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 - - - 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 d539d0d95e..0000000000 --- a/VC80/80ScriptDev2.vcproj +++ /dev/null @@ -1,2976 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/VC90/90ScriptDev2.vcproj b/VC90/90ScriptDev2.vcproj deleted file mode 100644 index 80d14c485c..0000000000 --- a/VC90/90ScriptDev2.vcproj +++ /dev/null @@ -1,2975 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/base/BSW_ai.cpp b/base/BSW_ai.cpp new file mode 100644 index 0000000000..1000e941c1 --- /dev/null +++ b/base/BSW_ai.cpp @@ -0,0 +1,867 @@ +/* Copyright (C) 2009 - 2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ +#include "precompiled.h" +#include "BSW_ai.h" +#ifdef DEF_BOSS_SPELL_WORKER_H +#include "ace/Process_Mutex.h" + +BSWScriptedAI::BSWScriptedAI(Creature* pCreature) : ScriptedAI(pCreature) +{ + doReset(); + debug_log("BSW: Initialized BSWScriptedAI structure for creature %u difficulty %u",m_creature->GetEntry(),currentDifficulty); +}; + +BSWScriptedAI::~BSWScriptedAI() +{ + m_BSWRecords.clear(); + debug_log("BSW: Removing BSWScriptedAI structure for creature %u",m_creature->GetEntry()); +}; + +void BSWScriptedAI::doReset() +{ + Map* pMap = m_creature->GetMap(); + if (pMap) currentDifficulty = pMap->GetDifficulty(); + else currentDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; + m_BSWRecords.clear(); + setStage(0); + _loadFromDB(); + _fillEmptyDataField(); + resetTimers(); +}; + +void BSWScriptedAI::_resetTimer(uint8 m_uiSpellIdx) +{ + if (m_BSWRecords[m_uiSpellIdx].m_uiSpellTimerMin[currentDifficulty] == 0 + && m_BSWRecords[m_uiSpellIdx].m_uiSpellTimerMax[currentDifficulty] >= HOUR*IN_MILLISECONDS) + { + m_BSWRecords[m_uiSpellIdx].m_SpellTimer = 0; + } + else if (m_BSWRecords[m_uiSpellIdx].m_uiSpellTimerMin[currentDifficulty] != m_BSWRecords[m_uiSpellIdx].m_uiSpellTimerMax[currentDifficulty]) + { + m_BSWRecords[m_uiSpellIdx].m_SpellTimer = urand(0,m_BSWRecords[m_uiSpellIdx].m_uiSpellTimerMax[currentDifficulty]); + } + else m_BSWRecords[m_uiSpellIdx].m_SpellTimer = m_BSWRecords[m_uiSpellIdx].m_uiSpellTimerMin[currentDifficulty]; + +}; + +void BSWScriptedAI::_loadFromDB() +{ + // mutex block for process-safe request execute + ACE_Process_Mutex mMutex = ACE_Process_Mutex("BSW_Lock"); + + debug_log("BSW: Loading table of creature %u spell on difficulty %u", m_creature->GetEntry(), currentDifficulty); + + char query[MAX_QUERY_LEN]; + + sprintf(query, "SELECT entry, spellID_N10, spellID_N25, spellID_H10, spellID_H25, timerMin_N10, timerMin_N25, timerMin_H10, timerMin_H25, timerMax_N10, timerMax_N25, timerMax_H10, timerMax_H25, data1, data2, data3, data4, locData_x, locData_y, locData_z, varData, StageMask_N, StageMask_H, CastType, isVisualEffect, isBugged, textEntry FROM `boss_spell_table` WHERE entry = %u;\r\n", m_creature->GetEntry()); + + mMutex.acquire(); + QueryResult* Result = strSD2Pquery(query); + mMutex.release(); + + if (Result) + { + uint32 uiCount = 0; + do + { + BSWRecord m_BSWRecord; + + Field* pFields = Result->Fetch(); + + m_BSWRecord.id = uiCount; + + uint32 m_creatureEntry = pFields[0].GetUInt32(); + + for (uint8 j = 0; j < DIFFICULTY_LEVELS; ++j) + m_BSWRecord.m_uiSpellEntry[j] = pFields[1+j].GetUInt32(); + + for (uint8 j = 0; j < DIFFICULTY_LEVELS; ++j) + m_BSWRecord.m_uiSpellTimerMin[j] = pFields[1+DIFFICULTY_LEVELS+j].GetUInt32(); + + for (uint8 j = 0; j < DIFFICULTY_LEVELS; ++j) + m_BSWRecord.m_uiSpellTimerMax[j] = pFields[1+DIFFICULTY_LEVELS*2+j].GetUInt32(); + + for (uint8 j = 0; j < DIFFICULTY_LEVELS; ++j) + m_BSWRecord.m_uiSpellData[j] = pFields[1+DIFFICULTY_LEVELS*3+j].GetUInt32(); + + m_BSWRecord.LocData.x = pFields[1+DIFFICULTY_LEVELS*4].GetFloat(); + m_BSWRecord.LocData.y = pFields[2+DIFFICULTY_LEVELS*4].GetFloat(); + m_BSWRecord.LocData.z = pFields[3+DIFFICULTY_LEVELS*4].GetFloat(); + + m_BSWRecord.varData = pFields[4+DIFFICULTY_LEVELS*4].GetInt32(); + + m_BSWRecord.StageMaskN = pFields[5+DIFFICULTY_LEVELS*4].GetUInt32(); + m_BSWRecord.StageMaskH = pFields[6+DIFFICULTY_LEVELS*4].GetUInt32(); + + m_BSWRecord.m_CastTarget = _getBSWCastType(pFields[7+DIFFICULTY_LEVELS*4].GetUInt8()); + + m_BSWRecord.m_IsVisualEffect = (pFields[8+DIFFICULTY_LEVELS*4].GetUInt8() == 0) ? false : true ; + + m_BSWRecord.m_IsBugged = (pFields[9+DIFFICULTY_LEVELS*4].GetUInt8() == 0) ? false : true ; + + m_BSWRecord.textEntry = pFields[10+DIFFICULTY_LEVELS*4].GetInt32(); + + m_BSWRecords.push_back(m_BSWRecord); + + if (m_creatureEntry != m_creature->GetEntry()) error_log("BSW: Unknown error while load boss_spell_table"); + else ++uiCount; + } while (Result->NextRow()); + + delete Result; + + debug_log("BSW: Loaded %u spell data records for creature %u", bossSpellCount(), m_creature->GetEntry()); + } + else + { + error_log("BSW: BSW table for creature %u is empty.", m_creature->GetEntry()); + }; +} + +bool BSWScriptedAI::_QuerySpellPeriod(uint8 m_uiSpellIdx, uint32 diff, bool ignorecast) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + if (m_creature->IsNonMeleeSpellCasted(false) && !ignorecast) return false; + + if (pSpell->m_SpellTimer <= diff) + { + if (pSpell->m_uiSpellTimerMax[currentDifficulty] >= HOUR*IN_MILLISECONDS) pSpell->m_SpellTimer=HOUR*IN_MILLISECONDS; + else pSpell->m_SpellTimer = urand(pSpell->m_uiSpellTimerMin[currentDifficulty],pSpell->m_uiSpellTimerMax[currentDifficulty]); + return true; + } + else + { + pSpell->m_SpellTimer -= diff; + return false; + }; +}; + +CanCastResult BSWScriptedAI::_BSWSpellSelector(uint8 m_uiSpellIdx, Unit* pTarget) +{ + + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + Unit* pSummon = NULL; + + CanCastResult result = CAST_FAIL_OTHER; + + debug_log("BSW: Casting spell number %u type %u",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + + if (pSpell->m_uiSpellTimerMax[currentDifficulty] >= HOUR*IN_MILLISECONDS) + m_creature->InterruptNonMeleeSpells(true); + + switch (pSpell->m_CastTarget) { + + case DO_NOTHING: + result = CAST_OK; + break; + + case CAST_ON_SELF: + result = _BSWCastOnTarget(m_creature, m_uiSpellIdx); + break; + + case CAST_ON_SUMMONS: + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case CAST_ON_VICTIM: + pTarget = m_creature->getVictim(); + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case CAST_ON_RANDOM: + pTarget = _doSelect(0, false, 60.0f); + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case CAST_ON_BOTTOMAGGRO: + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_BOTTOMAGGRO,0); + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case CAST_ON_TARGET: + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case APPLY_AURA_SELF: + if (_doAura(m_uiSpellIdx, m_creature, EFFECT_INDEX_0)) + result = CAST_OK; + else result = CAST_FAIL_OTHER; + break; + + case APPLY_AURA_TARGET: + if (!pTarget || !pTarget->IsInMap(m_creature)) + { + result = CAST_FAIL_OTHER; + break; + } + if (_doAura(m_uiSpellIdx, pTarget, EFFECT_INDEX_0)) + result = CAST_OK; + else result = CAST_FAIL_OTHER; + break; + + case SUMMON_NORMAL: + pSummon = _doSummon(m_uiSpellIdx, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + if(pSummon) result = CAST_OK; + else result = CAST_FAIL_OTHER; + break; + + case SUMMON_TEMP: + pSummon = _doSummon(m_uiSpellIdx, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, + urand(pSpell->m_uiSpellTimerMin[currentDifficulty],pSpell->m_uiSpellTimerMax[currentDifficulty])); + if(pSummon) result = CAST_OK; + else result = CAST_FAIL_OTHER; + break; + + case SUMMON_INSTANT: + pSummon = _doSummon(m_uiSpellIdx, TEMPSUMMON_MANUAL_DESPAWN,0); + if(pSummon) result = CAST_OK; + else result = CAST_FAIL_OTHER; + break; + + case CAST_ON_ALLPLAYERS: + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const& pPlayers = pMap->GetPlayers(); + if (!pPlayers.isEmpty()) + { + for (Map::PlayerList::const_iterator itr = pPlayers.begin(); itr != pPlayers.end(); ++itr) + { + pTarget = itr->getSource(); + if (pTarget && pTarget->isAlive() && pTarget->IsWithinDistInMap(m_creature, pSpell->LocData.x)) + { + if (!pSpell->m_IsBugged) + { + m_creature->CastSpell(pTarget, pSpell->m_uiSpellEntry[currentDifficulty], false); + } + else + { + _BSWDoCast(m_uiSpellIdx, pTarget); + }; + result = CAST_OK; + }; + } + } else result = CAST_FAIL_OTHER; + } + break; + + case CAST_ON_FRENDLY: + pTarget = DoSelectLowestHpFriendly(pSpell->LocData.x,0); + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case CAST_ON_FRENDLY_LOWHP: + pTarget = DoSelectLowestHpFriendly(pSpell->LocData.x,1); + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case CAST_ON_RANDOM_POINT: + if (!pTarget) pTarget = m_creature; + if (pSpell->LocData.z <= 1.0f) + { + float fPosX, fPosY, fPosZ; + if (!pTarget->IsPositionValid() || !pTarget->IsInMap(m_creature)) + { + if (pTarget->GetTypeId() == TYPEID_PLAYER) + error_log("BSW: CAST_ON_RANDOM_POINT FAILED: player has invalid position. SpellID is %u",pSpell->m_uiSpellEntry[currentDifficulty]); + else error_log("BSW: CAST_ON_RANDOM_POINT FAILED: creature has invalid position. SpellID is %u",pSpell->m_uiSpellEntry[currentDifficulty]); + result = CAST_FAIL_OTHER; + break; + } + + pTarget->GetPosition(fPosX, fPosY, fPosZ); + pTarget->GetRandomPoint(fPosX, fPosY, fPosZ, urand((uint32)pSpell->LocData.x, (uint32)pSpell->LocData.y), fPosX, fPosY, fPosZ); + if ((int)fPosZ == 0) + { + error_log("BSW: CAST_ON_RANDOM_POINT FAILED: Positon Z is NULL. Strange bug"); + result = CAST_FAIL_OTHER; + break; + } + + if (SpellEntry const *spell = (SpellEntry *)GetSpellStore()->LookupEntry(pSpell->m_uiSpellEntry[currentDifficulty])) + if (SpellRangeEntry const *pSpellRange = GetSpellRangeStore()->LookupEntry(spell->GetRangeIndex())) + if (m_creature->GetDistance(fPosX, fPosY, fPosZ) <= pSpellRange->maxRange) + { + m_creature->CastSpell(fPosX, fPosY, fPosZ, pSpell->m_uiSpellEntry[currentDifficulty], false); + result = CAST_OK; + break; + }; + result = CAST_FAIL_TOO_FAR; + } else result = CAST_FAIL_OTHER; + break; + + case CAST_ON_RANDOM_PLAYER: + if ( pSpell->LocData.x < 1 ) pTarget = _doSelect(0, false, 60.0f); + else pTarget = _doSelect(0, false, (float)pSpell->LocData.x); + result = _BSWCastOnTarget(pTarget, m_uiSpellIdx); + break; + + case APPLY_AURA_ALLPLAYERS: + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const& pPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pPlayers.begin(); itr != pPlayers.end(); ++itr) + { + pTarget = itr->getSource(); + if (pTarget && pTarget->isAlive() && pTarget->IsWithinDistInMap(m_creature, pSpell->LocData.x)) + { + _doAura(m_uiSpellIdx, pTarget, EFFECT_INDEX_0); + result = CAST_OK; + } + } + } + break; + + case FORCE_CAST: + result = _BSWDoForceCast(m_uiSpellIdx, pTarget); + break; + + case SPELLTABLEPARM_NUMBER: + default: + error_log("BSW: FAILED casting spell number %u type %u - type not exists",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + result = CAST_FAIL_OTHER; + break; + }; + + if (pSpell->textEntry && result == CAST_OK) + { + if (pTarget) + DoScriptText(pSpell->textEntry,m_creature,pTarget); + else + DoScriptText(pSpell->textEntry,m_creature); + }; + + debug_log("BSW: Casted spell number %u, result = %u",pSpell->m_uiSpellEntry[currentDifficulty], result); + + return result; +}; + +CanCastResult BSWScriptedAI::_BSWCastOnTarget(Unit* pTarget, uint8 m_uiSpellIdx) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + if (!pTarget || !pTarget->IsInMap(m_creature) || !pTarget->isAlive()) + { + debug_log("BSW: warning - failed casting (on target) spell number %u - no target or target not in map",pSpell->m_uiSpellEntry[currentDifficulty]); + return CAST_FAIL_OTHER; + } + + debug_log("BSW: Casting (on target) spell %u type %u",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + + if (!pSpell->m_IsBugged) return _DoCastSpellIfCan(pTarget, pSpell->m_uiSpellEntry[currentDifficulty]); + else if (pSpell->m_IsBugged) return _BSWDoCast(m_uiSpellIdx, pTarget); + else return CAST_FAIL_OTHER; +}; + +bool BSWScriptedAI::_hasAura(uint8 m_uiSpellIdx, Unit* pTarget) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + return _hasAura(pSpell->m_uiSpellEntry[currentDifficulty], pTarget); + +}; + +bool BSWScriptedAI::_hasAura(uint32 SpellID, Unit* pTarget) +{ + if (!pTarget || !pTarget->IsInMap(m_creature)) + { + error_log("BSW: FAILED Query aura for spell %u - no target or target not in map",SpellID); + return false; + } + + return (pTarget->HasAura(SpellID)); + +}; + +uint8 BSWScriptedAI::_auraCount(uint8 m_uiSpellIdx, Unit* pTarget, SpellEffectIndex index) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + return _auraCount(pSpell->m_uiSpellEntry[currentDifficulty], pTarget, index); + +}; + +uint8 BSWScriptedAI::_auraCount(uint32 SpellID, Unit* pTarget, SpellEffectIndex index) +{ + if (!_hasAura(SpellID,pTarget)) return 0; + + if (Aura* aura = pTarget->GetAura(SpellID, index)) + if (aura->GetStackAmount() > 0) + return aura->GetStackAmount(); + return 0; + +}; + +uint8 BSWScriptedAI::_findSpellIDX(uint32 SpellID) +{ + if (bossSpellCount() > 0) + for(uint8 i = 0; i < bossSpellCount(); ++i) + if (m_BSWRecords[i].m_uiSpellEntry[RAID_DIFFICULTY_10MAN_NORMAL] == SpellID) return i; + + error_log("BSW: spell %u not found in m_creature %u spelltable. Memory or database error?", SpellID, m_creature->GetEntry()); + + return SPELL_INDEX_ERROR; +} + +BSWRecord* BSWScriptedAI::_getRecord(uint32 SpellID) +{ + if (!m_BSWRecords.empty()) + { + for(uint8 i = 0; i < m_BSWRecords.size(); ++i) + if (m_BSWRecords[i].m_uiSpellEntry[RAID_DIFFICULTY_10MAN_NORMAL] == SpellID) return &m_BSWRecords[i]; + } + error_log("BSW: spell %u not found in m_creature %u spelltable. Memory or database error?", SpellID, m_creature->GetEntry()); + return NULL; +} + +BossSpellTableParameters BSWScriptedAI::_getBSWCastType(uint32 pTemp) +{ + switch (pTemp) { + case 0: return DO_NOTHING; + case 1: return CAST_ON_SELF; + case 2: return CAST_ON_SUMMONS; + case 3: return CAST_ON_VICTIM; + case 4: return CAST_ON_RANDOM; + case 5: return CAST_ON_BOTTOMAGGRO; + case 6: return CAST_ON_TARGET; + case 7: return APPLY_AURA_SELF; + case 8: return APPLY_AURA_TARGET; + case 9: return SUMMON_NORMAL; + case 10: return SUMMON_INSTANT; + case 11: return SUMMON_TEMP; + case 12: return CAST_ON_ALLPLAYERS; + case 13: return CAST_ON_FRENDLY; + case 14: return CAST_ON_FRENDLY_LOWHP; + case 15: return CAST_ON_RANDOM_POINT; + case 16: return CAST_ON_RANDOM_PLAYER; + case 17: return APPLY_AURA_ALLPLAYERS; + case 18: return FORCE_CAST; + case 19: return SPELLTABLEPARM_NUMBER; + default: return DO_NOTHING; + }; +}; + +CanCastResult BSWScriptedAI::_BSWDoCast(uint8 m_uiSpellIdx, Unit* pTarget) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + if (!pTarget || !pTarget->IsInMap(m_creature) || !pTarget->isAlive()) + { + error_log("BSW: warning - failed casting bugged spell number %u - no target or target not in map",pSpell->m_uiSpellEntry[currentDifficulty]); + return CAST_FAIL_OTHER; + } + + debug_log("BSW: Casting bugged spell number %u type %u",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + + pTarget->InterruptNonMeleeSpells(false); + + pTarget->CastSpell(pTarget, pSpell->m_uiSpellEntry[currentDifficulty], false); + + return CAST_OK; +}; + +CanCastResult BSWScriptedAI::_BSWDoForceCast(uint8 m_uiSpellIdx, Unit* pTarget) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + if (!pTarget || !pTarget->IsInMap(m_creature) || !pTarget->isAlive()) + { + error_log("BSW: warning - failed forced casting spell number %u - no target or target not in map",pSpell->m_uiSpellEntry[currentDifficulty]); + return CAST_FAIL_OTHER; + } + + debug_log("BSW: Forced casting spell number %u type %u",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + + pTarget->InterruptNonMeleeSpells(false); + + pTarget->CastSpell(m_creature, pSpell->m_uiSpellEntry[currentDifficulty], true); + + return CAST_OK; +}; + +void BSWScriptedAI::_fillEmptyDataField() +{ + for (uint8 i = 0; i < bossSpellCount(); ++i) + for (uint8 j = 1; j < DIFFICULTY_LEVELS; ++j) + { + if (m_BSWRecords[i].m_uiSpellEntry[j] == 0) + { + SpellEntry const* spell = GetSpellEntryByDifficulty(m_BSWRecords[i].m_uiSpellEntry[0],(Difficulty)j,true); + if (spell) + m_BSWRecords[i].m_uiSpellEntry[j] = spell->Id; + else m_BSWRecords[i].m_uiSpellEntry[j] = m_BSWRecords[i].m_uiSpellEntry[j-1]; + } + + if (m_BSWRecords[i].m_uiSpellTimerMin[j] == 0) + m_BSWRecords[i].m_uiSpellTimerMin[j] = m_BSWRecords[i].m_uiSpellTimerMin[j-1]; + + if (m_BSWRecords[i].m_uiSpellTimerMax[j] == 0) + m_BSWRecords[i].m_uiSpellTimerMax[j] = m_BSWRecords[i].m_uiSpellTimerMax[j-1]; + + if (m_BSWRecords[i].m_uiSpellData[j] == 0) + m_BSWRecords[i].m_uiSpellData[j] = m_BSWRecords[i].m_uiSpellData[j-1]; + }; +}; + +Unit* BSWScriptedAI::_doSummon(uint8 m_uiSpellIdx, TempSummonType summontype, uint32 delay) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + debug_log("BSW: Summoning creature number %u type %u despawn delay %u",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget, delay); + + if (pSpell->LocData.z <= 1.0f) + { + float fPosX, fPosY, fPosZ; + if (!m_creature->IsPositionValid()) + { + error_log("BSW: FAILED summoning creature, creature %u has invalid position",m_creature->GetEntry()); + return NULL; + } + m_creature->GetPosition(fPosX, fPosY, fPosZ); + m_creature->GetRandomPoint(fPosX, fPosY, fPosZ, urand((uint32)pSpell->LocData.x, (uint32)pSpell->LocData.y), fPosX, fPosY, fPosZ); + return m_creature->SummonCreature(pSpell->m_uiSpellEntry[currentDifficulty], fPosX, fPosY, fPosZ+0.8f, 0, summontype, delay); + } + else return m_creature->SummonCreature(pSpell->m_uiSpellEntry[currentDifficulty], pSpell->LocData.x, pSpell->LocData.y, pSpell->LocData.z, 0, summontype, delay); +}; + +Unit* BSWScriptedAI::_doSummonAtPosition(uint8 m_uiSpellIdx, float fPosX, float fPosY, float fPosZ) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + switch (pSpell->m_CastTarget) + { + case SUMMON_NORMAL: + return _doSummonAtPosition(pSpell->m_uiSpellEntry[currentDifficulty], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 0, fPosX, fPosY, fPosZ); + break; + + case SUMMON_TEMP: + return _doSummonAtPosition(pSpell->m_uiSpellEntry[currentDifficulty], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, urand(pSpell->m_uiSpellTimerMin[currentDifficulty],pSpell->m_uiSpellTimerMax[currentDifficulty]), fPosX, fPosY, fPosZ); + break; + + case SUMMON_INSTANT: + return _doSummonAtPosition(pSpell->m_uiSpellEntry[currentDifficulty], TEMPSUMMON_MANUAL_DESPAWN, urand(pSpell->m_uiSpellTimerMin[currentDifficulty],pSpell->m_uiSpellTimerMax[currentDifficulty]), fPosX, fPosY, fPosZ); + break; + + default: + break; + } + error_log("BSW: FAILED creature number %u type %u ",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + return NULL; +}; + +Unit* BSWScriptedAI::_doSummonAtPosition(uint32 guid, TempSummonType summontype, uint32 delay, float fPosX, float fPosY, float fPosZ) +{ + + debug_log("BSW: Summoning creature number %u despawn delay %u at position %f %f %f", guid, delay, fPosX, fPosY, fPosZ); + + return m_creature->SummonCreature(guid, fPosX, fPosY, fPosZ, 0, summontype, delay); +}; + +bool BSWScriptedAI::_doRemove(uint8 m_uiSpellIdx, Unit* pTarget, uint8 index) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + debug_log("BSW: Removing effects of spell %u type %u",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + + switch (pSpell->m_CastTarget) + { + case DO_NOTHING: + return true; + break; + + case SUMMON_NORMAL: + case SUMMON_TEMP: + case SUMMON_INSTANT: + return false; + break; + + case CAST_ON_SELF: + case APPLY_AURA_SELF: + pTarget = m_creature; + break; + + case CAST_ON_SUMMONS: + case CAST_ON_VICTIM: + case CAST_ON_BOTTOMAGGRO: + case CAST_ON_TARGET: + case FORCE_CAST: + case APPLY_AURA_TARGET: + if (!pTarget) + return false; + break; + + case CAST_ON_RANDOM: + case CAST_ON_RANDOM_PLAYER: + case APPLY_AURA_ALLPLAYERS: + case CAST_ON_ALLPLAYERS: + _doRemoveFromAll(m_uiSpellIdx); + return true; + break; + + default: + debug_log("BSW: FAILED Removing effects of spell %u type %u - unsupported type",pSpell->m_uiSpellEntry[currentDifficulty], pSpell->m_CastTarget); + return false; + break; + } + + return _doRemove(pSpell->m_uiSpellEntry[currentDifficulty], pTarget, index); + +}; + +bool BSWScriptedAI::_doRemove(uint32 SpellID, Unit* pTarget, uint8 index) +{ + + if (!_hasAura(SpellID, pTarget)) return false; + + if (index == EFFECT_INDEX_ALL) + { + pTarget->RemoveAurasDueToSpell(SpellID); + } + else if (_auraCount(SpellID,pTarget,(SpellEffectIndex)index) > 1) + { + if (SpellAuraHolderPtr holder = pTarget->GetSpellAuraHolder(SpellID, pTarget->GetObjectGuid())) + { + if (holder->ModStackAmount(-1)) + { + pTarget->RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_DISPEL); + } else return false; + } + } + else + pTarget->RemoveAurasDueToSpell(SpellID); + + debug_log("BSW: Removed effects of spell %u index %u",SpellID, index); + return true; +}; + +bool BSWScriptedAI::_doRemoveFromAll(uint8 m_uiSpellIdx) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + return _doRemoveFromAll(pSpell->m_uiSpellEntry[currentDifficulty]); +}; + +bool BSWScriptedAI::_doRemoveFromAll(uint32 SpellID) +{ + Map* pMap = m_creature->GetMap(); + Map::PlayerList const& pPlayers = pMap->GetPlayers(); + if (!pPlayers.isEmpty()) + { + debug_log("BSW: Removing effects of spell %u from all players",SpellID); + + for (Map::PlayerList::const_iterator itr = pPlayers.begin(); itr != pPlayers.end(); ++itr) + { + Unit* pTarget = itr->getSource(); + if (pTarget && pTarget->IsInWorld()) + { + pTarget->RemoveAurasDueToSpell(SpellID); + if (Pet* pPet = pTarget->GetPet()) + pPet->RemoveAurasDueToSpell(SpellID); + } + } + return true; + } + else + { + debug_log("BSW: Removing effects of spell %u from all players FAILED - no players in map",SpellID); + return false; + } +}; + +bool BSWScriptedAI::_doAura(uint8 m_uiSpellIdx, Unit* pTarget) +{ +// BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + if (!pTarget) + pTarget = m_creature; + + bool result = true; + + for(int i = 0; i < MAX_EFFECT_INDEX; ++i) + result = result && _doAura(m_uiSpellIdx, pTarget, SpellEffectIndex(i), !i); + + return result; + +}; + +bool BSWScriptedAI::_doAura(uint32 SpellID, Unit* pTarget) +{ + if (!pTarget) + pTarget = m_creature; + + bool result = true; + + for(int i = 0; i < MAX_EFFECT_INDEX; ++i) + result = result && _doAura(SpellID, pTarget, SpellEffectIndex(i), 0, !i); + + return result; + +}; + + +bool BSWScriptedAI::_doAura(uint8 m_uiSpellIdx, Unit* pTarget, SpellEffectIndex index, bool isStack) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + if (!pTarget) + pTarget = m_creature; + + return _doAura(pSpell->m_uiSpellEntry[currentDifficulty], pTarget, index, pSpell->varData, isStack); + +}; + + +bool BSWScriptedAI::_doAura(uint32 SpellID, Unit* pTarget, SpellEffectIndex index, int32 basepoint, bool isStack) +{ + if (!pTarget || !pTarget->IsInMap(m_creature) || !pTarget->isAlive()) + { + error_log("BSW: FAILED adding aura of spell number %u - no target or target not in map or target is dead",SpellID); + return false; + } + + if (_hasAura(SpellID,pTarget)) + debug_log("BSW: adding aura stack from spell %u index %u",SpellID, index); + else debug_log("BSW: adding new aura from spell %u index %u",SpellID, index); + + SpellEntry const *spell = (SpellEntry *)GetSpellStore()->LookupEntry(SpellID); + + if (spell) + { + if (IsSpellAppliesAura(spell, (1 << EFFECT_INDEX_0) | (1 << EFFECT_INDEX_1) | (1 << EFFECT_INDEX_2)) || IsSpellHaveEffect(spell, SPELL_EFFECT_PERSISTENT_AREA_AURA)) + { + int32 _basepoint = basepoint ? basepoint - 1 : spell->GetSpellEffect(SpellEffectIndex(index))->EffectBasePoints + 1; + + bool addedToExisting = true; + + SpellAuraHolderPtr holder = pTarget->GetSpellAuraHolder(SpellID, pTarget->GetObjectGuid()); + + Aura* aura = NULL; + + if (!holder) + { + holder = CreateSpellAuraHolder(spell, pTarget, pTarget); + addedToExisting = false; + } + + aura = holder->GetAuraByEffectIndex(index); + if (aura) + { + if (isStack) + holder->ModStackAmount(1); + } + else + { + aura = holder->CreateAura(spell, index, &_basepoint, holder, pTarget, m_creature, NULL); + holder->SetAuraDuration(aura->GetAuraMaxDuration()); + } + + if (aura && addedToExisting) + { + pTarget->AddAuraToModList(aura); + aura->ApplyModifier(true,true); + } + else if (holder) + pTarget->AddSpellAuraHolder(holder); + + return holder ? true : false; + } + } + + error_log("BSW: FAILED adding aura from spell %u index %u",SpellID, index); + + return false; +}; + +CanCastResult BSWScriptedAI::_DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, ObjectGuid uiOriginalCasterGUID) +{ + if (!pTarget || !pTarget->IsInWorld() || !pTarget->IsInMap(m_creature)|| !pTarget->isAlive()) return CAST_FAIL_OTHER; + + return DoCastSpellIfCan(pTarget,uiSpell,uiCastFlags,uiOriginalCasterGUID); +} + +// Not threat-based select random player function + +Unit* BSWScriptedAI::_doSelect(uint32 SpellID, bool spellsearchtype, float range, bool includeVictim) +{ + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &pList = pMap->GetPlayers(); + if (pList.isEmpty()) return NULL; + + std::vector _list; + _list.clear(); + + for(Map::PlayerList::const_iterator i = pList.begin(); i != pList.end(); ++i) + if (Player* player = i->getSource()) + { + if (player->isGameMaster()) continue; + + if (!player->IsInMap(m_creature)) continue; + + if (player == m_creature->getVictim() && !includeVictim) continue; + + if (player->isAlive() + && player->IsWithinDistInMap(m_creature, range) + && (SpellID == 0 || (player->HasAura(SpellID) == spellsearchtype)) + ) + _list.push_back((Unit*)player); + } + + debug_log("BSW: search random player with criteria = %u, found %u players.",SpellID,_list.size()); + + if (_list.empty()) return NULL; + else return _list[urand(0,_list.size() - 1)]; +}; + +Creature* BSWScriptedAI::doSelectNearestCreature(uint32 id, float range) +{ + Creature* pTarget = GetClosestCreatureWithEntry(m_creature, id, range); + + if (pTarget && pTarget->IsInMap(m_creature) && pTarget != m_creature && pTarget->isAlive()) + { + debug_log("BSW: search creature %u in range %f - found it.",id,range); + return pTarget; + } + else + { + debug_log("BSW: search creature %u in range %f - NOT found.",id,range); + return NULL; + } +} + +uint32 BSWScriptedAI::_getSpellData(uint8 m_uiSpellIdx) +{ + BSWRecord* pSpell = &m_BSWRecords[m_uiSpellIdx]; + + return pSpell->m_uiSpellData[currentDifficulty]; +}; + +bool BSWScriptedAI::doCastAll(uint32 diff) +{ + + uint8 succesfulCast = 0; + + if (bossSpellCount() > 0) + { + for(uint8 i = 0; i < bossSpellCount(); ++i) + if (_QuerySpellPeriod(i, diff)) + if (_BSWSpellSelector(i) == CAST_OK) + ++succesfulCast; + + if (succesfulCast) + debug_log("BSW: Casting all spells for creature %u done. Successful casted %u spells from %u.", m_creature->GetEntry(),succesfulCast,bossSpellCount()); + } + else + { + error_log("BSW: Casting all spells for creature %u failed. Database has no spells.", m_creature->GetEntry()); + } + + return (succesfulCast >= 1) ? true : false; + +}; + +bool BSWScriptedAI::_isDifficultyInMask(uint8 mask) +{ + return ((uint8)currentDifficulty & mask); +}; + +#endif diff --git a/base/BSW_ai.h b/base/BSW_ai.h new file mode 100644 index 0000000000..d188d6cacf --- /dev/null +++ b/base/BSW_ai.h @@ -0,0 +1,292 @@ +/* Copyright (C) 2009 - 2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_BOSS_SPELL_WORKER_H +#define DEF_BOSS_SPELL_WORKER_H +#define BSW_VERSION 0.6.12 + +#include "precompiled.h" +#include "Player.h" +#include "SpellAuras.h" +#include "SpellMgr.h" +#include "Unit.h" +#include "Database/DatabaseEnv.h" +#include "../ScriptMgr.h" + + +enum +{ + DIFFICULTY_LEVELS = 4, + EFFECT_INDEX_ALL = 255, + SPELL_INDEX_ERROR = 255, +}; + +enum BossSpellFlag +{ + CAST_NORMAL, + CAST_REMOVE, + CAST_OVERRIDE, + SPELLFLAG_NUMBER +}; + +enum BossSpellTableParameters +{ + DO_NOTHING = 0, + CAST_ON_SELF = 1, + CAST_ON_SUMMONS = 2, + CAST_ON_VICTIM = 3, + CAST_ON_RANDOM = 4, + CAST_ON_BOTTOMAGGRO = 5, + CAST_ON_TARGET = 6, + APPLY_AURA_SELF = 7, + APPLY_AURA_TARGET = 8, + SUMMON_NORMAL = 9, + SUMMON_INSTANT = 10, + SUMMON_TEMP = 11, + CAST_ON_ALLPLAYERS = 12, + CAST_ON_FRENDLY = 13, + CAST_ON_FRENDLY_LOWHP = 14, + CAST_ON_RANDOM_POINT = 15, + CAST_ON_RANDOM_PLAYER = 16, + APPLY_AURA_ALLPLAYERS = 17, + FORCE_CAST = 18, + SPELLTABLEPARM_NUMBER +}; + +struct WayPoints +{ + WayPoints(int32 _id, float _x, float _y, float _z) + { + id = _id; + x = _x; + y = _y; + z = _z; + } + int32 id; + float x, y, z; +}; + +struct BSWRecord +{ + + public: + // External (loaded from database) variables + uint32 id; + uint32 m_uiSpellEntry[DIFFICULTY_LEVELS]; // Stores spell entry for difficulty levels + uint32 m_uiSpellTimerMin[DIFFICULTY_LEVELS]; // The timer (min) before the next spell casting, in milliseconds + uint32 m_uiSpellTimerMax[DIFFICULTY_LEVELS]; // The timer (max) before the next spell casting + uint32 m_uiSpellData[DIFFICULTY_LEVELS]; // Additional data for spell casting or summon + Location LocData; // Float data structure for locations + int varData; // Additional data for spell + uint32 StageMaskN; // Stage mask for this spell (normal) + uint32 StageMaskH; // Stage mask for this spell (heroic) + BossSpellTableParameters m_CastTarget; // Target on casting spell + bool m_IsVisualEffect; // Spellcasting is visual effect or real effect + bool m_IsBugged; // Need override for this spell + int32 textEntry; // Text entry from script_text for this spell + // Internal variables + uint32 m_SpellTimer; // Current timer for this spell +}; + +struct MANGOS_DLL_DECL BSWScriptedAI : public ScriptedAI +{ + public: + explicit BSWScriptedAI(Creature* pCreature); + + ~BSWScriptedAI(); + + void doReset(); + + void resetTimer(uint32 SpellID) + { + if (queryIndex(_findSpellIDX(SpellID))) _resetTimer(_findSpellIDX(SpellID)); + else return; + }; + + void resetTimers() + { + for (uint8 i = 0; i < bossSpellCount(); ++i) + _resetTimer(i); + }; + + bool timedQuery(uint32 SpellID, uint32 diff, bool ignorecast = false) + { + return queryIndex(_findSpellIDX(SpellID)) ? _QuerySpellPeriod(_findSpellIDX(SpellID), diff, ignorecast) : false; + }; + + CanCastResult timedCast(uint32 SpellID, uint32 diff, Unit* pTarget = NULL) + { + if (!queryIndex(_findSpellIDX(SpellID))) return CAST_FAIL_OTHER; + return _QuerySpellPeriod(_findSpellIDX(SpellID), diff) ? _BSWSpellSelector(_findSpellIDX(SpellID), pTarget) : CAST_FAIL_STATE; + }; + + CanCastResult doCast(uint32 SpellID, Unit* pTarget = NULL) + { + return queryIndex(_findSpellIDX(SpellID)) ? _BSWSpellSelector(_findSpellIDX(SpellID), pTarget) : CAST_FAIL_OTHER; + }; + + CanCastResult doCast(Unit* pTarget, uint32 SpellID) + { + if (!pTarget) return CAST_FAIL_OTHER; + return queryIndex(_findSpellIDX(SpellID)) ? _BSWCastOnTarget(pTarget, _findSpellIDX(SpellID)) : CAST_FAIL_OTHER; + }; + + bool doRemove(uint32 SpellID, Unit* pTarget = NULL, uint8 index = EFFECT_INDEX_ALL) + { + return queryIndex(_findSpellIDX(SpellID)) ? _doRemove(_findSpellIDX(SpellID),pTarget,index) : _doRemove(SpellID,pTarget,index); + }; + + bool doRemoveFromAll(uint32 SpellID) + { + return queryIndex(_findSpellIDX(SpellID)) ? _doRemoveFromAll(_findSpellIDX(SpellID)) : _doRemoveFromAll(SpellID); + }; + + bool doAura(uint32 SpellID, Unit* pTarget, SpellEffectIndex index, int32 basepoint = 0, bool isStack = true) + { + return queryIndex(_findSpellIDX(SpellID)) ? _doAura(_findSpellIDX(SpellID), pTarget, index, isStack) : _doAura(SpellID, pTarget, index, basepoint, isStack); + }; + + bool doAura(uint32 SpellID, Unit* pTarget = NULL) + { + return queryIndex(_findSpellIDX(SpellID)) ? _doAura(_findSpellIDX(SpellID), pTarget) : _doAura(SpellID, pTarget); + }; + + bool hasAura(uint32 SpellID, Unit* pTarget = NULL) + { + if (!pTarget) pTarget = m_creature; + return queryIndex(_findSpellIDX(SpellID)) ? _hasAura(_findSpellIDX(SpellID),pTarget) : _hasAura(SpellID,pTarget); + }; + + uint8 auraCount(uint32 SpellID, Unit* pTarget = NULL, SpellEffectIndex index = EFFECT_INDEX_0) + { + if (!pTarget) pTarget = m_creature; + return queryIndex(_findSpellIDX(SpellID)) ? _auraCount(_findSpellIDX(SpellID),pTarget,index) : _auraCount(SpellID,pTarget,index); + }; + + Unit* doSummon(uint32 SpellID, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN, uint32 delay = 60000) + { + return queryIndex(_findSpellIDX(SpellID)) ? _doSummon(_findSpellIDX(SpellID), type, delay) : NULL; + }; + + Unit* doSelectRandomPlayer(uint32 SpellID = 0, bool spellsearchtype = false, float range = 100.0f, bool includeVictim = true) + { + return _doSelect(SpellID, spellsearchtype, range, includeVictim); + }; + + Unit* doSelectRandomPlayerAtRange(float range, bool includeVictim = true) + { + return _doSelect(0, false, range, includeVictim); + }; + + Unit* doSummon(uint32 SpellID, float fPosX, float fPosY, float fPosZ, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN, uint32 delay = 60000) + { + return queryIndex(_findSpellIDX(SpellID)) ? _doSummonAtPosition(_findSpellIDX(SpellID), fPosX, fPosY, fPosZ) : _doSummonAtPosition(SpellID, type, delay, fPosX, fPosY, fPosZ); + }; + + uint8 bossSpellCount() + { + return m_BSWRecords.size(); + }; + + bool queryIndex(uint8 m_uiSpellIdx) + { + if (m_uiSpellIdx == SPELL_INDEX_ERROR) return false; + else if (m_uiSpellIdx >= 0 && m_uiSpellIdx < bossSpellCount()) return true; + else return false; + }; + + Creature* doSelectNearestCreature(uint32 guid, float range = 120.0f); + + uint32 getSpellData(uint32 SpellID) + { + return queryIndex(_findSpellIDX(SpellID)) ? _getSpellData(_findSpellIDX(SpellID)) : 0; + }; + + bool doCastAll(uint32 diff); + + uint8 getStage() { return _stage; }; + + void setStage(uint8 stage) { _stage = stage; }; + + bool isHeroic() { Map* pMap = m_creature->GetMap(); return pMap->IsRaid() ? _isDifficultyInMask(12) : _isDifficultyInMask(2); }; + + bool isNormal() { return !isHeroic(); }; + + bool is25() { Map* pMap = m_creature->GetMap(); return pMap->IsRaid() ? _isDifficultyInMask(10) : false; }; + + uint32 getSpellWithDifficulty(uint32 SpellID) { return (queryIndex(_findSpellIDX(SpellID)) ? m_BSWRecords[_findSpellIDX(SpellID)].m_uiSpellEntry[currentDifficulty] : SpellID); }; + + protected: + + Difficulty currentDifficulty; + + std::vector m_BSWRecords; + + private: + + BossSpellTableParameters _getBSWCastType(uint32 pTemp); + + uint8 _findSpellIDX(uint32 SpellID); + + BSWRecord* _getRecord(uint32 SpellID); + + void _loadFromDB(); + + void _resetTimer(uint8 m_uiSpellIdx); + + Unit* _doSelect(uint32 SpellID, bool spellsearchtype = false, float range = 100.0f, bool includeVictim = true); + + Unit* _doSummon(uint8 m_uiSpellIdx, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN, uint32 delay = 60000); + + Unit* _doSummonAtPosition(uint8 m_uiSpellIdx, float fPosX, float fPosY, float fPosZ); + + Unit* _doSummonAtPosition(uint32 guid, TempSummonType type, uint32 delay, float fPosX, float fPosY, float fPosZ); + + CanCastResult _BSWDoCast(uint8 m_uiSpellIdx, Unit* pTarget); + + CanCastResult _BSWDoForceCast(uint8 m_uiSpellIdx, Unit* pTarget); + + CanCastResult _BSWSpellSelector(uint8 m_uiSpellIdx, Unit* pTarget = NULL); + + CanCastResult _BSWCastOnTarget(Unit* pTarget, uint8 m_uiSpellIdx); + + bool _QuerySpellPeriod(uint8 m_uiSpellIdx, uint32 diff, bool ignorecast = false); + + CanCastResult _DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, ObjectGuid uiOriginalCasterGUID = ObjectGuid()); + + bool _doRemove(uint8 m_uiSpellIdx, Unit* pTarget = NULL, uint8 index = EFFECT_INDEX_ALL); + + bool _doRemove(uint32 SpellID, Unit* pTarget, uint8 index = EFFECT_INDEX_ALL); + + bool _doRemoveFromAll(uint8 m_uiSpellIdx); + + bool _doRemoveFromAll(uint32 SpellID); + + bool _doAura(uint8 m_uiSpellIdx, Unit* pTarget, SpellEffectIndex index, bool isStack = true); + + bool _doAura(uint32 SpellID, Unit* pTarget, SpellEffectIndex index, int32 basepoint = 0, bool isStack = true); + + bool _doAura(uint8 m_uiSpellIdx, Unit* pTarget); + + bool _doAura(uint32 SpellID, Unit* pTarget); + + bool _hasAura(uint8 m_uiSpellIdx, Unit* pTarget); + + bool _hasAura(uint32 SpellID, Unit* pTarget); + + uint8 _auraCount(uint8 m_uiSpellIdx, Unit* pTarget = NULL, SpellEffectIndex index = EFFECT_INDEX_0); + + uint8 _auraCount(uint32 SpellID, Unit* pTarget, SpellEffectIndex index); + + void _fillEmptyDataField(); + + uint32 _getSpellData(uint8 m_uiSpellIdx); + + bool _isDifficultyInMask(uint8 mask); + + uint8 _stage; + +}; + +#endif diff --git a/base/BSW_instance.cpp b/base/BSW_instance.cpp new file mode 100644 index 0000000000..2f962643aa --- /dev/null +++ b/base/BSW_instance.cpp @@ -0,0 +1,182 @@ +/* Copyright (C) 2009 - 2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#include "precompiled.h" +#include "BSW_instance.h" + +BSWScriptedInstance::BSWScriptedInstance(Map* pMap) : ScriptedInstance(pMap) +{ + debug_log("BSW: Initialized BSWScriptedInstance structure for map %u difficulty %u",pMap->GetId(),pMap->GetDifficulty()); + m_auiEvent = 0; + m_auiEventTimer = 0; + m_auiCreatureID = 0; + m_auiEventLock = false; + m_pMap = pMap; +}; + +BSWScriptedInstance::~BSWScriptedInstance() +{ + debug_log("BSW: Removing BSWScriptedInstance structure for map %u",m_pMap->GetId()); +}; + +void BSWScriptedInstance::DoCompleteAchievement(uint32 uiAchievmentId) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + if (!lPlayers.isEmpty()) + { + for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->CompletedAchievement(uiAchievmentId); + } + } + else + debug_log("BSW: DoCompleteAchievement attempt set data, but no players in map."); +} + +void BSWScriptedInstance::DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1 /*=0*/, uint32 miscvalue2 /*=0*/) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + if (!lPlayers.isEmpty()) + { + for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->UpdateAchievementCriteria(type, miscvalue1, miscvalue2); + } + } + else + debug_log("SD2: DoUpdateAchievementCriteria attempt set data but no players in map."); +} + +void BSWScriptedInstance::DoOpenDoor(ObjectGuid guid) +{ + if (guid.IsEmpty()) + return; + + GameObject* pGo = instance->GetGameObject(guid); + + if (pGo) + pGo->SetGoState(GO_STATE_ACTIVE); + else + debug_log("BSW: DoOpenDoor attempt set data to object %u, but no this object", guid.GetCounter()); +} + +void BSWScriptedInstance::DoCloseDoor(ObjectGuid guid) +{ + if (guid.IsEmpty()) + return; + + GameObject* pGo = instance->GetGameObject(guid); + + if (pGo) + pGo->SetGoState(GO_STATE_READY); + else + debug_log("BSW: DoCloseDoor attempt set data to object %u, but no this object", guid.GetCounter()); +} + +void BSWScriptedInstance::DoOpenDoor(uint32 entry) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(entry); + if (find != m_mGoEntryGuidStore.end()) + { + ObjectGuid guid = find->second; + DoOpenDoor(guid); + } + else + debug_log("BSW: Script call DoOpenDoor (by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", entry, instance->GetId()); +} + +void BSWScriptedInstance::DoCloseDoor(uint32 entry) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(entry); + if (find != m_mGoEntryGuidStore.end()) + { + ObjectGuid guid = find->second; + DoCloseDoor(guid); + } + else + debug_log("BSW: Script call DoCloseDoor (by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", entry, instance->GetId()); +} + +uint32 BSWScriptedInstance::GetEvent(uint32 creatureID) +{ + if (m_auiEventLock || m_auiCreatureID != creatureID) + { + return 0; + } + else + { + debug_log("BSW: GetEvent: send event %u to creature %u",m_auiEvent, creatureID); + m_auiEventLock = true; + return m_auiEvent; + } +} + +void BSWScriptedInstance::SetNextEvent(uint32 EventNum, uint32 creatureID, uint32 timer) +{ + m_auiEvent = EventNum; + m_auiCreatureID = creatureID; + m_auiEventTimer = timer; + m_auiEventLock = false; + debug_log("BSW: SetNextEvent: setted event %u to creature %u, timer %u",m_auiEvent, creatureID, timer); +} + +bool BSWScriptedInstance::GetEventTimer(uint32 creatureID, const uint32 diff) +{ + if (m_auiEvent == 0 || m_auiCreatureID != creatureID) + return false; + + if (m_auiEventTimer <= diff) + { + m_auiEventTimer = 0; + return true; + } + else + { + m_auiEventTimer -= diff; + return false; + } +} + +void BSWScriptedInstance::SetCriteriaState(uint32 criteria_id, bool state, Player* player) +{ + if (!criteria_id) + return; + + if (player && state) + m_personalCriteriaMap.insert(std::make_pair(criteria_id, player->GetObjectGuid())); + else + m_groupCriteriaMap.insert(std::make_pair(criteria_id, state)); + +} + +bool BSWScriptedInstance::GetCriteriaState(uint32 criteria_id, Player const* player) +{ + if (!criteria_id) + return false; + + std::map::const_iterator itr = m_groupCriteriaMap.find(criteria_id); + + if (itr != m_groupCriteriaMap.end()) + if (itr->second) + return true; + + if (player) + { + std::pair::const_iterator, std::multimap::const_iterator> bounds = + m_personalCriteriaMap.equal_range(criteria_id); + + for(std::multimap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + { + if (itr->second == player->GetObjectGuid()) + return true; + } + + } + + return false; +} diff --git a/base/BSW_instance.h b/base/BSW_instance.h new file mode 100644 index 0000000000..5b5056f4b0 --- /dev/null +++ b/base/BSW_instance.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2009 - 2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef BSW_INSTANCE_H +#define BSW_INSTANCE_H +#define BSW_INSTANCE_VERSION 0.6.20 +#include "sc_instance.h" + +class MANGOS_DLL_DECL BSWScriptedInstance : public ScriptedInstance +{ + public: + + BSWScriptedInstance(Map* pMap); + virtual ~BSWScriptedInstance(); + + //sends completed achievments to all players in instance + void DoCompleteAchievement(uint32 uiAchievmentId); + //sends achievment criteria update to all players in instance + void DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1 = 0, uint32 miscvalue2 = 0); + + void DoOpenDoor(ObjectGuid guid); + void DoCloseDoor(ObjectGuid guid); + + void DoOpenDoor(uint32 entry); + void DoCloseDoor(uint32 entry); + + void SetCriteriaState(uint32 criteria_id, bool state = true, Player* player = NULL); + bool GetCriteriaState(uint32 criteria_id, Player const* player = NULL); + + void SetNextEvent(uint32 EventNum, uint32 creatureID, uint32 timer = 1000); + uint32 GetEvent(uint32 creatureID); + bool GetEventTimer(uint32 creatureID, const uint32 diff); + + private: + uint32 m_auiEvent; + uint32 m_auiCreatureID; + uint32 m_auiEventTimer; + bool m_auiEventLock; + Map* m_pMap; + + std::map m_groupCriteriaMap; + std::multimap m_personalCriteriaMap; + +}; +#endif diff --git a/base/escort_ai.cpp b/base/escort_ai.cpp index bfce9385e9..d8d35eb42b 100644 --- a/base/escort_ai.cpp +++ b/base/escort_ai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -11,6 +11,7 @@ EndScriptData */ #include "precompiled.h" #include "escort_ai.h" +#include "../system/system.h" const float MAX_PLAYER_DISTANCE = 66.0f; @@ -21,16 +22,37 @@ enum }; npc_escortAI::npc_escortAI(Creature* pCreature) : ScriptedAI(pCreature), - m_uiPlayerGUID(0), - m_uiPlayerCheckTimer(1000), + m_playerGuid(), m_uiWPWaitTimer(2500), + m_uiPlayerCheckTimer(1000), m_uiEscortState(STATE_ESCORT_NONE), - m_bIsRunning(false), m_pQuestForEscort(NULL), + m_bIsRunning(false), m_bCanInstantRespawn(false), m_bCanReturnToStart(false) {} +void npc_escortAI::GetAIInformation(ChatHandler& reader) +{ + std::ostringstream oss; + + oss << "EscortAI "; + if (m_playerGuid) + oss << "started for " << m_playerGuid.GetString() << " "; + if (m_pQuestForEscort) + oss << "started with quest " << m_pQuestForEscort->GetQuestId(); + + 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; + } + + reader.PSendSysMessage(oss.str().c_str()); +} + bool npc_escortAI::IsVisible(Unit* pWho) const { if (!pWho) @@ -60,24 +82,25 @@ void npc_escortAI::AttackStart(Unit* 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) -{ -} +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) @@ -146,16 +169,16 @@ void npc_escortAI::MoveInLineOfSight(Unit* pWho) } } -void npc_escortAI::JustDied(Unit* pKiller) +void npc_escortAI::JustDied(Unit* /*pKiller*/) { - if (!HasEscortState(STATE_ESCORT_ESCORTING) || !m_uiPlayerGUID || !m_pQuestForEscort) + if (!HasEscortState(STATE_ESCORT_ESCORTING) || !m_playerGuid || !m_pQuestForEscort) return; if (Player* pPlayer = GetPlayerForEscort()) { 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()) { @@ -179,28 +202,26 @@ void npc_escortAI::JustRespawned() if (!IsCombatMovement()) SetCombatMovement(true); - //add a small delay before going to first waypoint, normal in near all cases + // 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->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->SetLootRecipient(NULL); if (HasEscortState(STATE_ESCORT_ESCORTING)) { - debug_log("SD2: EscortAI has left combat and is now returning to CombatStartPosition."); - - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) + // 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; @@ -209,10 +230,7 @@ void npc_escortAI::EnterEvadeMode() } } else - { - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MoveTargetedHome(); - } + m_creature->GetMotionMaster()->MoveTargetedHome(); Reset(); } @@ -223,15 +241,11 @@ bool npc_escortAI::IsPlayerOrGroupInRange() { 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(); - if (pMember && m_creature->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE)) - { return true; - break; - } } } else @@ -243,58 +257,68 @@ bool npc_escortAI::IsPlayerOrGroupInRange() return false; } -void npc_escortAI::UpdateAI(const uint32 uiDiff) +// Returns false, if npc is despawned +bool npc_escortAI::MoveToNextWaypoint() { - //Waypoint Updating - if (HasEscortState(STATE_ESCORT_ESCORTING) && !m_creature->getVictim() && m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_RETURNING)) + // 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()) { - if (m_uiWPWaitTimer <= uiDiff) + debug_log("SD2: EscortAI reached end of waypoints"); + + if (m_bCanReturnToStart) { - //End of the line - if (CurrentWP == WaypointList.end()) - { - debug_log("SD2: EscortAI reached end of waypoints"); + float fRetX, fRetY, fRetZ; + m_creature->GetRespawnCoord(fRetX, fRetY, fRetZ); - if (m_bCanReturnToStart) - { - float fRetX, fRetY, fRetZ; - m_creature->GetRespawnCoord(fRetX, fRetY, fRetZ); + m_creature->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ); - m_creature->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ); + m_uiWPWaitTimer = 0; - m_uiWPWaitTimer = 0; + debug_log("SD2: EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ); + return true; + } - debug_log("SD2: EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ); - return; - } + if (m_bCanInstantRespawn) + { + m_creature->SetDeathState(JUST_DIED); + m_creature->Respawn(); + } + else + m_creature->ForcedDespawn(); - if (m_bCanInstantRespawn) - { - m_creature->SetDeathState(JUST_DIED); - m_creature->Respawn(); - } - else - m_creature->ForcedDespawn(); + return false; + } - return; - } + 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); - if (!HasEscortState(STATE_ESCORT_PAUSED)) - { - 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); - WaypointStart(CurrentWP->uiId); + m_uiWPWaitTimer = 0; - 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_uiPlayerGUID && !m_creature->getVictim() && !HasEscortState(STATE_ESCORT_RETURNING)) + // 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)) { if (m_uiPlayerCheckTimer < uiDiff) { @@ -322,9 +346,9 @@ 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 + // Check if we have a current target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -336,46 +360,51 @@ void npc_escortAI::MovementInform(uint32 uiMoveType, uint32 uiPointId) if (uiMoveType != POINT_MOTION_TYPE || !HasEscortState(STATE_ESCORT_ESCORTING)) return; - //Combat start position reached, continue waypoint movement + // Combat start position reached, continue waypoint movement if (uiPointId == POINT_LAST_POINT) { debug_log("SD2: EscortAI has returned to original position before combat"); - if (m_bIsRunning && m_creature->HasSplineFlag(SPLINEFLAG_WALKMODE)) - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - else if (!m_bIsRunning && !m_creature->HasSplineFlag(SPLINEFLAG_WALKMODE)) - m_creature->AddSplineFlag(SPLINEFLAG_WALKMODE); - + m_creature->SetWalk(!m_bIsRunning); RemoveEscortState(STATE_ESCORT_RETURNING); - - if (!m_uiWPWaitTimer) - m_uiWPWaitTimer = 1; } else if (uiPointId == POINT_HOME) { debug_log("SD2: EscortAI has returned to original home location and will continue from beginning of waypoint list."); CurrentWP = WaypointList.begin(); - m_uiWPWaitTimer = 1; + m_uiWPWaitTimer = 0; } else { - //Make sure that we are still on the right waypoint + // Make sure that we are still on the right waypoint if (CurrentWP->uiId != uiPointId) { - error_log("SD2: EscortAI reached waypoint out of order %u, expected %u.", uiPointId, CurrentWP->uiId); + script_error_log("EscortAI for Npc %u reached waypoint out of order %u, expected %u.", m_creature->GetEntry(), uiPointId, CurrentWP->uiId); return; } debug_log("SD2: EscortAI waypoint %u reached.", CurrentWP->uiId); - //Call WP function + // 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 + 1; + 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) @@ -387,7 +416,7 @@ void npc_escortAI::MovementInform(uint32 uiMoveType, uint32 uiPointId) void npc_escortAI::FillPointMovementListForCreature() { - std::vector const &pPointsEntries = pSystemMgr.GetPointMoveList(m_creature->GetEntry()); + std::vector const& pPointsEntries = pSystemMgr.GetPointMoveList(m_creature->GetEntry()); if (pPointsEntries.empty()) return; @@ -403,23 +432,27 @@ void npc_escortAI::FillPointMovementListForCreature() void npc_escortAI::SetCurrentWaypoint(uint32 uiPointId) { - if (!(HasEscortState(STATE_ESCORT_PAUSED))) // only when paused - return; - - if (uiPointId >= WaypointList.size()) // too high number + if (!(HasEscortState(STATE_ESCORT_PAUSED))) // Only when paused return; - if (uiPointId == CurrentWP->uiId) // already here + if (uiPointId == CurrentWP->uiId) // Already here return; - CurrentWP = WaypointList.begin(); // set to begin (can't -- backwards in itr list) - - while(uiPointId != CurrentWP->uiId) + bool bFoundWaypoint = false; + for (std::list::iterator itr = WaypointList.begin(); itr != WaypointList.end(); ++itr) { - ++CurrentWP; - - if (CurrentWP == WaypointList.end()) + if (itr->uiId == uiPointId) + { + CurrentWP = itr; // Set to found itr + bFoundWaypoint = true; break; + } + } + + if (!bFoundWaypoint) + { + debug_log("SD2: EscortAI current waypoint tried to set to id %u, but doesn't exist in WaypointList", uiPointId); + return; } m_uiWPWaitTimer = 1; @@ -432,32 +465,32 @@ void npc_escortAI::SetRun(bool bRun) if (bRun) { if (!m_bIsRunning) - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + m_creature->SetWalk(false); else debug_log("SD2: EscortAI attempt to set run mode, but is already running."); } else { if (m_bIsRunning) - m_creature->AddSplineFlag(SPLINEFLAG_WALKMODE); + m_creature->SetWalk(true); else debug_log("SD2: EscortAI attempt to set walk mode, but is already walking."); } m_bIsRunning = bRun; } -//TODO: get rid of this many variables passed in function. -void npc_escortAI::Start(bool bRun, uint64 uiPlayerGUID, const Quest* pQuest, bool bInstantRespawn, bool bCanLoopPath) +// 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; } @@ -472,10 +505,10 @@ void npc_escortAI::Start(bool bRun, uint64 uiPlayerGUID, const Quest* pQuest, bo return; } - //set variables + // set variables m_bIsRunning = bRun; - m_uiPlayerGUID = uiPlayerGUID; + m_playerGuid = pPlayer ? pPlayer->GetObjectGuid() : ObjectGuid(); m_pQuestForEscort = pQuest; m_bCanInstantRespawn = bInstantRespawn; @@ -491,16 +524,15 @@ void npc_escortAI::Start(bool bRun, uint64 uiPlayerGUID, const Quest* pQuest, bo 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 = " UI64FMTD, WaypointList.size(), m_bIsRunning, m_uiPlayerGUID); + debug_log("SD2: EscortAI started with " SIZEFMTD " waypoints. Run = %d, PlayerGuid = %s", WaypointList.size(), m_bIsRunning, m_playerGuid.GetString().c_str()); CurrentWP = WaypointList.begin(); - //Set initial speed - if (m_bIsRunning) - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + // Set initial speed + m_creature->SetWalk(!m_bIsRunning); AddEscortState(STATE_ESCORT_ESCORTING); diff --git a/base/escort_ai.h b/base/escort_ai.h index 8094e3115f..93d1414710 100644 --- a/base/escort_ai.h +++ b/base/escort_ai.h @@ -1,11 +1,12 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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 -#include "../system/system.h" +// Remove this include, when EscortAI stores uint32 quest-id instead of Quest* +#include "ObjectMgr.h" struct Escort_Waypoint { @@ -24,12 +25,12 @@ struct Escort_Waypoint uint32 uiWaitTime; }; -enum eEscortState +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 @@ -38,37 +39,39 @@ struct MANGOS_DLL_DECL npc_escortAI : public ScriptedAI explicit npc_escortAI(Creature* pCreature); ~npc_escortAI() {} - virtual void Aggro(Unit*); + void GetAIInformation(ChatHandler& reader) override; - virtual void Reset() = 0; + virtual void Aggro(Unit*) override; + + virtual void Reset() override = 0; // CreatureAI functions - bool IsVisible(Unit*) const; + bool IsVisible(Unit*) const override; - void AttackStart(Unit*); + void AttackStart(Unit*) override; - void EnterCombat(Unit*); + void EnterCombat(Unit*) override; - void MoveInLineOfSight(Unit*); + void MoveInLineOfSight(Unit*) override; - void JustDied(Unit*); + void JustDied(Unit*) override; - void JustRespawned(); + void JustRespawned() override; - void EnterEvadeMode(); + void EnterEvadeMode() override; - 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 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 MovementInform(uint32, uint32); + void MovementInform(uint32, uint32) override; // EscortAI functions - //void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs = 0); + // void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs = 0); virtual void WaypointReached(uint32 uiPointId) = 0; - virtual void WaypointStart(uint32 uiPointId) {} + virtual void WaypointStart(uint32 /*uiPointId*/) {} - void Start(bool bRun = false, uint64 uiPlayerGUID = 0, const Quest* pQuest = NULL, bool bInstantRespawn = false, bool bCanLoopPath = false); + void Start(bool bRun = false, const Player* pPlayer = NULL, const Quest* pQuest = NULL, bool bInstantRespawn = false, bool bCanLoopPath = false); void SetRun(bool bRun = true); void SetEscortPaused(bool uPaused); @@ -79,29 +82,30 @@ struct MANGOS_DLL_DECL npc_escortAI : public ScriptedAI void SetCurrentWaypoint(uint32 uiPointId); protected: - Player* GetPlayerForEscort() { return m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); } + Player* GetPlayerForEscort() { return m_creature->GetMap()->GetPlayer(m_playerGuid); } 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; } - uint64 m_uiPlayerGUID; + 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 754688198e..6346033659 100644 --- a/base/follower_ai.cpp +++ b/base/follower_ai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -20,10 +20,10 @@ enum }; FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature), - m_uiLeaderGUID(0), - m_pQuestForFollow(NULL), + m_leaderGuid(), m_uiUpdateFollowTimer(2500), - m_uiFollowState(STATE_FOLLOW_NONE) + m_uiFollowState(STATE_FOLLOW_NONE), + m_pQuestForFollow(NULL) {} void FollowerAI::AttackStart(Unit* pWho) @@ -42,15 +42,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 +119,17 @@ void FollowerAI::MoveInLineOfSight(Unit* pWho) } } -void FollowerAI::JustDied(Unit* pKiller) +void FollowerAI::JustDied(Unit* /*pKiller*/) { - if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || !m_uiLeaderGUID || !m_pQuestForFollow) + 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 +153,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 +211,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 +245,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 +280,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 - m_uiLeaderGUID = pLeader->GetGUID(); + // set variables + m_leaderGuid = pLeader->GetObjectGuid(); if (uiFactionForFollower) - m_creature->setFaction(uiFactionForFollower); + m_creature->SetFactionTemporary(uiFactionForFollower, TEMPFACTION_RESTORE_RESPAWN); m_pQuestForFollow = pQuest; @@ -308,12 +305,12 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - debug_log("SD2: FollowerAI start follow %s (GUID " UI64FMTD ")", pLeader->GetName(), m_uiLeaderGUID); + debug_log("SD2: FollowerAI start follow %s (Guid %s)", pLeader->GetName(), m_leaderGuid.GetString().c_str()); } Player* FollowerAI::GetLeaderForFollower() { - if (Player* pLeader = m_creature->GetMap()->GetPlayer(m_uiLeaderGUID)) + if (Player* pLeader = m_creature->GetMap()->GetPlayer(m_leaderGuid)) { if (pLeader->isAlive()) return pLeader; @@ -321,16 +318,15 @@ 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(); if (pMember && pMember->isAlive() && m_creature->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE)) { debug_log("SD2: FollowerAI GetLeader changed and returned new leader."); - m_uiLeaderGUID = pMember->GetGUID(); + m_leaderGuid = pMember->GetObjectGuid(); return pMember; - break; } } } diff --git a/base/follower_ai.h b/base/follower_ai.h index 8cc70f42d0..ef864c8112 100644 --- a/base/follower_ai.h +++ b/base/follower_ai.h @@ -1,21 +1,19 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef SC_FOLLOWERAI_H #define SC_FOLLOWERAI_H -#include "../system/system.h" - -enum eFollowState +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 @@ -24,26 +22,26 @@ class MANGOS_DLL_DECL FollowerAI : public ScriptedAI explicit FollowerAI(Creature* pCreature); ~FollowerAI() {} - //virtual void WaypointReached(uint32 uiPointId) = 0; + // virtual void WaypointReached(uint32 uiPointId) = 0 override; - 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); } @@ -57,11 +55,11 @@ class MANGOS_DLL_DECL FollowerAI : public ScriptedAI bool AssistPlayerInCombat(Unit* pWho); - uint64 m_uiLeaderGUID; + ObjectGuid m_leaderGuid; 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 5554d54b20..3cc6b099b7 100644 --- a/base/guard_ai.cpp +++ b/base/guard_ai.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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 +29,24 @@ EndScriptData */ guardAI::guardAI(Creature* pCreature) : ScriptedAI(pCreature), m_uiGlobalCooldown(0), + m_uiZoneAttackMsgTimer(0), + m_uiHelp(0), m_uiBuffTimer(0) {} void guardAI::Reset() { m_uiGlobalCooldown = 0; - m_uiBuffTimer = 0; //Rebuff as soon as we can + m_uiBuffTimer = 0; // Rebuff as soon as we can + m_uiZoneAttackMsgTimer = 0; + m_uiHelp = 5000; } -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 +54,91 @@ void guardAI::Aggro(Unit *pWho) } } - if (const SpellEntry *pSpellInfo = m_creature->ReachWithSpellAttack(pWho)) + if (const SpellEntry* pSpellInfo = m_creature->ReachWithSpellAttack(pWho)) DoCastSpell(pWho, pSpellInfo); + +///-> Send Zone Under Attack message to the LocalDefense and WorldDefense Channels + if (pWho->GetTypeId() == TYPEID_PLAYER && !m_uiZoneAttackMsgTimer) + { + m_creature->SendZoneUnderAttackMessage((Player*)pWho); + m_uiZoneAttackMsgTimer = 30000; + } } -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::SummonGuardsHelpers() +{ + int entry = 0; + float x,y,z,X,Y,Z; + // Creature* pHelper; + m_creature->GetPosition(x,y,z); + m_creature->getVictim()->GetPosition(X,Y,Z); + if (x > X) + X = x + urand(20, 30); + else + X = x - urand(20, 30); + if (y > Y) + Y = y + urand(20, 30); + else + Y = y - urand(20, 30); + m_creature->GetRespawnCoord(x,y,z); + if (m_creature->getFaction() == F_ORGRIMMAR) + entry = NPC_ORGRIMMAR_GRUNT; + if (m_creature->getFaction() == F_DARNASSUS) + entry = NPC_DARNASSUS_SENTINEL; + if (m_creature->getFaction() == F_STORMWIND) + entry = NPC_STORMWIND_GUARD; + if (m_creature->getFaction() == F_UNDERCITY) + entry = NPC_UNDERCITY_GUARD; + if (m_creature->getFaction() == F_IRONFORGE) + entry = NPC_IRONFORGE_GUARD; + if (m_creature->getFaction() == F_THUNDER_BLUFF) + entry = NPC_BLUFF_WATCHERS; + if (m_creature->getFaction() == F_EXODAR) + entry = NPC_EXODAR_PEACEKEEPER; + if (m_creature->getFaction() == F_SILVERMOON) + entry = NPC_SILVERMOON_CITYGUARD; + DoSpawnCreature(entry, (float) (X - x), (float) (Y - y), (float) (Z - z), 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); +} + 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 + // Always decrease ZoneAttackMsgTimer + if (m_uiZoneAttackMsgTimer > uiDiff) + m_uiZoneAttackMsgTimer -= uiDiff; + else m_uiZoneAttackMsgTimer = 0; + + // 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 +146,70 @@ 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; + // Always decrease Help when in combat + if (m_uiHelp > uiDiff) + m_uiHelp -= uiDiff; + else m_uiHelp = 0; + + if (!m_uiHelp && m_creature->GetEntry()) + { + if (m_creature->getFaction() == F_ORGRIMMAR) + m_creature->MonsterSay("Orgrimmar is under Invasion! Guards!! Help me!", LANG_ORCISH); + if (m_creature->getFaction() == F_DARNASSUS) + m_creature->MonsterSay("Darnassus is under Invasion! Guards!! Help me!", LANG_DARNASSIAN); + if (m_creature->getFaction() == F_STORMWIND) + m_creature->MonsterSay("Stormwind is under Invasion! Guards!! Help me!", LANG_COMMON); + if (m_creature->getFaction() == F_UNDERCITY) + m_creature->MonsterSay("Undercity is under Invasion! Guards!! Help me!", LANG_GUTTERSPEAK); + if( m_creature->getFaction() == F_IRONFORGE) + m_creature->MonsterSay("Ironforge is under Invasion! Guards!! Help me!", LANG_DWARVISH); + if (m_creature->getFaction() == F_THUNDER_BLUFF) + m_creature->MonsterSay("Thunder Bluff is under Invasion! Guards!! Help me!", LANG_TAURAHE); + if (m_creature->getFaction() == F_EXODAR) + m_creature->MonsterSay("The Exodar is under Invasion! Guards!! Help me!", LANG_DRAENEI); + if (m_creature->getFaction() == F_SILVERMOON) + m_creature->MonsterSay("Silvermoon is under Invasion! Guards!! Help me!", LANG_THALASSIAN); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_BATTLEROAR); +// for (int i = 0; i < 3;i++) +// { +// SummonGuardsHelpers(); +// } + m_uiHelp = urand(60000, 105000); + } + // 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 (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + // 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 +220,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 +268,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; @@ -197,6 +279,12 @@ void guardAI::DoReplyToTextEmote(uint32 uiTextEmote) } } +void guardAI_thunderbluff::ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) +{ + if (pPlayer->GetTeam() == HORDE) + DoReplyToTextEmote(uiTextEmote); +} + void guardAI_orgrimmar::ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) { if (pPlayer->GetTeam() == HORDE) diff --git a/base/guard_ai.h b/base/guard_ai.h index 832bd24622..b83037831a 100644 --- a/base/guard_ai.h +++ b/base/guard_ai.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -24,40 +25,72 @@ enum eShattrathGuard SPELL_EXILE = 39533 }; +enum SummonUnderAttackGuards +{ +///-> values match faction values used by YTDB + NPC_BLUFF_WATCHERS = 3084, ///-> Faction 105 + NPC_ORGRIMMAR_GRUNT = 3296, ///-> Faction 85 + NPC_DARNASSUS_SENTINEL = 4262, ///-> Faction 79 + NPC_STORMWIND_GUARD = 68, ///-> Faction 11 + NPC_UNDERCITY_GUARD = 5624, ///-> Faction 68 + NPC_IRONFORGE_GUARD = 5595, ///-> Faction 55 + NPC_EXODAR_PEACEKEEPER = 16733, ///-> Faction 1638 + NPC_SILVERMOON_CITYGUARD = 16222, ///-> Faction 1745 +///-> Faction list for guard + F_THUNDER_BLUFF = 105, + F_ORGRIMMAR = 85, + F_DARNASSUS = 79, + F_STORMWIND = 11, + F_UNDERCITY = 68, + F_IRONFORGE = 55, + F_EXODAR = 1638, + F_SILVERMOON = 1745, +}; + struct MANGOS_DLL_DECL guardAI : public ScriptedAI { public: explicit guardAI(Creature* pCreature); ~guardAI() {} - 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 + 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 + uint32 m_uiZoneAttackMsgTimer; ///-> This keeps track of zone under attack message + uint32 m_uiHelp; ///-> help timer that aggroed guards + + void Reset() override; - void Reset(); + void Aggro(Unit* pWho) override; - void Aggro(Unit *pWho); + void JustDied(Unit* /*pKiller*/) override; - void JustDied(Unit *pKiller); + void SummonGuardsHelpers(); - void UpdateAI(const uint32 uiDiff); + void UpdateAI(const uint32 uiDiff) override; - //common used for guards in main cities - void DoReplyToTextEmote(uint32 uiTextEmote); + // Commonly used for guards in main cities + void DoReplyToTextEmote(uint32 uiTextEmote); +}; + +struct MANGOS_DLL_DECL guardAI_thunderbluff : public guardAI +{ + guardAI_thunderbluff(Creature* pCreature) : guardAI(pCreature) {} + void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) override; }; struct MANGOS_DLL_DECL 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 { 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 new file mode 100644 index 0000000000..1f10497950 --- /dev/null +++ b/base/pet_ai.cpp @@ -0,0 +1,132 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +/* ScriptData +SDName: ScriptedPetAI +SD%Complete: 50 +SDComment: Intended to be used with Guardian/Protector/Minipets. Little/no control over when pet enter/leave combat. Must be considered to be under development. +SDCategory: Npc +EndScriptData */ + +#include "precompiled.h" +#include "pet_ai.h" + +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); +} + +void ScriptedPetAI::MoveInLineOfSight(Unit* pWho) +{ + if (m_creature->getVictim()) + return; + + if (!m_creature->GetCharmInfo() || !m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE)) + return; + + if (m_creature->CanInitiateAttack() && pWho->isTargetableForAttack() && + m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) + { + if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) + return; + + if (m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho)) + { + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + AttackStart(pWho); + } + } +} + +void ScriptedPetAI::AttackStart(Unit* pWho) +{ + if (pWho && m_creature->Attack(pWho, true)) + m_creature->GetMotionMaster()->MoveChase(pWho); +} + +void ScriptedPetAI::AttackedBy(Unit* pAttacker) +{ + if (m_creature->getVictim()) + return; + + if (m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) && + m_creature->CanReachWithMeleeAttack(pAttacker)) + AttackStart(pAttacker); +} + +void ScriptedPetAI::ResetPetCombat() +{ + Unit* pOwner = m_creature->GetCharmerOrOwner(); + + if (pOwner && m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) + { + m_creature->GetMotionMaster()->MoveFollow(pOwner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + } + else + { + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + } + + m_creature->AttackStop(); + + debug_log("SD2: ScriptedPetAI reset pet combat and stop attack."); + Reset(); +} + +void ScriptedPetAI::UpdatePetAI(const uint32 /*uiDiff*/) +{ + DoMeleeAttackIfReady(); +} + +void ScriptedPetAI::UpdateAI(const uint32 uiDiff) +{ + if (!m_creature->isAlive()) // should not be needed, isAlive is checked in mangos before calling UpdateAI + return; + + // UpdateAllies() is done in the generic PetAI in Mangos, but we can't do this from script side. + // Unclear what side effects this has, but is something to be resolved from Mangos. + + if (m_creature->getVictim()) // in combat + { + if (!m_creature->getVictim()->isTargetableForAttack()) + { + // target no longer valid for pet, so either attack stops or new target are selected + // doesn't normally reach this, because of how petAi is designed in Mangos. CombatStop + // are called before this update diff, and then pet will already have no victim. + ResetPetCombat(); + return; + } + + // update when in combat + UpdatePetAI(uiDiff); + } + else if (m_creature->GetCharmInfo()) + { + Unit* pOwner = m_creature->GetCharmerOrOwner(); + + if (!pOwner) + return; + + if (pOwner->isInCombat() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE)) + { + // Not correct in all cases. + // When mob initiate attack by spell, pet should not start attack before spell landed. + AttackStart(pOwner->getAttackerForHelper()); + } + else if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) + { + // not following, so start follow + if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW)) + m_creature->GetMotionMaster()->MoveFollow(pOwner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + + // update when not in combat + UpdatePetOOCAI(uiDiff); + } + } +} diff --git a/base/pet_ai.h b/base/pet_ai.h new file mode 100644 index 0000000000..f36302e4a7 --- /dev/null +++ b/base/pet_ai.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_PET_H +#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 +{ + public: + explicit ScriptedPetAI(Creature* pCreature); + ~ScriptedPetAI() {} + + void MoveInLineOfSight(Unit* /*pWho*/) override; + + void AttackStart(Unit* /*pWho*/) override; + + void AttackedBy(Unit* /*pAttacker*/) override; + + bool IsVisible(Unit* /*pWho*/) const override; + + void KilledUnit(Unit* /*pVictim*/) override {} + + void OwnerKilledUnit(Unit* /*pVictim*/) override {} + + void UpdateAI(const uint32 uiDiff) override; + + virtual void Reset() {} + + virtual void UpdatePetAI(const uint32 uiDiff); // while in combat + + virtual void UpdatePetOOCAI(const uint32 /*uiDiff*/) {} // when not in combat + + protected: + void ResetPetCombat(); +}; + +#endif diff --git a/config.h b/config.h index 16050750a1..0c76c6f1a5 100644 --- a/config.h +++ b/config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2009 MaNGOS + * Copyright (C) 2005-2012 MaNGOS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,12 +19,20 @@ #ifndef SC_CONFIG_H #define SC_CONFIG_H +#include "../../../config.h" #include "Platform/CompilerDefs.h" #include "revision.h" +#include "sd2_revision_nr.h" +#include "sd2_revision_R2.h" // 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 + +// The path to config files +#ifndef SYSCONFDIR +# define SYSCONFDIR "" +#endif #ifdef WIN32 #define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport) @@ -34,8 +42,8 @@ #define MANGOS_DLL_EXPORT extern "C" export #endif -#ifndef _VERSION - #define _VERSION "Revision [" REVISION_ID "] " REVISION_DATE " " REVISION_TIME +#ifndef SD2_VERSION + #define SD2_VERSION "Revision [" SD2_REVISION_NR "] Revision R2 [" SD2_REVISION_R2 "] (" REVISION_ID ") " REVISION_DATE " " REVISION_TIME #endif // The path to config files @@ -45,14 +53,61 @@ #if PLATFORM == PLATFORM_WINDOWS #ifdef _WIN64 - #define _FULLVERSION _VERSION " (Win64)" + #define SD2_FULLVERSION SD2_VERSION " (Win64)" #else - #define _FULLVERSION _VERSION " (Win32)" + #define SD2_FULLVERSION SD2_VERSION " (Win32)" #endif - #define _SCRIPTDEV2_CONFIG "scriptdev2.conf" + #define _SCRIPTDEV2_CONFIG SYSCONFDIR"scriptdev2.conf" #else - #define _FULLVERSION _VERSION " (Unix)" + #define SD2_FULLVERSION SD2_VERSION " (Unix)" #define _SCRIPTDEV2_CONFIG SYSCONFDIR"scriptdev2.conf" #endif +#if CLIENT_VERSION >= 16057 + #define MAX_EXPANSION 4 + #define SD2_WORLD_MOP 1 + #undef SD2_WORLD_CATA + #undef SD2_WORLD_WOTLK + #undef SD2_WORLD_TBC + #undef SD2_WORLD_CLASSIC +#elif CLIENT_VERSION >= 13623 + #define MAX_EXPANSION 3 + #undef SD2_WORLD_MOP + #define SD2_WORLD_CATA 1 + #undef SD2_WORLD_WOTLK + #undef SD2_WORLD_TBC + #undef SD2_WORLD_CLASSIC +#elif CLIENT_VERSION > 8606 + #define MAX_EXPANSION 2 + #undef SD2_WORLD_MOP + #undef SD2_WORLD_CATA + #define SD2_WORLD_WOTLK 1 + #undef SD2_WORLD_TBC + #undef SD2_WORLD_CLASSIC +#elif CLIENT_VERSION > 6005 + #define MAX_EXPANSION 1 + #undef SD2_WORLD_MOP + #undef SD2_WORLD_CATA + #undef SD2_WORLD_WOTLK + #define SD2_WORLD_TBC 1 + #undef SD2_WORLD_CLASSIC +#else + #define MAX_EXPANSION 0 + #define SD2_WORLD_MOP 1 + #undef SD2_WORLD_CATA + #undef SD2_WORLD_WOTLK + #undef SD2_WORLD_TBC + #define SD2_WORLD_CLASSIC 1 +#endif + +#if (COMPILER == COMPILER_MICROSOFT) +# define LOCATION StaticLocation +# define EVENTLOCATION EventLocations +# define SPAWNLOCATION SpawnLocation +#else +# define LOCATION Location +# define EVENTLOCATION EventLocations +# define SPAWNLOCATION SpawnLocation +#endif + #endif diff --git a/config.h.in b/config.h.in deleted file mode 100644 index bb3caf880a..0000000000 --- a/config.h.in +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SC_CONFIG_H -#define SC_CONFIG_H - -#include "Platform/CompilerDefs.h" -#include "revision.h" - -// Format is YYYYMMDDRR where RR is the change in the conf file -// for that day. -#define SD2_CONF_VERSION 2009040501 - -#ifdef WIN32 - #define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport) -#elif defined( __GNUC__ ) - #define MANGOS_DLL_EXPORT extern "C" -#else - #define MANGOS_DLL_EXPORT extern "C" export -#endif - -#ifndef _VERSION - #define _VERSION "Revision [" REVISION_ID "] " REVISION_DATE " " REVISION_TIME -#endif - -// The path to config files -#ifndef 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" -#else - #define _FULLVERSION _VERSION " (Unix)" - #define _SCRIPTDEV2_CONFIG SYSCONFDIR"scriptdev2.conf" -#endif - -#endif diff --git a/docs/ChangeLog.html b/docs/ChangeLog.html new file mode 100644 index 0000000000..41907f49e5 --- /dev/null +++ b/docs/ChangeLog.html @@ -0,0 +1,937 @@ + + + + + +ScriptDev2 Milestones + + + + + +
+
+
+ +

Supports:

+
+
+
+
+

1. Milestone ScriptDev2 - 0.6

+
+
+

1.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 +

    +
  • +
+
+
+

1.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 +

    +
  • +
+
+
+

1.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 +

    +
  • +
+
+
+

1.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 +

    +
  • +
+
+

1.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 0000000000..61c8b02a11 --- /dev/null +++ b/docs/ChangeLog.txt @@ -0,0 +1,49 @@ += 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.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 0000000000..84a2de4ee6 --- /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 0000000000..6cf3167176 --- /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 0000000000..bbab3f6639 --- /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 0000000000..0078281d33 --- /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 0000000000..96c942eac5 --- /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 0000000000..a783c9bcc6 --- /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 7bf1847491..0000000000 --- a/docs/How to install.txt +++ /dev/null @@ -1,53 +0,0 @@ - ---- How to install ScriptDev2 --- - -1) Download MaNGOS (using git clone) - -2) Do the source stuff: - -MS Windows: -- Create a new folder under "src\bindings\" within the MaNGOS source called "ScriptDev2" -- Checkout the ScriptDev2 trunk from "https://scriptdev2.svn.sourceforge.net/svnroot/scriptdev2" -- Apply the Git patch to Mangos - "git am src/bindings/ScriptDev2/patches/MaNGOS-XXXX-ScriptDev2.patch" ('XXXX' is revision number for Mangos). (Note this is not required for compile, but needed to avoid deletion of untracked folders/files in GIT-directory when using certain GIT commands (example: git clean -f -d)) -- Compile MaNGOS -- Compile ScriptDev2 using the ScriptVC80 or ScriptVC90 Solution within the ScriptDev2 folder (this will overwrite the Mangoscript dll in the output directory) - -GNU/Linux: -- Checkout the ScriptDev2 to "src/bindings/ScriptDev2" - "svn co https://scriptdev2.svn.sourceforge.net/svnroot/scriptdev2 src/bindings/ScriptDev2" -SVN: -- Apply MaNGOS-XXXX-ScriptDev2.patch to Mangos, where XXXX is the highest version to that of your MaNGOS revision. -GIT: -- 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: - -MS Windows: -- All you have to do is open src\bindings\ and right click on the ScriptDev2 folder and click "Update" and then follow steps 4, 6, and 7 again. You must still compile MaNGOS before ScriptDev2 when on the Windows platform. - -GNU/Linux: -- Go to the src/bindings/ScriptDev2 directory - "cd src/bindings/ScriptDev2" -- Update ScriptDev2 - "svn up" - -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. - -You can view the ScriptDev2 Change Log at: -http://scriptdev2.svn.sourceforge.net/viewvc/scriptdev2/?view=log diff --git a/docs/How_to_install.html b/docs/How_to_install.html new file mode 100644 index 0000000000..1526b4eb60 --- /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:
+Apply the Git patch to Mangos - git am src/bindings/ScriptDev2/patches/MaNGOS-11167-ScriptDev2.patch
+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 0000000000..54adc380bd --- /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:* + +Apply the Git patch to Mangos - `git am src/bindings/ScriptDev2/patches/MaNGOS-11167-ScriptDev2.patch` + +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 0000000000..bc528524ce --- /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 0000000000..3e27507e50 --- /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 deleted file mode 100644 index a66cb35650..0000000000 --- a/docs/Script Layout.txt +++ /dev/null @@ -1,32 +0,0 @@ ---- Script Layout --- -A quick explanation of the layout I hope everyone will follow for scriptdev2. - ---- Sub Folders --- - -Area - Contains scripts used solely by area triggers - -Boss - Boss scripts for bosses that are not zone specific - -Mob - Generic Creature scripts for creatures that are not zone specific - -Custom - Intentionally empty folder from SVN. If you make a custom script please put it here. - -GO - Contains scripts used solely by Game Objects (GOs) that do not have a specific zone - -Guard - Scripts for Guard NPCs - -Honor - Honor npcs (currently a blank script as these npcs do nothing special) - -Item - Item scripts - -NPC - Scripts for individual NPCs who do not have a specific zone - -Servers - Generic NPC servers script for things such as flightmasters and guildmasters. - -Zone - ALL zone specific scripts should be written within these folders. This includes creature scripts, boss scripts, go scripts, area scripts, and npc scripts. - ---- Naming Conventions --- - -Please keep file names to "type_objectname.cpp" where type is replaced by the type of object and objectname is replaced by the name of the object, creature, item, or area that this script will be used by. - -AddSC functions should follow "void AddSC_creaturename(void);" format. Do not append AI or anything else. diff --git a/docs/Script_Layout.txt b/docs/Script_Layout.txt new file mode 100644 index 0000000000..53cfadd63d --- /dev/null +++ b/docs/Script_Layout.txt @@ -0,0 +1,22 @@ +--- Script Layout --- +A quick explanation of the layout I hope everyone will follow for scriptdev2. + +--- Sub Folders --- + +battlegrounds - Contains scripts for npcs in Battlegrounds + +custom - Intentionally empty folder from SVN. If you make a custom script please put it here. + +examples - Contains a couple of example scripts showing the most commonly used functions within SD2 + +eastern_kingdoms, kalimdor, northrend, outland - Contain scripts for anything related to npcs or instances on the corresponding continent. +Instances are grouped to subfolders, the normal continent-maps are divided into zones + +world - Contains scripts for anything that is not related to a specified zone. +This includes item_scripts, areatrigger_scripts, some npcs that can be found at many places, go_scripts and spell_scripts + +--- Naming Conventions --- + +Please keep file names to "type_objectname.cpp" where type is replaced by the type of object and objectname is replaced by the name of the object, creature, item, or area that this script will be used by. + +AddSC functions should follow "void AddSC_filename(void);" format. Do not append AI or anything else. diff --git a/docs/Text-tables.txt b/docs/Text-tables.txt index 11c4197206..75188ecbfd 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.txt b/docs/ToDo.txt index 5df315da03..bae8bc7c35 100644 --- a/docs/ToDo.txt +++ b/docs/ToDo.txt @@ -1,14 +1,27 @@ ---- 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 == +* Implement missing scripts for the Death Knigh area quests +* Implement script for Ruby Sanctum +* Finish script for Ulduar, Trial of the Crusader, Icecrown Citadel, Eye of Eternity and Obsidian Sanctum +* Implement dungeon scripts for Halls of Reflection, Trial of the Champion, Pit of Saron and Culling of Stratholme (requires core proper waipoint movement support) +* Finish dungeon scripts for Utgarde Pinnacle, Ahn'kahet and Azjol Nerub +* Implement Year event bosses - Ahune, Headless Horseman +* Implement various missing quest scripts ---- Core Problems --- +== TBC content == +* Various quests which still require script (examples: 5821, 5943, 9729, 9879, 9446, 10310, 10512, 10584, 11085, 10985) +* Karazhan - Missing scripts: Chess event +* Hyjal Summit - Optimize game event. +* Black Temple - Teron Gorefiend script improvement (requires core proper mind control support) +* Sunwell Plateau - Felmyst - phase II script missing -- 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: 660, 667, 1222, 1270, 3367, 5721) +* Zul'farrak (requires core proper waipoint movement support). +* Blackwing Lair - Razorgore (requires core proper mind control support). +* Ruins of AQ - Add missing script parts for Buru and Ossirian +* Temple of AQ - Add missing script part for Viscidus diff --git a/docs/aaa_Overview.html b/docs/aaa_Overview.html new file mode 100644 index 0000000000..c8f68e4005 --- /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 0000000000..a9c6180629 --- /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 b4ce73fb1e..9589d835c9 100644 --- a/include/precompiled.cpp +++ b/include/precompiled.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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 7bf0d38ae2..a9dda53baa 100644 --- a/include/precompiled.h +++ b/include/precompiled.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -6,17 +6,27 @@ #define SC_PRECOMPILED_H #include "../ScriptMgr.h" +#include "../config.h" +#include "Object.h" +#include "Vehicle.h" +#include "Unit.h" +#include "Creature.h" +#include "CreatureAI.h" +#include "GameObject.h" #include "sc_creature.h" #include "sc_gossip.h" #include "sc_grid_searchers.h" #include "sc_instance.h" +#include "sc_timer.h" +#include "sc_utility.h" +#include "SpellAuras.h" #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 a25f7ea863..2004bb2cd3 100644 --- a/include/sc_creature.cpp +++ b/include/sc_creature.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,19 +7,37 @@ #include "Spell.h" #include "WorldPacket.h" #include "ObjectMgr.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" // Spell summary for ScriptedAI::SelectSpell 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_events(NULL), m_uiEvadeCheckCooldown(2500) {} +ScriptedAI::~ScriptedAI() +{ + if (m_events) + delete m_events; +} + +/// 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(IsCombatMovement())); +} + +/// Return if the creature can "see" pWho bool ScriptedAI::IsVisible(Unit* pWho) const { if (!pWho) @@ -28,10 +46,19 @@ bool ScriptedAI::IsVisible(Unit* pWho) const return m_creature->IsWithinDist(pWho, VISIBLE_RANGE) && pWho->isVisibleForOrDetect(m_creature, m_creature, true); } +/** + * This function triggers the creature attacking pWho, depending on conditions like: + * - Can the creature start an attack? + * - Is pWho hostile to the creature? + * - Can the creature reach pWho? + * - Is pWho in aggro-range? + * If the creature can attack pWho, it will if it has no victim. + * Inside dungeons, the creature will get into combat with pWho, even if it has already a victim + */ 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; @@ -52,61 +79,81 @@ void ScriptedAI::MoveInLineOfSight(Unit* pWho) } } +/** + * This function sets the TargetGuid for the creature if required + * Also it will handle the combat movement (chase movement), depending on SetCombatMovement(bool) + */ void ScriptedAI::AttackStart(Unit* pWho) { - if (pWho && m_creature->Attack(pWho, true)) + 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); } } +/** + * This function only calls Aggro, which is to be used for scripting purposes + */ void ScriptedAI::EnterCombat(Unit* pEnemy) { if (pEnemy) Aggro(pEnemy); } -void ScriptedAI::Aggro(Unit* pEnemy) +/** + * Main update function, by default let the creature behave as expected by a mob (threat management and melee dmg) + * Always handle here threat-management with m_creature->SelectHostileTarget() + * Handle (if required) melee attack with DoMeleeAttackIfReady() + * This is usally overwritten to support timers for ie spells + */ +void ScriptedAI::UpdateAI(uint32 const /*uiDiff*/) { -} - -void ScriptedAI::UpdateAI(const uint32 uiDiff) -{ - //Check if we have a current target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Check if we have a current target + if (!SelectVictim()) return; - if (m_creature->isAttackReady()) - { - //If we are within range melee the target - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } + DoMeleeAttackIfReady(); } +/** + * This function cleans up the combat state if the creature evades + * It will: + * - Drop Auras + * - Drop all threat + * - Stop combat + * - Move the creature home + * - Clear tagging for loot + * - call Reset() + */ void ScriptedAI::EnterEvadeMode() { - m_creature->RemoveAllAuras(); + VehicleKitPtr pVehicleKit = m_creature->GetVehicleKit(); + if (pVehicleKit) + pVehicleKit->Reset(); + + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); - m_creature->LoadCreatureAddon(); - if (m_creature->isAlive()) + if (m_creature->isAlive() && !m_creature->GetVehicle()) + { + m_creature->GetMotionMaster()->Clear(true); m_creature->GetMotionMaster()->MoveTargetedHome(); + } m_creature->SetLootRecipient(NULL); Reset(); } +/// This function calls Reset() to reset variables as expected void ScriptedAI::JustRespawned() { Reset(); @@ -127,42 +174,51 @@ void ScriptedAI::DoStartNoMovement(Unit* pVictim) m_creature->StopMoving(); } -void ScriptedAI::DoMeleeAttackIfReady() -{ - //Make sure our attack is ready before checking distance - if (m_creature->isAttackReady()) - { - //If we are within range melee the target - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } -} - void ScriptedAI::DoStopAttack() { if (m_creature->getVictim()) m_creature->AttackStop(); } -void ScriptedAI::DoCast(Unit* pTarget, uint32 uiSpellId, bool bTriggered) +void ScriptedAI::DoCast(Unit* pTarget, uint32 uiSpellId, bool bTriggered /*=false*/) { - if (m_creature->IsNonMeleeSpellCasted(false) && !bTriggered) + if (!bTriggered && m_creature->IsNonMeleeSpellCasted(false)) return; m_creature->CastSpell(pTarget, uiSpellId, bTriggered); } -void ScriptedAI::DoCastSpell(Unit* pTarget, SpellEntry const* pSpellInfo, bool bTriggered) +void ScriptedAI::DoCastSpell(Unit* pTarget, SpellEntry const* pSpellInfo, bool bTriggered /*=false*/) { - if (m_creature->IsNonMeleeSpellCasted(false) && !bTriggered) + if (!bTriggered && m_creature->IsNonMeleeSpellCasted(false)) return; m_creature->CastSpell(pTarget, pSpellInfo, bTriggered); } +void ScriptedAI::DoCastVictim(uint32 spellId, bool triggered) +{ + if (!m_creature->getVictim() || m_creature->IsNonMeleeSpellCasted(false) && !triggered) + return; + + m_creature->CastSpell(m_creature->getVictim(), spellId, triggered); +} + +void ScriptedAI::DoCastAOE(uint32 spellId, bool triggered) +{ + if (!triggered && m_creature->IsNonMeleeSpellCasted(false)) + return; + + m_creature->CastSpell((Unit*)NULL, spellId, triggered); +} + +void ScriptedAI::DoCastSpellOnPlayers(uint32 spellId) +{ + Map::PlayerList const &lPlayers = m_creature->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = lPlayers.begin(); i != lPlayers.end(); ++i) + m_creature->CastSpell(i->getSource(),spellId, true); +} + void ScriptedAI::DoPlaySoundToSet(WorldObject* pSource, uint32 uiSoundId) { if (!pSource) @@ -170,7 +226,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; } @@ -179,116 +235,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 uiMechanic, SelectTarget selectTargets, uint32 uiPowerCostMin, uint32 uiPowerCostMax, float fRangeMin, float fRangeMax, SelectEffect selectEffects) +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]); + pTempSpell = GetSpellStore()->LookupEntry(m_creature->GetSpell(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->GetSpell(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->GetSpell(i)].Effects & (1 << (selectEffects - 1)))) continue; - //Check for school if specified - if (uiSchool >= 0 && pTempSpell->SchoolMask & uiSchool) + // Check for school if specified + if (uiSchool >= 0 && pTempSpell->GetSchoolMask() & uiSchool) continue; - //Check for spell mechanic if specified - if (uiMechanic >= 0 && pTempSpell->Mechanic != uiMechanic) + // Check for spell mechanic if specified + if (iMechanic >= 0 && pTempSpell->GetMechanic() != (uint32)iMechanic) continue; - //Make sure that the spell uses the requested amount of power - if (uiPowerCostMin && pTempSpell->manaCost < uiPowerCostMin) + // Make sure that the spell uses the requested amount of power + if (uiPowerCostMin && pTempSpell->GetManaCost() < uiPowerCostMin) continue; - if (uiPowerCostMax && pTempSpell->manaCost > uiPowerCostMax) + if (uiPowerCostMax && pTempSpell->GetManaCost() > uiPowerCostMax) continue; - //Continue if we don't have the mana to actually cast this spell - if (pTempSpell->manaCost > m_creature->GetPower((Powers)pTempSpell->powerType)) + // Continue if we don't have the mana to actually cast this spell + if (pTempSpell->GetManaCost() > m_creature->GetPower((Powers)pTempSpell->GetPowerType())) continue; - //Get the Range - pTempRange = GetSpellRangeStore()->LookupEntry(pTempSpell->rangeIndex); + // Get the Range + pTempRange = GetSpellRangeStore()->LookupEntry(pTempSpell->GetRangeIndex()); - //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 - if (!bTriggered && m_creature->GetPower((Powers)pSpellEntry->powerType) < pSpellEntry->manaCost) + // Check for power + if (!bTriggered && m_creature->GetPower(pSpellEntry->GetPowerType()) < pSpellEntry->GetManaCost()) return false; - SpellRangeEntry const* pTempRange = GetSpellRangeStore()->LookupEntry(pSpellEntry->rangeIndex); + SpellRangeEntry const* pTempRange = GetSpellRangeStore()->LookupEntry(pSpellEntry->GetRangeIndex()); - //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; @@ -307,75 +363,79 @@ 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 - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_SELF) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); - - //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); - - //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); - - //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) - 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); - - //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); - - //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 - 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); - - //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); - - //Make sure that this spell applies an aura - if (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); + SpellEffectEntry const* pSpellEffect = pTempSpell->GetSpellEffect(SpellEffectIndex(j)); + if (!pSpellEffect) + continue; + + // Spell targets self + if (pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SELF) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF - 1); + + // Spell targets a single enemy + if (pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CHAIN_DAMAGE || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CURRENT_ENEMY_COORDINATES) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY - 1); + + // Spell targets AoE at enemy + if (pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_ENEMY_IN_AREA || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_ENEMY_IN_AREA_INSTANT || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CASTER_COORDINATES || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY - 1); + + // Spell targets an enemy + if (pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CHAIN_DAMAGE || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CURRENT_ENEMY_COORDINATES || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_ENEMY_IN_AREA || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_ENEMY_IN_AREA_INSTANT || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CASTER_COORDINATES || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(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->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SELF || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SINGLE_FRIEND || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SINGLE_PARTY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND - 1); + + // Spell targets aoe friends + if (pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_PARTY_AROUND_CASTER || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_AREAEFFECT_PARTY || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CASTER_COORDINATES) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND - 1); + + // Spell targets any friend(or self) + if (pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SELF || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SINGLE_FRIEND || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_SINGLE_PARTY || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_ALL_PARTY_AROUND_CASTER || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_AREAEFFECT_PARTY || + pTempSpell->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_CASTER_COORDINATES) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND - 1); + + // Make sure that this spell includes a damage effect + if (pSpellEffect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE || + pSpellEffect->Effect == SPELL_EFFECT_INSTAKILL || + pSpellEffect->Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + pSpellEffect->Effect == 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) + if (pSpellEffect->Effect == SPELL_EFFECT_HEAL || + pSpellEffect->Effect == SPELL_EFFECT_HEAL_MAX_HEALTH || + pSpellEffect->Effect == SPELL_EFFECT_HEAL_MECHANICAL || + (pSpellEffect->Effect == SPELL_EFFECT_APPLY_AURA && pTempSpell->GetEffectApplyAuraNameByIndex(SpellEffectIndex(j)) == 8)) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING - 1); + + // Make sure that this spell applies an aura + if (pSpellEffect->Effect == SPELL_EFFECT_APPLY_AURA) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA - 1); } } } @@ -384,12 +444,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()); @@ -405,7 +465,7 @@ void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float fX, float fY, float fZ, flo if (pUnit->GetTypeId() != TYPEID_PLAYER) { - error_log("SD2: Creature " UI64FMTD " (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: " UI64FMTD ") to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGUID(), m_creature->GetEntry(), pUnit->GetTypeId(), pUnit->GetGUID(), 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; } @@ -460,37 +520,37 @@ Player* ScriptedAI::GetPlayerAtMinimumRange(float fMinimumRange) return pPlayer; } -void ScriptedAI::SetEquipmentSlots(bool bLoadDefault, int32 uiMainHand, int32 uiOffHand, int32 uiRanged) +void ScriptedAI::SetEquipmentSlots(bool bLoadDefault, int32 iMainHand, int32 iOffHand, int32 iRanged) { if (bLoadDefault) { - m_creature->LoadEquipment(m_creature->GetCreatureInfo()->equipmentId,true); + m_creature->LoadEquipment(m_creature->GetCreatureInfo()->EquipmentTemplateId, true); return; } - if (uiMainHand >= 0) - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(uiMainHand)); - - if (uiOffHand >= 0) - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(uiOffHand)); + if (iMainHand >= 0) + m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, iMainHand); - if (uiRanged >= 0) - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(uiRanged)); -} + if (iOffHand >= 0) + m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, iOffHand); -void ScriptedAI::SetCombatMovement(bool bCombatMove) -{ - m_bCombatMovement = bCombatMove; + if (iRanged >= 0) + m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, iRanged); } // 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 { - NPC_BROODLORD = 12017, - NPC_VOID_REAVER = 19516, - NPC_JAN_ALAI = 23578, - NPC_SARTHARION = 28860 + NPC_BROODLORD = 12017, + NPC_VOID_REAVER = 19516, + NPC_JAN_ALAI = 23578, + NPC_SARTHARION = 28860, + NPC_TALON_KING_IKISS = 18473, + NPC_KARGATH_BLADEFIST = 16808, + NPC_ANUBARAK = 29120, + NPC_SINDRAGOSA = 36853, + NPC_ZARITHRIAN = 39746, }; bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) @@ -510,7 +570,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) @@ -528,8 +588,32 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) if (fX > 3218.86f && fX < 3275.69f && fY < 572.40f && fY > 484.68f) return false; break; + case NPC_TALON_KING_IKISS: + { + float fX, fY, fZ; + m_creature->GetRespawnCoord(fX, fY, fZ); + if (m_creature->GetDistance2d(fX, fY) < 70.0f) + return false; + break; + } + case NPC_KARGATH_BLADEFIST: + if (fX < 255.0f && fX > 205.0f) + return false; + break; + case NPC_ANUBARAK: + 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; } @@ -537,8 +621,25 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) return true; } +EventManager& ScriptedAI::Events() +{ + // use lazy initialization to save memory + if (!m_events) + m_events = new EventManager(); + + return *m_events; +} + +void Scripted_NoMovementAI::GetAIInformation(ChatHandler& reader) +{ + reader.PSendSysMessage("Subclass of Scripted_NoMovementAI"); +} + void Scripted_NoMovementAI::AttackStart(Unit* pWho) { + if (!m_creature->CanAttackByItself()) + return; + if (pWho && m_creature->Attack(pWho, true)) { m_creature->AddThreat(pWho); @@ -548,3 +649,8 @@ void Scripted_NoMovementAI::AttackStart(Unit* pWho) DoStartNoMovement(pWho); } } + +bool ScriptedAI::UpdateVictim() const +{ + return m_creature->SelectHostileTarget() && m_creature->getVictim(); +} diff --git a/include/sc_creature.h b/include/sc_creature.h index 0c8a6fd0c4..b38f58eaf5 100644 --- a/include/sc_creature.h +++ b/include/sc_creature.h @@ -1,36 +1,37 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef SC_CREATURE_H #define SC_CREATURE_H -#include "CreatureAI.h" -#include "Creature.h" +#include "Chat.h" -//Spell targets used by SelectSpell +class EventManager; + +// 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 @@ -39,148 +40,398 @@ enum SCEquip EQUIP_UNEQUIP = 0 }; +/// 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 { - explicit ScriptedAI(Creature* pCreature); - ~ScriptedAI() {} + public: + explicit ScriptedAI(Creature* pCreature); + ~ScriptedAI(); + + // ************* + // CreatureAI Functions + // ************* + + // == Information about AI ======================== + // Get information about the AI + void GetAIInformation(ChatHandler& reader) override; + + // == Reactions At ================================= + + // Called if IsVisible(Unit* pWho) is true at each relative pWho move + void MoveInLineOfSight(Unit* pWho) override; + + // Called for reaction at enter to combat if not in combat yet (enemy can be NULL) + void EnterCombat(Unit* pEnemy) override; + + // Called at stoping attack by any attacker + void EnterEvadeMode() override; + + // Called when reached home after MoveTargetHome (in evade) + void JustReachedHome() 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 {} + + // Called at any Damage from any attacker (before damage apply) + void DamageTaken(Unit* /*pDealer*/, uint32& /*uiDamage*/) override {} - //************* - //CreatureAI Functions - //************* + // Called at creature death + void JustDied(Unit* /*pKiller*/) override {} - //Called if IsVisible(Unit *who) is true at each *who move - void MoveInLineOfSight(Unit*); + // Called when the corpse of this creature gets removed + void CorpseRemoved(uint32& /*uiRespawnDelay*/) override {} - //Called at each attack of m_creature by any victim - void AttackStart(Unit*); + // Called when a summoned creature is killed + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override {} - // Called for reaction at enter to combat if not in combat yet (enemy can be NULL) - void EnterCombat(Unit*); + // Called at creature killing another unit + void KilledUnit(Unit* /*pVictim*/) override {} - //Called at stoping attack by any attacker - void EnterEvadeMode(); + // Called when owner of m_creature (if m_creature is PROTECTOR_PET) kills a unit + void OwnerKilledUnit(Unit* /*pVictim*/) override {} - //Called at any heal cast/item used (call non implemented in mangos) - void HealBy(Unit* pHealer, uint32 uiAmountHealed) {} + // Called when the creature successfully summons a creature + void JustSummoned(Creature* /*pSummoned*/) override {} - // Called at any Damage to any victim (before damage apply) - void DamageDeal(Unit* pDoneTo, uint32& uiDamage) {} + // Called when the creature successfully summons a gameobject + void JustSummoned(GameObject* /*pGo*/) override {} - // Called at any Damage from any attacker (before damage apply) - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) {} + // Called when a summoned creature gets TemporarySummon::UnSummon ed + void SummonedCreatureDespawn(Creature* /*pSummoned*/) override {} - //Is unit visible for MoveInLineOfSight - bool IsVisible(Unit* pWho) const; + // Called when hit by a spell + void SpellHit(Unit* /*pCaster*/, const SpellEntry* /*pSpell*/) override {} - //Called at World update tick - void UpdateAI(const uint32); + // Called when spell hits creature's target + void SpellHitTarget(Unit* /*pTarget*/, const SpellEntry* /*pSpell*/) override {} - //Called at creature death - void JustDied(Unit*) {} + // 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 + //void AttackedBy(Unit* pAttacker) override { CreatureAI::AttackedBy(pAttacker); } - //Called at creature killing another unit - void KilledUnit(Unit*) {} + // Called when creature is respawned (for reseting variables) + void JustRespawned() override; - // Called when the creature summon successfully other creature - void JustSummoned(Creature*) {} + // Called at waypoint reached or point movement finished + void MovementInform(uint32 /*uiMovementType*/, uint32 /*uiData*/) override {} - // Called when a summoned creature is despawned - void SummonedCreatureDespawn(Creature*) {} + // Called if a temporary summoned of m_creature reach a move point + void SummonedMovementInform(Creature* /*pSummoned*/, uint32 /*uiMotionType*/, uint32 /*uiData*/) override {} - // Called when hit by a spell - void SpellHit(Unit*, const SpellEntry*) {} + // Called at text emote receive from player + void ReceiveEmote(Player* /*pPlayer*/, uint32 /*uiEmote*/) override {} - // Called when creature is spawned or respawned (for reseting variables) - void JustRespawned(); + // Called at each attack of m_creature by any victim + void AttackStart(Unit* pWho) override; - //Called at waypoint reached or PointMovement end - void MovementInform(uint32, uint32) {} + // Called at World update tick + void UpdateAI(uint32 const) override; - //************* - // Variables - //************* + // Called to select / update victim + //Unit* SelectVictim() override { return CreatureAI::SelectVictim(); } - //************* - //Pure virtual functions - //************* + // Called when an AI Event is received + void ReceiveAIEvent(AIEventType /*eventType*/, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override {} - //Called at creature reset either by death or evade - virtual void Reset() = 0; + // == State checks ================================= - //Called at creature EnterCombat - virtual void Aggro(Unit*); + // Check if unit is visible for MoveInLineOfSight + bool IsVisible(Unit* pWho) const override; - //************* - //AI Helper Functions - //************* + // Called when victim entered water and creature can not enter water + //bool canReachByRangeAttack(Unit* pWho) override { return CreatureAI::canReachByRangeAttack(pWho); } - //Start movement toward victim - void DoStartMovement(Unit* pVictim, float fDistance = 0, float fAngle = 0); + // ************* + // Variables + // ************* - //Start no movement on victim - void DoStartNoMovement(Unit* pVictim); + // ************* + // Pure virtual functions + // ************* - //Do melee swing of current victim if in rnage and ready and not casting - void DoMeleeAttackIfReady(); + /** + * This is a SD2 internal function, that every AI must implement + * Usally used to reset combat variables + * Called by default on creature evade and respawn + * In most scripts also called in the constructor of the AI + */ + virtual void Reset() = 0; - //Stop attack of current victim - void DoStopAttack(); + /// Called at creature EnterCombat with an enemy + /** + * This is a SD2 internal function + * Called by default on creature EnterCombat with an enemy + */ + virtual void Aggro(Unit* /*pWho*/) {} - //Cast spell by Id - void DoCast(Unit* pTarget, uint32 uiSpellId, bool bTriggered = false); + // ************* + // AI Helper Functions + // ************* - //Cast spell by spell info - void DoCastSpell(Unit* pTarget, SpellEntry const* pSpellInfo, bool bTriggered = false); + // Start movement toward victim + void DoStartMovement(Unit* pVictim, float fDistance = 0, float fAngle = 0); - //Plays a sound to all nearby players - void DoPlaySoundToSet(WorldObject* pSource, uint32 uiSoundId); + // Start no movement on victim + void DoStartNoMovement(Unit* pVictim); - //Drops all threat to 0%. Does not remove players from the threat list - void DoResetThreat(); + // Stop attack of current victim + void DoStopAttack(); - //Teleports a player without dropping threat (only teleports to same map) - void DoTeleportPlayer(Unit* pUnit, float fX, float fY, float fZ, float fO); + // Cast spell by Id + void DoCast(Unit* pTarget, uint32 uiSpellId, bool bTriggered = false); - //Returns friendly unit with the most amount of hp missing from max hp - Unit* DoSelectLowestHpFriendly(float fRange, uint32 uiMinHPDiff = 1); + // Cast spell by spell info + void DoCastSpell(Unit* pTarget, SpellEntry const* pSpellInfo, bool bTriggered = false); + void DoCastVictim(uint32 spellId, bool triggered = false); + void DoCastAOE(uint32 spellId, bool triggered = false); + void DoCastSpellOnPlayers(uint32 spellId); - //Returns a list of friendly CC'd units within range - std::list DoFindFriendlyCC(float fRange); + // Plays a sound to all nearby players + void DoPlaySoundToSet(WorldObject* pSource, uint32 uiSoundId); - //Returns a list of all friendly units missing a specific buff within range - std::list DoFindFriendlyMissingBuff(float fRange, uint32 uiSpellId); + // Drops all threat to 0%. Does not remove enemies from the threat list + void DoResetThreat(); - //Return a player with at least minimumRange from m_creature - Player* GetPlayerAtMinimumRange(float fMinimumRange); + // Teleports a player without dropping threat (only teleports to same map) + void DoTeleportPlayer(Unit* pUnit, float fX, float fY, float fZ, float fO); - //Spawns a creature relative to m_creature - Creature* DoSpawnCreature(uint32 uiId, float fX, float fY, float fZ, float fAngle, uint32 uiType, uint32 uiDespawntime); + // Returns friendly unit with the most amount of hp missing from max hp + Unit* DoSelectLowestHpFriendly(float fRange, uint32 uiMinHPDiff = 1); - //Returns spells that meet the specified criteria from the creatures spell list - SpellEntry const* SelectSpell(Unit* pTarget, int32 uiSchool, int32 uiMechanic, SelectTarget selectTargets, uint32 uiPowerCostMin, uint32 uiPowerCostMax, float fRangeMin, float fRangeMax, SelectEffect selectEffect); + // Returns a list of friendly CC'd units within range + std::list DoFindFriendlyCC(float fRange); - //Checks if you can cast the specified spell - bool CanCast(Unit* pTarget, SpellEntry const* pSpell, bool bTriggered = false); + // Returns a list of all friendly units missing a specific buff within range + std::list DoFindFriendlyMissingBuff(float fRange, uint32 uiSpellId); - void SetEquipmentSlots(bool bLoadDefault, int32 uiMainHand = EQUIP_NO_CHANGE, int32 uiOffHand = EQUIP_NO_CHANGE, int32 uiRanged = EQUIP_NO_CHANGE); + // Return a player with at least minimumRange from m_creature + Player* GetPlayerAtMinimumRange(float fMinimumRange); - //Generally used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims - void SetCombatMovement(bool bCombatMove); - bool IsCombatMovement() { return m_bCombatMovement; } + // Spawns a creature relative to m_creature + Creature* DoSpawnCreature(uint32 uiId, float fX, float fY, float fZ, float fAngle, uint32 uiType, uint32 uiDespawntime); - bool EnterEvadeIfOutOfCombatArea(const uint32 uiDiff); + // Returns spells that meet the specified criteria from the creatures spell list + SpellEntry const* SelectSpell(Unit* pTarget, int32 uiSchool, int32 iMechanic, SelectTarget selectTargets, uint32 uiPowerCostMin, uint32 uiPowerCostMax, float fRangeMin, float fRangeMax, SelectEffect selectEffect); + + // Checks if you can cast the specified spell + bool CanCast(Unit* pTarget, SpellEntry const* pSpell, bool bTriggered = false); + + void SetEquipmentSlots(bool bLoadDefault, int32 iMainHand = EQUIP_NO_CHANGE, int32 iOffHand = EQUIP_NO_CHANGE, int32 iRanged = EQUIP_NO_CHANGE); + + bool EnterEvadeIfOutOfCombatArea(const uint32 uiDiff); + + bool UpdateVictim() const; + + EventManager& Events(); private: bool m_bCombatMovement; uint32 m_uiEvadeCheckCooldown; + EventManager* m_events; }; struct MANGOS_DLL_DECL Scripted_NoMovementAI : public ScriptedAI { - Scripted_NoMovementAI(Creature* pCreature) : ScriptedAI(pCreature) {} + Scripted_NoMovementAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + } + + void GetAIInformation(ChatHandler& reader) override; - //Called at each attack of m_creature by any victim - void AttackStart(Unit*); + // Called at each attack of m_creature by any victim + void AttackStart(Unit* pWho) override; +}; + +class EventMap : private std::map +{ + public: + EventMap() : _time(0), _phase(0) {} + + // Returns current timer value, does not represent real dates/times + uint32 GetTimer() const { return _time; } + + // Removes all events and clears phase + void Reset() { clear(); _time = 0; _phase = 0; } + + void Update(uint32 time) { _time += time; } + + uint32 GetPhaseMask() const { return (_phase >> 24) & 0xFF; } + + bool Empty() const { return empty(); } + + // Sets event phase, must be in range 1 - 8 + void SetPhase(uint32 phase) + { + if (phase && phase < 8) + _phase = (1 << (phase + 24)); + else if (!phase) + _phase = 0; + } + + // Creates new event entry in map with given id, time, group if given (1 - 8) and phase if given (1 - 8) + // 0 for group/phase means it belongs to no group or runs in all phases + void ScheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0) + { + time += _time; + if (groupId && groupId < 9) + eventId |= (1 << (groupId + 16)); + if (phase && phase < 8) + eventId |= (1 << (phase + 24)); + const_iterator itr = find(time); + while (itr != end()) + { + ++time; + itr = find(time); + } + + insert(std::make_pair(time, eventId)); + } + + // Removes event with specified id and creates new entry for it + void RescheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0) + { + CancelEvent(eventId); + ScheduleEvent(eventId, time, groupId, phase); + } + + // Reschedules closest event + void RepeatEvent(uint32 time) + { + if (empty()) + return; + + uint32 eventId = begin()->second; + erase(begin()); + time += _time; + const_iterator itr = find(time); + while (itr != end()) + { + ++time; + itr = find(time); + } + + insert(std::make_pair(time, eventId)); + } + + // Removes first event + void PopEvent() + { + erase(begin()); + } + + // Gets next event id to execute and removes it from map + uint32 ExecuteEvent() + { + while (!empty()) + { + if (begin()->first > _time) + return 0; + else if (_phase && (begin()->second & 0xFF000000) && !(begin()->second & _phase)) + erase(begin()); + else + { + uint32 eventId = (begin()->second & 0x0000FFFF); + erase(begin()); + return eventId; + } + } + return 0; + } + + // Gets next event id to execute + uint32 GetEvent() + { + while (!empty()) + { + if (begin()->first > _time) + return 0; + else if (_phase && (begin()->second & 0xFF000000) && !(begin()->second & _phase)) + erase(begin()); + else + return (begin()->second & 0x0000FFFF); + } + + return 0; + } + + // Delay all events + void DelayEvents(uint32 delay) + { + if (delay < _time) + _time -= delay; + else + _time = 0; + } + + // Delay all events having the specified Group + void DelayEvents(uint32 delay, uint32 groupId) + { + uint32 nextTime = _time + delay; + uint32 groupMask = (1 << (groupId + 16)); + for (iterator itr = begin(); itr != end() && itr->first < nextTime;) + { + if (itr->second & groupMask) + { + ScheduleEvent(itr->second, itr->first - _time + delay); + erase(itr); + itr = begin(); + } + else + ++itr; + } + } + + // Cancel events with specified id + void CancelEvent(uint32 eventId) + { + for (iterator itr = begin(); itr != end();) + { + if (eventId == (itr->second & 0x0000FFFF)) + { + erase(itr); + itr = begin(); + } + else + ++itr; + } + } + + // Cancel events belonging to specified group + void CancelEventGroup(uint32 groupId) + { + uint32 groupMask = (1 << (groupId + 16)); + + for (iterator itr = begin(); itr != end();) + { + if (itr->second & groupMask) + { + erase(itr); + itr = begin(); + } + else + ++itr; + } + } + + // Returns time of next event to execute + // To get how much time remains substract _time + uint32 GetNextEventTime(uint32 eventId) const + { + for (const_iterator itr = begin(); itr != end(); ++itr) + if (eventId == (itr->second & 0x0000FFFF)) + return itr->first; + + return 0; + } + + private: + uint32 _time; + uint32 _phase; }; #endif diff --git a/include/sc_gossip.h b/include/sc_gossip.h index e1034572f6..a3c263a341 100644 --- a/include/sc_gossip.h +++ b/include/sc_gossip.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -140,49 +140,20 @@ extern uint32 GetSkillLevel(Player* pPlayer, uint32 uiSkill); #define ADD_GOSSIP_ITEM_ID(uiIcon, iTextId, uiSender, uiOptionId) PlayerTalkClass->GetGossipMenu().AddMenuItem(uiIcon, iTextId, uiSender, uiOptionId, 0, 0) #define ADD_GOSSIP_ITEM_EXTENDED(uiIcon, chrText, uiSender, uiOptionId, chrBoxMessage, uiBoxMoney, bCode) PlayerTalkClass->GetGossipMenu().AddMenuItem(uiIcon, chrText, uiSender, uiOptionId, chrBoxMessage, uiBoxMoney, bCode) -// This fuction Sends the current menu to show to client, uiTextId - NPCTEXTID(uint32) , uiGuid - npc guid(uint64) -#define SEND_GOSSIP_MENU(uiTextId, uiGuid) PlayerTalkClass->SendGossipMenu(uiTextId, uiGuid) - -// This fuction shows POI(point of interest) to client. -// a - position X -// b - position Y -// c - Icon Id -// d - Flags -// e - Data -// f - Location Name -#define SEND_POI(a, b, c, d, e, f) PlayerTalkClass->SendPointOfInterest(a, b, c, d, e, f) +// This fuction Sends the current menu to show to client +// uiTextId - NPCTEXTID (uint32) +// guid - npc guid (ObjectGuid) +#define SEND_GOSSIP_MENU(uiTextId, guid) PlayerTalkClass->SendGossipMenu(uiTextId, guid) // Closes the Menu #define CLOSE_GOSSIP_MENU() PlayerTalkClass->CloseGossip() -// Fuction to tell to client the details -// a - quest object -// b - npc guid(uint64) -// c - Activate accept(bool) -#define SEND_QUEST_DETAILS(a, b, c) PlayerTalkClass->SendQuestDetails(a, b, c) - -// Fuction to tell to client the requested items to complete quest -// a - quest object -// b - npc guid(uint64) -// c - Iscompletable(bool) -// d - close at cancel(bool) - in case single incomplite ques -#define SEND_REQUESTEDITEMS(a, b, c, d) PlayerTalkClass->SendRequestedItems(a, b, c, d) - -// Fuctions to send NPC lists, a - is always the npc guid(uint64) +// Fuctions to send NPC lists +// a - is always the npc guid (ObjectGuid) #define SEND_VENDORLIST(a) GetSession()->SendListInventory(a) #define SEND_TRAINERLIST(a) GetSession()->SendTrainerList(a) #define SEND_BANKERLIST(a) GetSession()->SendShowBank(a) #define SEND_TABARDLIST(a) GetSession()->SendTabardVendorActivate(a) #define SEND_TAXILIST(a) GetSession()->SendTaxiStatus(a) -// Function to send the Auction List, a - npc guid(uint64), b - pointer to npc(Creature*) -#define SEND_AUCTIONLIST(a, b) GetSession()->SendAuctionHello(a, b) - -// Ressurect's the player if is dead. -#define SEND_SPRESURRECT() GetSession()->SendSpiritResurrect() -// ----------------------------------- - -// defined fuctions to use with Creature - -#define QUEST_DIALOG_STATUS(a, b, c) GetSession()->getDialogStatus(a, b, c) #endif diff --git a/include/sc_grid_searchers.cpp b/include/sc_grid_searchers.cpp index 27343151c7..48cb102b5d 100644 --- a/include/sc_grid_searchers.cpp +++ b/include/sc_grid_searchers.cpp @@ -1,10 +1,25 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #include "precompiled.h" -//return closest GO in grid, with range from pSource +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" + +// return closest attackable Unit in grid, with range from pSource +Unit* GetClosestAttackableUnit(Unit* pSource, float fMaxSearchRange) +{ + Unit* pTarget = NULL; + MaNGOS::NearestAttackableUnitInObjectRangeCheck unit_check(pSource, fMaxSearchRange); + MaNGOS::UnitLastSearcher searcher(pTarget, unit_check); + Cell::VisitAllObjects(pSource, searcher, fMaxSearchRange); + return pTarget; +} + +// return closest GO in grid, with range from pSource GameObject* GetClosestGameObjectWithEntry(WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange) { GameObject* pGo = NULL; @@ -17,12 +32,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) +// 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, true, fMaxSearchRange); + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*pSource, uiEntry, bOnlyAlive, bOnlyDead, fMaxSearchRange, bExcludeSelf); MaNGOS::CreatureLastSearcher searcher(pCreature, creature_check); Cell::VisitGridObjects(pSource, searcher, fMaxSearchRange); @@ -32,16 +47,23 @@ Creature* GetClosestCreatureWithEntry(WorldObject* pSource, uint32 uiEntry, floa void GetGameObjectListWithEntryInGrid(std::list& lList , WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange) { - AllGameObjectsWithEntryInRangeCheck check(pSource, uiEntry, fMaxSearchRange); - MaNGOS::GameObjectListSearcher searcher(lList, check); + MaNGOS::GameObjectEntryInPosRangeCheck check(*pSource, uiEntry, pSource->GetPositionX(), pSource->GetPositionY(), pSource->GetPositionZ(), fMaxSearchRange); + MaNGOS::GameObjectListSearcher searcher(lList, check); Cell::VisitGridObjects(pSource, searcher, fMaxSearchRange); } void GetCreatureListWithEntryInGrid(std::list& lList, WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange) { - AllCreaturesOfEntryInRangeCheck check(pSource, uiEntry, fMaxSearchRange); - MaNGOS::CreatureListSearcher searcher(lList, check); + MaNGOS::AllCreaturesOfEntryInRangeCheck check(pSource, uiEntry, fMaxSearchRange); + MaNGOS::CreatureListSearcher searcher(lList, check); Cell::VisitGridObjects(pSource, searcher, fMaxSearchRange); } + +void GetPlayerListInGrid(std::list& pList, WorldObject* pSource, float fMaxSearchRange) +{ + MaNGOS::AnyPlayerInObjectRangeCheck u_check(pSource, fMaxSearchRange); + MaNGOS::PlayerListSearcher checker(pList, u_check); + Cell::VisitWorldObjects(pSource, checker, fMaxSearchRange); +} diff --git a/include/sc_grid_searchers.h b/include/sc_grid_searchers.h index a15a637d21..39014b20b3 100644 --- a/include/sc_grid_searchers.h +++ b/include/sc_grid_searchers.h @@ -1,17 +1,13 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef SC_GRIDSEARCH_H #define SC_GRIDSEARCH_H -#include "Unit.h" -#include "GameObject.h" - -#include "Cell.h" -#include "CellImpl.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" +#include "Object.h" +class GameObject; +class Creature; struct ObjectDistanceOrder : public std::binary_function { @@ -37,51 +33,16 @@ struct ObjectDistanceOrderReversed : public std::binary_function& lList , WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange); void GetCreatureListWithEntryInGrid(std::list& lList, WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange); -class AllGameObjectsWithEntryInRangeCheck -{ - public: - AllGameObjectsWithEntryInRangeCheck(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} - WorldObject const& GetFocusObject() const { return *m_pObject; } - bool operator() (GameObject* pGo) - { - if (pGo->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pGo,m_fRange,false)) - return true; - - return false; - } - - private: - const WorldObject* m_pObject; - uint32 m_uiEntry; - float m_fRange; -}; - -class AllCreaturesOfEntryInRangeCheck -{ - public: - AllCreaturesOfEntryInRangeCheck(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} - WorldObject const& GetFocusObject() const { return *m_pObject; } - bool operator() (Unit* pUnit) - { - if (pUnit->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pUnit,m_fRange,false)) - return true; - - return false; - } - - private: - const WorldObject* m_pObject; - uint32 m_uiEntry; - float m_fRange; -}; +void GetPlayerListInGrid(std::list& pList, WorldObject* pSource, 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 30e085bf90..3a0b832bd0 100644 --- a/include/sc_instance.cpp +++ b/include/sc_instance.cpp @@ -1,18 +1,25 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #include "precompiled.h" +#include "SharedDefines.h" -//Optional uiWithRestoreTime. If not defined, autoCloseTime will be used (if not 0 by default in *_template) -void ScriptedInstance::DoUseDoorOrButton(uint64 uiGuid, uint32 uiWithRestoreTime, bool bUseAlternativeState) +/** + Function that uses a door or a button + + @param guid The ObjectGuid of the Door/ Button that will be used + @param uiWithRestoreTime (in seconds) if == 0 autoCloseTime will be used (if not 0 by default in *_template) + @param bUseAlternativeState Use to alternative state + */ +void ScriptedInstance::DoUseDoorOrButton(ObjectGuid guid, uint32 uiWithRestoreTime, bool bUseAlternativeState) { - if (!uiGuid) + if (!guid) return; - if (GameObject* pGo = instance->GetGameObject(uiGuid)) + 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); @@ -20,17 +27,87 @@ void ScriptedInstance::DoUseDoorOrButton(uint64 uiGuid, uint32 uiWithRestoreTime 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()); + } +} + +/// Function that uses a door or button that is stored in m_mGoEntryGuidStore +void ScriptedInstance::DoUseDoorOrButton(uint32 uiEntry, uint32 uiWithRestoreTime /*= 0*/, bool bUseAlternativeState /*= false*/) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(uiEntry); + if (find != m_mGoEntryGuidStore.end()) + DoUseDoorOrButton(find->second, uiWithRestoreTime, bUseAlternativeState); + else + // Output log, possible reason is not added GO to storage, or not yet loaded + debug_log("SD2: Script call DoUseDoorOrButton(by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); +} + +void ScriptedInstance::DoOpenDoor(ObjectGuid guid, bool bUseAlternativeState /*= false*/) +{ + if (guid.IsEmpty()) + return; + + GameObject* pGo = instance->GetGameObject(guid); + + if (pGo) + pGo->SetGoState(bUseAlternativeState ? GO_STATE_ACTIVE_ALTERNATIVE : GO_STATE_ACTIVE); + else + debug_log("SD2: DoOpenDoor attempt set data to object %u, but no this object", guid.GetCounter()); +} + +void ScriptedInstance::DoOpenDoor(uint32 uiEntry, bool bUseAlternativeState /*= false*/) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(uiEntry); + if (find != m_mGoEntryGuidStore.end()) + { + ObjectGuid guid = find->second; + DoOpenDoor(guid, bUseAlternativeState); + } + else + debug_log("SD2: Script call DoOpenDoor (by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); +} + +void ScriptedInstance::DoCloseDoor(ObjectGuid guid) +{ + if (guid.IsEmpty()) + return; + + GameObject* pGo = instance->GetGameObject(guid); + + if (pGo) + pGo->SetGoState(GO_STATE_READY); + else + debug_log("SD2: DoCloseDoor attempt set data to object %u, but no this object", guid.GetCounter()); +} + +void ScriptedInstance::DoCloseDoor(uint32 uiEntry) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(uiEntry); + if (find != m_mGoEntryGuidStore.end()) + { + ObjectGuid guid = find->second; + DoCloseDoor(guid); } + else + debug_log("SD2: Script call DoCloseDoor (by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); } -void ScriptedInstance::DoRespawnGameObject(uint64 uiGuid, uint32 uiTimeToDespawn) +/** + Function that respawns a despawned GameObject with given time + + @param guid The ObjectGuid of the GO that will be respawned + @param uiTimeToDespawn (in seconds) Despawn the GO after this time, default is a minute + */ +void ScriptedInstance::DoRespawnGameObject(ObjectGuid guid, uint32 uiTimeToDespawn) { - if (GameObject* pGo = instance->GetGameObject(uiGuid)) + if (!guid) + return; + + if (GameObject* pGo = instance->GetGameObject(guid)) { - //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) + // 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) return; if (pGo->isSpawned()) @@ -41,13 +118,62 @@ void ScriptedInstance::DoRespawnGameObject(uint64 uiGuid, uint32 uiTimeToDespawn } } +/// Function that uses a door or button that is stored in m_mGoEntryGuidStore +void ScriptedInstance::DoToggleGameObjectFlags(uint32 uiEntry, uint32 uiGOflags, bool bApply) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(uiEntry); + if (find != m_mGoEntryGuidStore.end()) + DoToggleGameObjectFlags(find->second, uiGOflags, bApply); + else + // Output log, possible reason is not added GO to storage, or not yet loaded + debug_log("SD2: Script call ToogleTameObjectFlags (by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); +} + +/** + Function that toggles the GO-flags of a GameObject + + @param guid The ObjectGuid of the GO that will be respawned + @param uiGOflags Which GO-flags to toggle + @param bApply should the GO-flags be applied or removed? + */ +void ScriptedInstance::DoToggleGameObjectFlags(ObjectGuid guid, uint32 uiGOflags, bool bApply) +{ + if (!guid) + return; + + if (GameObject* pGo = instance->GetGameObject(guid)) + { + if (bApply) + pGo->SetFlag(GAMEOBJECT_FLAGS, uiGOflags); + else + pGo->RemoveFlag(GAMEOBJECT_FLAGS, uiGOflags); + } +} + +/// Function that respawns a despawned GO that is stored in m_mGoEntryGuidStore +void ScriptedInstance::DoRespawnGameObject(uint32 uiEntry, uint32 uiTimeToDespawn) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(uiEntry); + if (find != m_mGoEntryGuidStore.end()) + DoRespawnGameObject(find->second, uiTimeToDespawn); + else + // Output log, possible reason is not added GO to storage, or not yet loaded; + debug_log("SD2: Script call DoRespawnGameObject(by Entry), but no gameobject of entry %u was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); +} + +/** + Helper function to update a world state for all players in the map + + @param uiStateId The WorldState that will be set for all players in the map + @param uiStateData The Value to which the State will be set to + */ void ScriptedInstance::DoUpdateWorldState(uint32 uiStateId, uint32 uiStateData) { Map::PlayerList const& lPlayers = instance->GetPlayers(); 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); @@ -56,3 +182,300 @@ void ScriptedInstance::DoUpdateWorldState(uint32 uiStateId, uint32 uiStateData) else debug_log("SD2: DoUpdateWorldState attempt send data but no players in map."); } + +void ScriptedInstance::DoCompleteAchievement(uint32 uiAchievmentId) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + if (!lPlayers.isEmpty()) + { + for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->CompletedAchievement(uiAchievmentId); + } + } + else + debug_log("SD2: DoCompleteAchievement attempt set data but no players in map."); +} +void ScriptedInstance::DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1 /*=0*/, uint32 miscvalue2 /*=0*/) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + if (!lPlayers.isEmpty()) + { + for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->UpdateAchievementCriteria(type, miscvalue1, miscvalue2); + } + } + else + debug_log("SD2: DoUpdateAchievementCriteria attempt set data but no players in map."); +} + +/// Get the first found Player* (with requested properties) in the map. Can return NULL. +Player* ScriptedInstance::GetPlayerInMap(bool bOnlyAlive /*=false*/, bool bCanBeGamemaster /*=true*/) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Player* pPlayer = itr->getSource(); + if (pPlayer && (!bOnlyAlive || pPlayer->isAlive()) && (bCanBeGamemaster || !pPlayer->isGameMaster())) + return pPlayer; + } + + return NULL; +} + +/// Returns a pointer to a loaded GameObject that was stored in m_mGoEntryGuidStore. Can return NULL +GameObject* ScriptedInstance::GetSingleGameObjectFromStorage(uint32 uiEntry) +{ + EntryGuidMap::iterator find = m_mGoEntryGuidStore.find(uiEntry); + if (find != m_mGoEntryGuidStore.end()) + return instance->GetGameObject(find->second); + + // Output log, possible reason is not added GO to map, or not yet loaded; + 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; +} + +/// Returns a pointer to a loaded Creature that was stored in m_mGoEntryGuidStore. Can return NULL +Creature* ScriptedInstance::GetSingleCreatureFromStorage(uint32 uiEntry, bool bSkipDebugLog /*=false*/) +{ + EntryGuidMap::iterator find = m_mNpcEntryGuidStore.find(uiEntry); + if (find != m_mNpcEntryGuidStore.end()) + return instance->GetCreature(find->second); + + // Output log, possible reason is not added GO to map, or not yet loaded; + if (!bSkipDebugLog) + 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; +} + +/** + Helper function to start a timed achievement criteria for players in the map + + @param criteriaType The Type that is required to complete the criteria, see enum AchievementCriteriaTypes in MaNGOS + @param uiTimedCriteriaMiscId The ID that identifies how the criteria is started + */ +void ScriptedInstance::DoStartTimedAchievement(AchievementCriteriaTypes criteriaType, uint32 uiTimedCriteriaMiscId) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + if (!lPlayers.isEmpty()) + { + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->StartTimedAchievementCriteria(criteriaType, uiTimedCriteriaMiscId); + } + } + else + debug_log("SD2: DoStartTimedAchievement attempt start achievements but no players in map."); +} + +/** + Constructor for DialogueHelper + + @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_pInstance(NULL), + m_pDialogueArray(pDialogueArray), + m_pCurrentEntry(NULL), + m_pDialogueTwoSideArray(NULL), + m_pCurrentEntryTwoSide(NULL), + m_uiTimer(0), + m_bIsFirstSide(true), + m_bCanSimulate(false) +{} + +/** + Constructor for DialogueHelper (Two Sides) + + @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_pInstance(NULL), + m_pDialogueArray(NULL), + m_pCurrentEntry(NULL), + m_pDialogueTwoSideArray(pDialogueTwoSideArray), + m_pCurrentEntryTwoSide(NULL), + m_uiTimer(0), + m_bIsFirstSide(true), + m_bCanSimulate(false) +{} + +/** + Function to start a (part of a) dialogue + + @param iTextEntry The TextEntry of the dialogue that will be started (must be always the entry of first side) + */ +void DialogueHelper::StartNextDialogueText(int32 iTextEntry) +{ + // Find iTextEntry + bool bFound = false; + + if (m_pDialogueArray) // One Side + { + for (DialogueEntry const* pEntry = m_pDialogueArray; pEntry->iTextEntry; ++pEntry) + { + if (pEntry->iTextEntry == iTextEntry) + { + m_pCurrentEntry = pEntry; + bFound = true; + break; + } + } + } + else // Two Sides + { + for (DialogueEntryTwoSide const* pEntry = m_pDialogueTwoSideArray; pEntry->iTextEntry; ++pEntry) + { + if (pEntry->iTextEntry == iTextEntry) + { + m_pCurrentEntryTwoSide = pEntry; + bFound = true; + break; + } + } + } + + if (!bFound) + { + 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; + } + + DoNextDialogueStep(); +} + +/// Internal helper function to do the actual say of a DialogueEntry +void DialogueHelper::DoNextDialogueStep() +{ + // Last Dialogue Entry done? + if ((m_pCurrentEntry && !m_pCurrentEntry->iTextEntry) || (m_pCurrentEntryTwoSide && !m_pCurrentEntryTwoSide->iTextEntry)) + { + m_uiTimer = 0; + return; + } + + // Get Text, SpeakerEntry and Timer + int32 iTextEntry = 0; + uint32 uiSpeakerEntry = 0; + + if (m_pDialogueArray) // One Side + { + uiSpeakerEntry = m_pCurrentEntry->uiSayerEntry; + iTextEntry = m_pCurrentEntry->iTextEntry; + + m_uiTimer = m_pCurrentEntry->uiTimer; + } + else // Two Sides + { + // Second Entries can be 0, if they are the entry from first side will be taken + uiSpeakerEntry = !m_bIsFirstSide && m_pCurrentEntryTwoSide->uiSayerEntryAlt ? m_pCurrentEntryTwoSide->uiSayerEntryAlt : m_pCurrentEntryTwoSide->uiSayerEntry; + iTextEntry = !m_bIsFirstSide && m_pCurrentEntryTwoSide->iTextEntryAlt ? m_pCurrentEntryTwoSide->iTextEntryAlt : m_pCurrentEntryTwoSide->iTextEntry; + + m_uiTimer = m_pCurrentEntryTwoSide->uiTimer; + } + + // Simulate Case + if (uiSpeakerEntry && iTextEntry < 0) + { + // Use Speaker if directly provided + Creature* pSpeaker = GetSpeakerByEntry(uiSpeakerEntry); + if (m_pInstance && !pSpeaker) // Get Speaker from instance + { + if (m_bCanSimulate) // Simulate case + m_pInstance->DoOrSimulateScriptTextForThisInstance(iTextEntry, uiSpeakerEntry); + else + pSpeaker = m_pInstance->GetSingleCreatureFromStorage(uiSpeakerEntry); + } + + if (pSpeaker) + DoScriptText(iTextEntry, pSpeaker); + } + + JustDidDialogueStep(m_pDialogueArray ? m_pCurrentEntry->iTextEntry : m_pCurrentEntryTwoSide->iTextEntry); + + // Increment position + if (m_pDialogueArray) + ++m_pCurrentEntry; + else + ++m_pCurrentEntryTwoSide; +} + +/// Call this function within any DialogueUpdate method. This is required for saying next steps in a dialogue +void DialogueHelper::DialogueUpdate(uint32 uiDiff) +{ + if (m_uiTimer) + { + if (m_uiTimer <= uiDiff) + DoNextDialogueStep(); + else + m_uiTimer -= uiDiff; + } +} + +void ScriptedInstance::DestroyItemFromAllPlayers(uint32 uiItemId) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + if (!lPlayers.isEmpty()) + { + for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + if (pPlayer->GetItemCount(uiItemId,true) > 0) + pPlayer->DestroyItemCount(uiItemId,pPlayer->GetItemCount(uiItemId),true); + } + } + else + error_log("SD2: DestroyItemFromAllPlayers attempt to remove item: %u but no players in map.", uiItemId); +} + +void ScriptedInstance::DoCastSpellOnPlayers(uint32 spellId, int32* bp0, int32* bp1, int32* bp2) +{ + Map::PlayerList const &lPlayers = instance->GetPlayers(); + if (!lPlayers.isEmpty()) + { + for (Map::PlayerList::const_iterator i = lPlayers.begin(); i != lPlayers.end(); ++i) + { + if (Player* player = i->getSource()) + { + if (bp0 || bp1 || bp2) + player->CastCustomSpell(player, spellId, bp0, bp1, bp2, true); + else + player->CastSpell(player, spellId, true); + } + } + } + else + error_log("SD2: DoCastSpellOnPlayers attempt to cast spell: %u but no players in map.", spellId); +} + +void ScriptedInstance::DoRemoveAurasDueToSpellOnPlayers(uint32 spellId) +{ + Map::PlayerList const &lPlayers = instance->GetPlayers(); + if (!lPlayers.isEmpty()) + { + for (Map::PlayerList::const_iterator i = lPlayers.begin(); i != lPlayers.end(); ++i) + if (Player* player = i->getSource()) + player->RemoveAurasDueToSpell(spellId); + } + else + error_log("SD2: DoRemoveAurasDueToSpellOnPlayers attempt to remove auras due to spell: %u but no players in map.", spellId); +} + +void ScriptedInstance::DoSetAlternativePowerOnPlayers(int32 amt) +{ + Map::PlayerList const &lPlayers = instance->GetPlayers(); + for (Map::PlayerList::const_iterator i = lPlayers.begin(); i != lPlayers.end(); ++i) + if (Player* player = i->getSource()) + player->SetPower(POWER_ALTERNATIVE, amt); +} diff --git a/include/sc_instance.h b/include/sc_instance.h index 8faacc1a79..03957d803c 100644 --- a/include/sc_instance.h +++ b/include/sc_instance.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -20,23 +20,137 @@ enum EncounterState #define OUT_SAVE_INST_DATA debug_log("SD2: Saving Instance Data for Instance %s (Map %d, Instance Id %d)", instance->GetMapName(), instance->GetId(), instance->GetInstanceId()) #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_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 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 { public: - ScriptedInstance(Map* pMap) : InstanceData(pMap) {} - ~ScriptedInstance() {} + virtual ~ScriptedInstance() {} + + // Default accessor functions + GameObject* GetSingleGameObjectFromStorage(uint32 uiEntry); + Creature* GetSingleCreatureFromStorage(uint32 uiEntry, bool bSkipDebugLog = false); + + // Change active state of doors or buttons + void DoUseDoorOrButton(ObjectGuid guid, uint32 uiWithRestoreTime = 0, bool bUseAlternativeState = false); + void DoUseDoorOrButton(uint32 uiEntry, uint32 uiWithRestoreTime = 0, bool bUseAlternativeState = false); + void DoOpenDoor(ObjectGuid guid, bool bUseAlternativeState = false); + void DoOpenDoor(uint32 uiEntry, bool bUseAlternativeState = false); + void DoCloseDoor(ObjectGuid guid); + void DoCloseDoor(uint32 uiEntry); - //change active state of doors or buttons - void DoUseDoorOrButton(uint64 uiGuid, uint32 uiWithRestoreTime = 0, bool bUseAlternativeState = false); + // Respawns a GO having negative spawntimesecs in gameobject-table + void DoRespawnGameObject(ObjectGuid guid, uint32 uiTimeToDespawn = MINUTE); + void DoRespawnGameObject(uint32 uiEntry, uint32 uiTimeToDespawn = MINUTE); - //Respawns a GO having negative spawntimesecs in gameobject-table - void DoRespawnGameObject(uint64 uiGuid, uint32 uiTimeToDespawn = MINUTE); + // Toggle the flags of a GO + void DoToggleGameObjectFlags(ObjectGuid guid, uint32 uiGOflags, bool bApply); + void DoToggleGameObjectFlags(uint32 uiEntry, uint32 uiGOflags, bool bApply); - //sends world state update to all players in instance + // Sends world state update to all players in instance void DoUpdateWorldState(uint32 uiStateId, uint32 uiStateData); + + // Sends completed achievments to all players in instance + void DoCompleteAchievement(uint32 uiAchievmentId); + + // Sends achievment criteria update to all players in instance + void DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1 = 0, uint32 miscvalue2 = 0); + + // Get a Player from map + Player* GetPlayerInMap(bool bOnlyAlive = false, bool bCanBeGamemaster = true); + + // Destroys an item from all players in this instance (encounters like Vashj, Najentus....) + void DestroyItemFromAllPlayers(uint32 uiItemId); + + /// Wrapper for simulating map-wide text in this instance. It is expected that the Creature is stored in m_mNpcEntryGuidStore if loaded. + void DoOrSimulateScriptTextForThisInstance(int32 iTextEntry, uint32 uiCreatureEntry) + { + // Prevent debug output in GetSingleCreatureFromStorage + DoOrSimulateScriptTextForMap(iTextEntry, uiCreatureEntry, instance, GetSingleCreatureFromStorage(uiCreatureEntry, true)); + } + + void DoCastSpellOnPlayers(uint32 spellId, int32* bp0 = NULL, int32* bp1 = NULL, int32* bp2 = NULL); + void DoRemoveAurasDueToSpellOnPlayers(uint32 spellId); + void DoSetAlternativePowerOnPlayers(int32 amt); + + // Starts a timed achievement criteria for all players in instance + void DoStartTimedAchievement(AchievementCriteriaTypes criteriaType, uint32 uiTimedCriteriaMiscId); + + virtual bool SetBossState(uint32 id, EncounterState state) { return true; } + void SendEncounterUnit(uint32 type, Unit* unit = NULL, uint8 param1 = 0, uint8 param2 = 0) { } + + 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 +{ + public: + ScriptedMap(Map* pMap) : ScriptedInstance(pMap) {} + virtual ~ScriptedMap() {} +}; + +/// A static const array of this structure must be handled to DialogueHelper +struct DialogueEntry +{ + int32 iTextEntry; ///< To be said text entry + uint32 uiSayerEntry; ///< Entry of the mob who should say + uint32 uiTimer; ///< Time delay until next text of array is said (0 stops) +}; + +/// A static const array of this structure must be handled to DialogueHelper +struct DialogueEntryTwoSide +{ + int32 iTextEntry; ///< To be said text entry (first side) + uint32 uiSayerEntry; ///< Entry of the mob who should say (first side) + int32 iTextEntryAlt; ///< To be said text entry (second side) + uint32 uiSayerEntryAlt; ///< Entry of the mob who should say (second side) + uint32 uiTimer; ///< Time delay until next text of array is said (0 stops) +}; + +/// Helper class handling a dialogue given as static const array of DialogueEntry or DialogueEntryTwoSide +class DialogueHelper +{ + public: + // The array MUST be terminated by {0,0,0} + DialogueHelper(DialogueEntry const* pDialogueArray); + // The array MUST be terminated by {0,0,0,0,0} + DialogueHelper(DialogueEntryTwoSide const* aDialogueTwoSide); + + /// Function to initialize the dialogue helper for instances. If not used with instances, GetSpeakerByEntry MUST be overwritten to obtain the speakers + void InitializeDialogueHelper(ScriptedInstance* pInstance, bool bCanSimulateText = false) { m_pInstance = pInstance; m_bCanSimulate = bCanSimulateText; } + /// Set if take first entries or second entries + void SetDialogueSide(bool bIsFirstSide) { m_bIsFirstSide = bIsFirstSide; } + + void StartNextDialogueText(int32 iTextEntry); + + void DialogueUpdate(uint32 uiDiff); + + protected: + /// Will be called when a dialogue step was done + 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; } + + private: + void DoNextDialogueStep(); + + ScriptedInstance* m_pInstance; + + DialogueEntry const* m_pDialogueArray; + DialogueEntry const* m_pCurrentEntry; + DialogueEntryTwoSide const* m_pDialogueTwoSideArray; + DialogueEntryTwoSide const* m_pCurrentEntryTwoSide; + + uint32 m_uiTimer; + bool m_bIsFirstSide; + bool m_bCanSimulate; +}; + #endif diff --git a/include/sc_timer.cpp b/include/sc_timer.cpp new file mode 100644 index 0000000000..4ec14ae293 --- /dev/null +++ b/include/sc_timer.cpp @@ -0,0 +1,34 @@ +/* Copyright (C) 2013 by boxa for ScriptDev2_R2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#include "precompiled.h" + +bool TTimer::Expired(uint32 const tickDiff) +{ + m_counter += tickDiff; + if (m_counter >= m_period) + { + if (m_autoReset) + m_counter = 0; + return true; + } + return false; +} + +void TTimer::Reset(uint32 const period) +{ + m_period = period; + m_counter = 0; +} + +void TTimer::Reset(uint32 const periodMin, uint32 const periodMax) +{ + Reset(urand(periodMin, periodMax)); +} + +void TTimer::ResetAuto(uint32 const period) +{ + Reset(period); + m_autoReset = true; +} diff --git a/include/sc_timer.h b/include/sc_timer.h new file mode 100644 index 0000000000..ea7f419002 --- /dev/null +++ b/include/sc_timer.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2013 by boxa for ScriptDev2_R2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_TIMER_H +#define SC_TIMER_H + +class TTimer +{ + public: + TTimer() : m_period(1000), m_counter(0), m_autoReset(false) {} + + void Reset() { m_counter = 0; } + void Reset(uint32 const period); + void Reset(uint32 const periodMin, uint32 const periodMax); + void ResetAuto(uint32 const period); + + bool Expired(uint32 const tickDiff); + + void Update(uint32 const tickDiff) { m_counter += tickDiff; } + bool IsExpired() const { return m_counter >= m_period; } + bool IsSet() const { return m_period > 0; } + + void SetAutoReset(bool const autoReset) { m_autoReset = autoReset; } + bool GetAutoReset() const { return m_autoReset; } + + uint32 GetPeriod() const { return m_period; } + uint32 GetCounter() const { return m_counter; } + + private: + uint32 m_period; + uint32 m_counter; + bool m_autoReset; +}; + +#endif diff --git a/include/sc_utility.cpp b/include/sc_utility.cpp new file mode 100644 index 0000000000..331c3112f3 --- /dev/null +++ b/include/sc_utility.cpp @@ -0,0 +1,247 @@ +#include "precompiled.h" + +//--- EventManager -------------------------------------------------- + +void EventManager::Cooldown::Update(uint32 time_diff) +{ + if (!remaining) + return; + if (remaining <= time_diff) + duration = remaining = 0; + else + remaining -= time_diff; +} + +EventManager::EventManager(): + m_time(0), m_phase(0) +{ +} + +void EventManager::InsertEvent(uint32 time_diff, Event const& ev) +{ + m_events.insert(EventContainer::value_type(m_time + time_diff, ev)); +} + +uint32 EventManager::GetCooldownDuration(uint32 categ) const +{ + CooldownMap::const_iterator i_cd = m_cooldowns.find(categ); + if (i_cd == m_cooldowns.end()) + return 0; + return i_cd->second.duration; +} + +uint32 EventManager::GetCooldownTime(uint32 categ) const +{ + CooldownMap::const_iterator i_cd = m_cooldowns.find(categ); + if (i_cd == m_cooldowns.end()) + return 0; + return i_cd->second.remaining; +} + +void EventManager::Reset() +{ + m_time = m_phase = 0; + m_events.clear(); + m_cooldowns.clear(); +} + +void EventManager::ResetCooldowns() +{ + m_cooldowns.clear(); +} + +void EventManager::Update(uint32 time_diff) +{ + m_time += time_diff; + for (CooldownMap::iterator i = m_cooldowns.begin(); i != m_cooldowns.end(); ++i) + i->second.Update(time_diff); +} + +void EventManager::SetPhase(uint32 phase) +{ + if (phase >= 32) + throw std::domain_error("EventManager::SetPhase(): phase value must be < 32"); + m_phase = phase; +} + +void EventManager::SetCooldown(uint32 time, uint32 categ) +{ + m_cooldowns[categ] = Cooldown(time); +} + +void EventManager::ScheduleEvent(uint32 event_id, uint32 time, uint32 period, uint32 cd, uint32 cd_cat, uint32 phase_mask) +{ + if (!event_id) + throw std::invalid_argument("EventManager::ScheduleEvent(): event_id must be != 0"); + if (!phase_mask) + throw std::invalid_argument("EventManager::ScheduleEvent(): phase_mask must be != 0"); + InsertEvent(time, Event(event_id, period, period, phase_mask, cd, cd_cat)); +} + +void EventManager::RescheduleEvent(uint32 event_id, uint32 time, uint32 period, uint32 cd, uint32 cd_cat, uint32 phase_mask) +{ + CancelEvent(event_id); + ScheduleEvent(event_id, time, period, cd, cd_cat, phase_mask); +} + +void EventManager::ScheduleEventInRange(uint32 event_id, uint32 time_min, uint32 time_max, uint32 period_min, uint32 period_max, uint32 cd, uint32 cd_cat, uint32 phase_mask) +{ + if (!event_id) + throw std::invalid_argument("EventManager::ScheduleEventInRange(): event_id must be != 0"); + if (!phase_mask) + throw std::invalid_argument("EventManager::ScheduleEventInRange(): phase_mask must be != 0"); + if (!time_max) + time_max = time_min; + if (!period_max) + period_max = period_min; + if (time_max < time_min) + throw std::invalid_argument("EventManager::ScheduleEventInRange(): time_max must be >= time_min"); + if (period_max < period_min) + throw std::invalid_argument("EventManager::ScheduleEventInRange(): period_max must be >= period_min"); + if (!period_min && period_max) + throw std::invalid_argument("EventManager::ScheduleEventInRange(): period range must not include 0"); + uint32 time = time_min != time_max ? urand(time_min, time_max) : time_min; + InsertEvent(time, Event(event_id, period_min, period_max, phase_mask, cd, cd_cat)); +} + +void EventManager::RescheduleEventInRange(uint32 event_id, uint32 time_min, uint32 time_max, uint32 period_min, uint32 period_max, uint32 cd, uint32 cd_cat, uint32 phase_mask) +{ + CancelEvent(event_id); + ScheduleEventInRange(event_id, time_min, time_max, period_min, period_max, cd, cd_cat, phase_mask); +} + +bool EventManager::HasEvent(uint32 time) const +{ + EventContainer::const_iterator i_ev = m_events.begin(); + if (i_ev == m_events.end()) + return false; + return i_ev->first <= m_time + time; +} + +uint32 EventManager::GetNextEvent() const +{ + EventContainer::const_iterator i_ev = m_events.begin(); + if (i_ev == m_events.end()) + return 0; + return i_ev->second.id; +} + +void EventManager::CancelAllEvents() +{ + m_events.clear(); +} + +void EventManager::CancelEvent(uint32 event_id, uint32 phase_mask) +{ + for (EventContainer::iterator i = m_events.begin(); i != m_events.end(); ) + if (i->second.id == event_id && i->second.phase_mask & phase_mask) + { + m_events.erase(i); + i = m_events.begin(); + } + else + ++i; +} + +void EventManager::CancelNextEvent() +{ + EventContainer::iterator i_ev = m_events.begin(); + if (i_ev == m_events.end()) + return; + m_events.erase(i_ev); +} + +void EventManager::CancelNextEventWithId(uint32 event_id, uint32 phase_mask) +{ + for (EventContainer::iterator i = m_events.begin(); i != m_events.end(); ++i) + if (i->second.id == event_id && i->second.phase_mask & phase_mask) + { + m_events.erase(i); + break; + } +} + +void EventManager::CancelEventsWithCategory(uint32 categ, uint32 phase_mask) +{ + for (EventContainer::iterator i = m_events.begin(); i != m_events.end(); ) + if (i->second.category == categ && i->second.phase_mask & phase_mask) + { + m_events.erase(i); + i = m_events.begin(); + } + else + ++i; +} + +void EventManager::DelayEvents(uint32 time, uint32 phase_mask) +{ + EventContainer delayed; + for (EventContainer::iterator i = m_events.begin(); i != m_events.end(); ) + if (i->second.phase_mask & phase_mask) + { + delayed.insert(std::make_pair(i->first + time, i->second)); + m_events.erase(i); + i = m_events.begin(); + } + else + ++i; + m_events.insert(delayed.begin(), delayed.end()); +} + +void EventManager::DelayEventsWithId(uint32 event_id, uint32 time, uint32 phase_mask) +{ + EventContainer delayed; + for (EventContainer::iterator i = m_events.begin(); i != m_events.end(); ) + if (i->second.id == event_id && i->second.phase_mask & phase_mask) + { + delayed.insert(std::make_pair(i->first + time, i->second)); + m_events.erase(i); + i = m_events.begin(); + } + else + ++i; + m_events.insert(delayed.begin(), delayed.end()); +} + +uint32 EventManager::ExecuteEvent() +{ + EventContainer::iterator i_ev = m_events.begin(); + // container empty, no events to process + if (i_ev == m_events.end()) + return 0; + // we got a event to process, executing + if (i_ev->first <= m_time) + { + uint32 delta = m_time - i_ev->first; // latency time in executing this event + Event ev = i_ev->second; + m_events.erase(i_ev); + // if event is periodic, calculate next execution time + uint32 period = ev.period_min != ev.period_max ? urand(ev.period_min, ev.period_max) : ev.period_min; + if (period) + { + delta %= period; // in case we took way too long, get difference counting lost ticks + InsertEvent(period - delta, ev); + } + // check if can be executed in current phase + if (!(ev.phase_mask & GetPhaseMask())) + return 0; + // if we're on cooldown then cannot execute event + CooldownMap::const_iterator i_cd = m_cooldowns.find(ev.category); + if (i_cd != m_cooldowns.end() && i_cd->second.remaining) + { + // try again after cooldown ends, but don't wait longer than remaining period time + if (!period || (i_cd->second.duration < period && i_cd->second.remaining < period - delta)) + { + ev.period_min = ev.period_max = 0; + InsertEvent(i_cd->second.remaining, ev); + } + return 0; + } + // all ok, now trigger cooldown if any + SetCooldown(ev.cooldown, ev.category); + // return succeful event executed + return ev.id; + } + // all events in future, nothing to do for now + return 0; +} diff --git a/include/sc_utility.h b/include/sc_utility.h new file mode 100644 index 0000000000..352ee25995 --- /dev/null +++ b/include/sc_utility.h @@ -0,0 +1,124 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_UTILITY_H +#define SC_UTILITY_H + +// class for handling timed events +class MANGOS_DLL_DECL EventManager +{ +protected: + struct Event + { + uint32 id; // event identifier + uint32 period_min; // repeating period (0 = doesn't repeat) + uint32 period_max; // random value in interval 'period_min' to 'period_max' + uint32 phase_mask; // phases where this event can happen (bit mask) + uint32 cooldown; // cooldown triggered after event executes + uint32 category; // cooldown category (will trigger cd only for this category) + + Event(uint32 _id, uint32 _pmin, uint32 _pmax, uint32 _phase, uint32 _cd, uint32 _cat): + id(_id), period_min(_pmin), period_max(_pmax), phase_mask(_phase), cooldown(_cd), category(_cat) + { + } + }; + + struct Cooldown + { + uint32 duration; // total length of the cooldown + uint32 remaining; // remaining time + + explicit Cooldown(uint32 _val = 0): + duration(_val), remaining(_val) + { + } + + void Update(uint32 time_diff); + }; + + typedef std::multimap EventContainer; + typedef std::map CooldownMap; + + uint32 m_time; // current elapsed time (in milliseconds) + uint32 m_phase; // current phase (value, not mask) + EventContainer m_events; // event queue + CooldownMap m_cooldowns; // cooldowns by category + + void InsertEvent(uint32 time_diff, Event const& ev); + +public: + enum { ALL_PHASES = 0xFFFFFFFF }; // default value for phase mask + + EventManager(); + + uint32 GetTimer() const { return m_time; } + uint32 GetPhase() const { return m_phase; } + uint32 GetPhaseMask() const { return 1 << m_phase; } + uint32 GetCooldownDuration(uint32 categ) const; + uint32 GetCooldownTime(uint32 categ) const; + + void Reset(); + void ResetCooldowns(); + + void Update(uint32 time_diff); + void SetPhase(uint32 phase); + void SetCooldown(uint32 time, uint32 categ = 0); + + // inserts an event in the queue that will execute in the next 'time' milliseconds and + // will repeat every 'period' milliseconds (if not 0). Each triggering of this event + // will cause a cooldown of 'cd' milliseconds on the 'cd_cat' category + void ScheduleEvent(uint32 event_id, uint32 time, uint32 period = 0, uint32 cd = 0, uint32 cd_cat = 0, uint32 phase_mask = ALL_PHASES); + // cancels pending events with the specified id and inserts new one into the queue + void RescheduleEvent(uint32 event_id, uint32 time, uint32 period = 0, uint32 cd = 0, uint32 cd_cat = 0, uint32 phase_mask = ALL_PHASES); + + // schedule event with random time interval + // if the _max value is 0, then its assumed no range (value equal to _min) + void ScheduleEventInRange(uint32 event_id, uint32 time_min, uint32 time_max = 0, uint32 period_min = 0, uint32 period_max = 0, uint32 cd = 0, uint32 cd_cat = 0, uint32 phase_mask = ALL_PHASES); + void RescheduleEventInRange(uint32 event_id, uint32 time_min, uint32 time_max = 0, uint32 period_min = 0, uint32 period_max = 0, uint32 cd = 0, uint32 cd_cat = 0, uint32 phase_mask = ALL_PHASES); + + bool HasEvent(uint32 time = 0) const; // check if there is a pending event in the next 'time' milliseconds + uint32 GetNextEvent() const; // returns next queued event + + void CancelAllEvents(); // cancels all events + void CancelEvent(uint32 event_id, uint32 phase_mask = ALL_PHASES); // ^ with specified id + void CancelNextEvent(); // cancels next queued event + void CancelNextEventWithId(uint32 event_id, uint32 phase_mask = ALL_PHASES); // ^ with specified id + void CancelEventsWithCategory(uint32 categ, uint32 phase_mask = ALL_PHASES); // cancels all events with specified cd category + + void DelayEvents(uint32 time, uint32 phase_mask = ALL_PHASES); // delays all events by the specified amount + void DelayEventsWithId(uint32 event_id, uint32 time, uint32 phase_mask = ALL_PHASES); // ^ with specified id + + uint32 ExecuteEvent(); // process and return next pending event + +private: + EventManager(EventManager const&); + EventManager& operator= (EventManager const&); +}; + +// helper for calculating bit masks (compile time constant that can be used in enums) +// usage: bit_mask::value +template +struct bit_mask { enum { value = 1UL << N1 | bit_mask::value }; }; + +template <> +struct bit_mask<-1, -1, -1, -1, -1, -1> { enum { value = 0 }; }; + +struct StaticLocation +{ + float x, y, z, o; +}; + +struct EventLocations +{ + float m_fX, m_fY, m_fZ, m_fO; + uint32 m_uiEntry; +}; + +struct SpawnLocation +{ + uint32 m_uiEntry; + float m_fX, m_fY, m_fZ, m_fO; +}; + +#endif // SC_UTILITY_H diff --git a/patches/MaNGOS-11167-ScriptDev2.patch b/patches/MaNGOS-11167-ScriptDev2.patch new file mode 100644 index 0000000000..c0388de943 --- /dev/null +++ b/patches/MaNGOS-11167-ScriptDev2.patch @@ -0,0 +1,22 @@ +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/patches/MaNGOS-9519-ScriptDev2.patch b/patches/MaNGOS-9519-ScriptDev2.patch deleted file mode 100644 index 50b80dd034..0000000000 --- a/patches/MaNGOS-9519-ScriptDev2.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 3a3dda6636d81c33c3c9b143f64b5a518bfadb56 Mon Sep 17 00:00:00 2001 -From: Reve -Date: Fri, 5 Mar 2010 21:41:55 +0100 -Subject: [PATCH] ScriptDev2 patch. - ---- - configure.ac | 6 +++++- - src/bindings/Makefile.am | 2 +- - src/mangosd/Makefile.am | 4 ++-- - 3 files changed, 8 insertions(+), 4 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 90b332a..c31ff26 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -308,7 +308,11 @@ AC_CONFIG_FILES([ - src/mangosd/Makefile - src/mangosd/mangosd.conf.dist - src/bindings/Makefile -- src/bindings/universal/Makefile -+ src/bindings/ScriptDev2/Makefile -+ src/bindings/ScriptDev2/scriptdev2.conf.dist -+ src/bindings/ScriptDev2/config.h -+ src/bindings/ScriptDev2/sql/Makefile -+ src/bindings/ScriptDev2/sql/Updates/Makefile - ]) - - ## Configure ACE, if needed -diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am -index d7dc654..79ea910 100644 ---- a/src/bindings/Makefile.am -+++ b/src/bindings/Makefile.am -@@ -14,4 +14,4 @@ - # along with this program; if not, write to the Free Software - # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - --SUBDIRS = universal -+SUBDIRS = ScriptDev2 -diff --git a/src/mangosd/Makefile.am b/src/mangosd/Makefile.am -index fe1ace1..40b6fdd 100644 ---- a/src/mangosd/Makefile.am -+++ b/src/mangosd/Makefile.am -@@ -40,7 +40,7 @@ mangos_worldd_SOURCES = \ - - ## Link world daemon against the shared library - mangos_worldd_LDADD = \ -- ../bindings/universal/libmangosscript.la \ -+ ../bindings/ScriptDev2/libmangosscript.la \ - ../game/libmangosgame.a \ - ../shared/Database/libmangosdatabase.a \ - ../shared/Config/libmangosconfig.a \ -@@ -51,7 +51,7 @@ mangos_worldd_LDADD = \ - ../../dep/src/g3dlite/libg3dlite.a \ - ../../dep/src/gsoap/libgsoap.a - --mangos_worldd_LDFLAGS = -L../../dep/src/g3dlite -L../../dep/src/gsoap -L../bindings/universal/ -L$(libdir) $(MANGOS_LIBS) -export-dynamic -+mangos_worldd_LDFLAGS = -L../../dep/src/g3dlite -L../../dep/src/gsoap -L../bindings/ScriptDev2/ -L$(libdir) $(MANGOS_LIBS) -export-dynamic - - ## Additional files to include when running 'make dist' - # Include world daemon configuration --- -1.6.5.1.1367.gcd48 - diff --git a/patches/custom/ScriptDev2_1835_to_MaNGOS_0.12.patch b/patches/custom/ScriptDev2_1835_to_MaNGOS_0.12.patch deleted file mode 100644 index e67d0e8b91..0000000000 --- a/patches/custom/ScriptDev2_1835_to_MaNGOS_0.12.patch +++ /dev/null @@ -1,284 +0,0 @@ -Index: include/precompiled.h -=================================================================== ---- include/precompiled.h (revision 1838) -+++ include/precompiled.h (working copy) -@@ -11,6 +11,11 @@ - #include "sc_grid_searchers.h" - #include "sc_instance.h" - -+enum backports -+{ -+ UNIT_VIRTUAL_ITEM_SLOT_ID = UNIT_VIRTUAL_ITEM_SLOT_DISPLAY -+}; -+ - #ifdef WIN32 - # include - BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -Index: scripts/kalimdor/azuremyst_isle.cpp -=================================================================== ---- scripts/kalimdor/azuremyst_isle.cpp (revision 1838) -+++ scripts/kalimdor/azuremyst_isle.cpp (working copy) -@@ -103,7 +103,7 @@ - - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) - { -- if (pSpell->SpellFamilyFlags2 & 0x080000000) -+ if (pSpell->Id == 28880) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); -Index: scripts/kalimdor/onyxias_lair/boss_onyxia.cpp -=================================================================== ---- scripts/kalimdor/onyxias_lair/boss_onyxia.cpp (revision 1838) -+++ scripts/kalimdor/onyxias_lair/boss_onyxia.cpp (working copy) -@@ -299,7 +299,7 @@ - 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->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND/* | UNIT_BYTE1_FLAG_UNK_2*/); - m_creature->AddSplineFlag(SPLINEFLAG_FLYING); - - if (m_pPointData) -Index: scripts/northrend/dragonblight.cpp -=================================================================== ---- scripts/northrend/dragonblight.cpp (revision 1838) -+++ scripts/northrend/dragonblight.cpp (working copy) -@@ -101,7 +101,7 @@ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); -- pPlayer->SendMovieStart(MOVIE_ID_GATES); -+// pPlayer->SendMovieStart(MOVIE_ID_GATES); - } - - return true; -Index: scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp -=================================================================== ---- scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp (revision 1838) -+++ scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp (working copy) -@@ -107,10 +107,10 @@ - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MOONFIRE); - m_uiSpellTimer = 10000; - break; -- case CLASS_DEATH_KNIGHT: -- DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE); -- m_uiSpellTimer = 10000; -- break; -+// case CLASS_DEATH_KNIGHT: -+// DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE); -+// m_uiSpellTimer = 10000; -+// break; - } - } - else -Index: scripts/world/item_scripts.cpp -=================================================================== ---- scripts/world/item_scripts.cpp (revision 1838) -+++ scripts/world/item_scripts.cpp (working copy) -@@ -47,7 +47,7 @@ - pPlayer->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); - - if (const SpellEntry* pSpellInfo = GetSpellStore()->LookupEntry(SPELL_ARCANE_CHARGES)) -- Spell::SendCastResult(pPlayer, pSpellInfo, 1, SPELL_FAILED_NOT_ON_GROUND); -+ Spell::SendCastResult(pPlayer, pSpellInfo, 1, SPELL_FAILED_ERROR); - - return true; - } -Index: scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp -=================================================================== ---- scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp (revision 1838) -+++ scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp (working copy) -@@ -91,10 +91,10 @@ - else - DoScriptText(EMOTE_UNLOCK_DOOR_AD, m_creature); - break; -- case 12: -- if (m_uiNpcEntry != NPC_ASH) -- m_creature->HandleEmote(EMOTE_ONESHOT_USESTANDING); -- break; -+// case 12: -+// if (m_uiNpcEntry != NPC_ASH) -+// m_creature->HandleEmote(EMOTE_ONESHOT_USESTANDING); -+// break; - case 13: - if (m_uiNpcEntry == NPC_ASH) - DoScriptText(SAY_POST_DOOR_AS, m_creature); -Index: system/ScriptLoader.cpp -=================================================================== ---- system/ScriptLoader.cpp (revision 1838) -+++ system/ScriptLoader.cpp (working copy) -@@ -263,85 +263,8 @@ - extern void AddSC_winterspring(); - - //northrend --extern void AddSC_boss_jedoga(); //ahnkahet --extern void AddSC_boss_nadox(); --extern void AddSC_boss_taldaram(); --extern void AddSC_boss_volazj(); --extern void AddSC_instance_ahnkahet(); --extern void AddSC_boss_anubarak(); //azjol-nerub --extern void AddSC_boss_hadronox(); --extern void AddSC_boss_krikthir(); --extern void AddSC_instance_azjol_nerub(); --extern void AddSC_boss_anubarak_trial(); //trial_of_the_crusader --extern void AddSC_boss_jaraxxus(); --extern void AddSC_instance_trial_of_the_crusader(); --extern void AddSC_northrend_beasts(); --extern void AddSC_trial_of_the_crusader(); --extern void AddSC_twin_valkyr(); --extern void AddSC_boss_novos(); //draktharon_keep --extern void AddSC_boss_tharonja(); --extern void AddSC_boss_trollgore(); --extern void AddSC_boss_colossus(); //gundrak --extern void AddSC_boss_galdarah(); --extern void AddSC_boss_moorabi(); --extern void AddSC_boss_sladran(); --extern void AddSC_instance_gundrak(); --extern void AddSC_boss_bronjahm(); // ICC, forge_of_souls --extern void AddSC_boss_devourer_of_souls(); --extern void AddSC_instance_forge_of_souls(); --extern void AddSC_boss_anubrekhan(); //naxxramas --extern void AddSC_boss_four_horsemen(); --extern void AddSC_boss_faerlina(); --extern void AddSC_boss_gluth(); --extern void AddSC_boss_gothik(); --extern void AddSC_boss_kelthuzad(); --extern void AddSC_boss_loatheb(); --extern void AddSC_boss_maexxna(); --extern void AddSC_boss_noth(); --extern void AddSC_boss_heigan(); --extern void AddSC_boss_patchwerk(); --extern void AddSC_boss_razuvious(); --extern void AddSC_boss_sapphiron(); --extern void AddSC_instance_naxxramas(); --extern void AddSC_boss_anomalus(); //nexus --extern void AddSC_boss_keristrasza(); --extern void AddSC_boss_ormorok(); --extern void AddSC_boss_telestra(); --extern void AddSC_instance_nexus(); --extern void AddSC_boss_sartharion(); //obsidian_sanctum --extern void AddSC_instance_obsidian_sanctum(); --extern void AddSC_boss_bjarngrim(); //Ulduar, halls_of_lightning --extern void AddSC_boss_ionar(); --extern void AddSC_boss_loken(); --extern void AddSC_boss_volkhan(); --extern void AddSC_instance_halls_of_lightning(); --extern void AddSC_boss_maiden_of_grief(); //Ulduar, halls_of_stone --extern void AddSC_boss_sjonnir(); --extern void AddSC_halls_of_stone(); --extern void AddSC_instance_halls_of_stone(); --extern void AddSC_instance_ulduar(); //ulduar --extern void AddSC_boss_ingvar(); //utgarde_keep --extern void AddSC_boss_keleseth(); --extern void AddSC_boss_skarvald_and_dalronn(); --extern void AddSC_instance_utgarde_keep(); --extern void AddSC_utgarde_keep(); --extern void AddSC_boss_gortok(); //utgarde_pinnacle --extern void AddSC_boss_skadi(); --extern void AddSC_boss_svala(); --extern void AddSC_boss_ymiron(); --extern void AddSC_instance_pinnacle(); --extern void AddSC_instance_violet_hold(); //violet_hold --extern void AddSC_violet_hold(); -+// removed - --extern void AddSC_borean_tundra(); --extern void AddSC_dalaran(); --extern void AddSC_dragonblight(); --extern void AddSC_howling_fjord(); --extern void AddSC_icecrown(); --extern void AddSC_sholazar_basin(); --extern void AddSC_storm_peaks(); --extern void AddSC_zuldrak(); -- - //outland - extern void AddSC_boss_exarch_maladaar(); //auchindoun, auchenai_crypts - extern void AddSC_boss_nexusprince_shaffar(); //auchindoun, mana_tombs -@@ -681,85 +604,8 @@ - AddSC_winterspring(); - - //northrend -- AddSC_boss_jedoga(); //ahnkahet -- AddSC_boss_nadox(); -- AddSC_boss_taldaram(); -- AddSC_boss_volazj(); -- AddSC_instance_ahnkahet(); -- AddSC_boss_anubarak(); //azjol-nerub -- AddSC_boss_hadronox(); -- AddSC_boss_krikthir(); -- AddSC_instance_azjol_nerub(); -- AddSC_boss_anubarak_trial(); //trial_of_the_crusader -- AddSC_boss_jaraxxus(); -- AddSC_instance_trial_of_the_crusader(); -- AddSC_northrend_beasts(); -- AddSC_trial_of_the_crusader(); -- AddSC_twin_valkyr(); -- AddSC_boss_novos(); //draktharon_keep -- AddSC_boss_tharonja(); -- AddSC_boss_trollgore(); -- AddSC_boss_colossus(); //gundrak -- AddSC_boss_galdarah(); -- AddSC_boss_moorabi(); -- AddSC_boss_sladran(); -- AddSC_instance_gundrak(); -- AddSC_boss_bronjahm(); // ICC, forge_of_souls -- AddSC_boss_devourer_of_souls(); -- AddSC_instance_forge_of_souls(); -- AddSC_boss_anubrekhan(); //naxxramas -- AddSC_boss_four_horsemen(); -- AddSC_boss_faerlina(); -- AddSC_boss_gluth(); -- AddSC_boss_gothik(); -- AddSC_boss_kelthuzad(); -- AddSC_boss_loatheb(); -- AddSC_boss_maexxna(); -- AddSC_boss_noth(); -- AddSC_boss_heigan(); -- AddSC_boss_patchwerk(); -- AddSC_boss_razuvious(); -- AddSC_boss_sapphiron(); -- AddSC_instance_naxxramas(); -- AddSC_boss_anomalus(); //nexus -- AddSC_boss_keristrasza(); -- AddSC_boss_ormorok(); -- AddSC_boss_telestra(); -- AddSC_instance_nexus(); -- AddSC_boss_sartharion(); //obsidian_sanctum -- AddSC_instance_obsidian_sanctum(); -- AddSC_boss_bjarngrim(); //Ulduar, halls_of_lightning -- AddSC_boss_ionar(); -- AddSC_boss_loken(); -- AddSC_boss_volkhan(); -- AddSC_instance_halls_of_lightning(); -- AddSC_boss_maiden_of_grief(); //Ulduar, halls_of_stone -- AddSC_boss_sjonnir(); -- AddSC_halls_of_stone(); -- AddSC_instance_halls_of_stone(); -- AddSC_instance_ulduar(); //ulduar -- AddSC_boss_ingvar(); //utgarde_keep -- AddSC_boss_keleseth(); -- AddSC_boss_skarvald_and_dalronn(); -- AddSC_instance_utgarde_keep(); -- AddSC_utgarde_keep(); -- AddSC_boss_gortok(); //utgarde_pinnacle -- AddSC_boss_skadi(); -- AddSC_boss_svala(); -- AddSC_boss_ymiron(); -- AddSC_instance_pinnacle(); -- AddSC_instance_violet_hold(); //violet_hold -- AddSC_violet_hold(); -+ // removed - -- AddSC_borean_tundra(); -- AddSC_dalaran(); -- AddSC_dragonblight(); -- AddSC_howling_fjord(); -- AddSC_icecrown(); -- AddSC_sholazar_basin(); -- AddSC_storm_peaks(); -- AddSC_zuldrak(); -- - //outland - AddSC_boss_exarch_maladaar(); //auchindoun, auchenai_crypts - AddSC_boss_nexusprince_shaffar(); //auchindoun, mana_tombs diff --git a/scriptVC100.sln b/scriptVC100.sln deleted file mode 100644 index a08bb2de36..0000000000 --- a/scriptVC100.sln +++ /dev/null @@ -1,25 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScriptDev2", "VC100\100ScriptDev2.vcxproj", "{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|Win32.ActiveCfg = Debug|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|Win32.Build.0 = Debug|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|x64.ActiveCfg = Debug|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|x64.Build.0 = Debug|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|Win32.ActiveCfg = Release|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|Win32.Build.0 = Release|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|x64.ActiveCfg = Release|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/scriptVC80.sln b/scriptVC80.sln deleted file mode 100644 index 420b4d657e..0000000000 --- a/scriptVC80.sln +++ /dev/null @@ -1,25 +0,0 @@ -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}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|Win32.ActiveCfg = Debug|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|Win32.Build.0 = Debug|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|x64.ActiveCfg = Debug|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|x64.Build.0 = Debug|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|Win32.ActiveCfg = Release|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|Win32.Build.0 = Release|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|x64.ActiveCfg = Release|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/scriptVC90.sln b/scriptVC90.sln deleted file mode 100644 index 9507f49dfe..0000000000 --- a/scriptVC90.sln +++ /dev/null @@ -1,25 +0,0 @@ -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}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|Win32.ActiveCfg = Debug|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|Win32.Build.0 = Debug|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|x64.ActiveCfg = Debug|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Debug|x64.Build.0 = Debug|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|Win32.ActiveCfg = Release|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|Win32.Build.0 = Release|Win32 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|x64.ActiveCfg = Release|x64 - {4295C8A9-79B7-4354-8064-F05FB9CA0C96}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/scriptdev2.conf.dist.in b/scriptdev2.conf.dist.in index b25d9d9dff..a97fde04f3 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 0e8daef146..babeae0949 100644 --- a/scripts/battlegrounds/battleground.cpp +++ b/scripts/battlegrounds/battleground.cpp @@ -1,112 +1,113 @@ -/* Copyright (C) 2006 - 2010 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: Battleground -SD%Complete: 100 -SDComment: Spirit guides in battlegrounds will revive all players every 30 sec -SDCategory: Battlegrounds -EndScriptData */ - -#include "precompiled.h" - -// **** Script Info **** -// Spiritguides in battlegrounds resurrecting many players at once -// every 30 seconds - through a channeled spell, which gets autocasted -// the whole time -// if spiritguide despawns all players around him will get teleported -// to the next spiritguide -// here i'm not sure, if a dummyspell exist for it - -// **** Quick Info **** -// battleground spiritguides - this script handles gossipHello -// and JustDied also it let autocast the channel-spell - -enum -{ - SPELL_SPIRIT_HEAL_CHANNEL = 22011, // Spirit Heal Channel - - SPELL_SPIRIT_HEAL = 22012, // Spirit Heal - SPELL_SPIRIT_HEAL_MANA = 44535, // in battlegrounds player get this no-mana-cost-buff - - SPELL_WAITING_TO_RESURRECT = 2584 // players who cancel this aura don't want a resurrection -}; - -struct MANGOS_DLL_DECL npc_spirit_guideAI : public ScriptedAI -{ - npc_spirit_guideAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - } - - void UpdateAI(const uint32 uiDiff) - { - // 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 &) - { - // TODO: would be better to cast a dummy spell - Map* pMap = m_creature->GetMap(); - - if (!pMap || !pMap->IsBattleGround()) - return; - - Map::PlayerList const &PlayerList = pMap->GetPlayers(); - - 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)) - continue; - - // repop player again - now this node won't be counted and another node is searched - pPlayer->RepopAtGraveyard(); - } - } - - void SpellHitTarget (Unit* pUnit, const SpellEntry* pSpellEntry) - { - if (pSpellEntry->Id == SPELL_SPIRIT_HEAL && pUnit->GetTypeId() == TYPEID_PLAYER - && pUnit->HasAura(SPELL_WAITING_TO_RESURRECT)) - pUnit->CastSpell(pUnit, SPELL_SPIRIT_HEAL_MANA, true); - } -}; - -bool GossipHello_npc_spirit_guide(Player* pPlayer, Creature* pCreature) -{ - pPlayer->CastSpell(pPlayer, SPELL_WAITING_TO_RESURRECT, true); - return true; -} - -CreatureAI* GetAI_npc_spirit_guide(Creature* pCreature) -{ - return new npc_spirit_guideAI(pCreature); -} - -void AddSC_battleground() -{ - Script* newscript; - - newscript = new Script; - newscript->Name = "npc_spirit_guide"; - newscript->GetAI = &GetAI_npc_spirit_guide; - newscript->pGossipHello = &GossipHello_npc_spirit_guide; - newscript->RegisterSelf(); -} +/* Copyright (C) 2006 - 2013 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: Battleground +SD%Complete: 100 +SDComment: Spirit guides in battlegrounds will revive all players every 30 sec +SDCategory: Battlegrounds +EndScriptData */ + +#include "precompiled.h" + +// **** Script Info **** +// Spiritguides in battlegrounds resurrecting many players at once +// every 30 seconds - through a channeled spell, which gets autocasted +// the whole time +// if spiritguide despawns all players around him will get teleported +// to the next spiritguide +// here i'm not sure, if a dummyspell exist for it + +// **** Quick Info **** +// battleground spiritguides - this script handles gossipHello +// and JustDied also it let autocast the channel-spell + +enum +{ + SPELL_SPIRIT_HEAL_CHANNEL = 22011, // Spirit Heal Channel + + SPELL_SPIRIT_HEAL = 22012, // Spirit Heal + SPELL_SPIRIT_HEAL_MANA = 44535, // in battlegrounds player get this no-mana-cost-buff + + SPELL_WAITING_TO_RESURRECT = 2584 // players who cancel this aura don't want a resurrection +}; + +struct MANGOS_DLL_DECL npc_spirit_guideAI : public ScriptedAI +{ + npc_spirit_guideAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pCreature->SetActiveObjectState(true); + Reset(); + } + + void Reset() {} + + 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, true); + m_creature->CastSpell(m_creature, SPELL_SPIRIT_HEAL_CHANNEL, false); + } + } + + void CorpseRemoved(uint32&) override + { + // TODO: would be better to cast a dummy spell + Map* pMap = m_creature->GetMap(); + + if (!pMap || !pMap->IsBattleGround()) + return; + + Map::PlayerList const& PlayerList = pMap->GetPlayers(); + + 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)) + continue; + + // repop player again - now this node won't be counted and another node is searched + pPlayer->RepopAtGraveyard(); + } + } + + 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->CastSpell(pUnit, SPELL_SPIRIT_HEAL_MANA, true); + } +}; + +bool GossipHello_npc_spirit_guide(Player* pPlayer, Creature* /*pCreature*/) +{ + pPlayer->CastSpell(pPlayer, SPELL_WAITING_TO_RESURRECT, true); + return true; +} + +CreatureAI* GetAI_npc_spirit_guide(Creature* pCreature) +{ + return new npc_spirit_guideAI(pCreature); +} + +void AddSC_battleground() +{ + AutoScript s("npc_spirit_guide"); + s->GetAI = &GetAI_npc_spirit_guide; + s->pGossipHello = &GossipHello_npc_spirit_guide; +} diff --git a/scripts/battlegrounds/battlegroundIC.cpp b/scripts/battlegrounds/battlegroundIC.cpp new file mode 100644 index 0000000000..73ad656c7b --- /dev/null +++ b/scripts/battlegrounds/battlegroundIC.cpp @@ -0,0 +1,158 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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: Battleground_IoC +SD%Complete: %? +SDComment: Battleground isle of conquest +SDCategory: Battleground_IoC +EndScriptData */ + +#include "precompiled.h" +#include "BattleGround/BattleGroundIC.h" + +/*###### +## go_ic_teleport +## boss_bg_ioc +######*/ + +#define MAX_PORTALS 15 + +enum +{ + SPELL_TELEPORT_EFFECT = 66548, // teleport effect + + NPC_CATAPULT = 34793, + NPC_DEMOLISHER = 34775, + NPC_GLAIVE_A = 34802, + NPC_GLAIVE_H = 35273, + + // bosses + SPELL_BRUTAL_STRIKE = 58460, + SPELL_RAGE = 66776, + SPELL_DAGGER_THROW = 67280, + SPELL_CRUSHING_LEAP = 68506, +}; + +static float SpawnLocation[MAX_PORTALS][3]= +{ + {324.635f, -749.128f, 49.3602f}, // alli left outside + {311.92f, -913.972f, 48.8159f}, // a r o + {425.675f, -857.09f, 48.5104f}, // a f o + {1236.53f, -669.415f, 48.2729f}, // h l o + {1235.09f, -857.898f, 48.9163f}, // h r o + {1143.25f, -779.599f, 48.629f}, // h f o + + {326.285f, -777.366f, 49.0208f}, // a l i + {323.54f, -888.361f, 48.9197f}, // a r i + {397.089f, -859.382f, 48.8993f}, // a f i + {1235.53f, -683.872f, 49.304f}, // h l i + {1233.27f, -844.526f, 48.8824f}, // h r i + {1158.76f, -746.182f, 48.6277f}, // horde front inside + + {827.958f, -994.467f, 134.071f}, // gunship portals (not working yet) + {738.613f, -1106.58f, 134.745f}, + {672.283f, -1156.99f, 133.706f}, +}; + +bool GOHello_go_ic_teleport(Player* pPlayer, GameObject* pGo) +{ + if (pPlayer->GetMapId() != 628) + return false; + + if (BattleGround* bg = pPlayer->GetBattleGround()) // no need to check for faction, since only the eligible players can click the portal + { + //BattleGroundIC* IoC = static_cast(bg); + + for (uint32 i = 0; i < MAX_PORTALS; ++i) + { + if ((pGo->GetPositionX() == SpawnLocation[i][0]) && + (pGo->GetPositionY() == SpawnLocation[i][1]) && + (pGo->GetPositionZ() == SpawnLocation[i][2])) + { + // teleports outside walls + if (i <= 5) + pPlayer->TeleportTo(bg->GetMapId(), SpawnLocation[i + 6][0], SpawnLocation[i + 6][1], SpawnLocation[i + 6][2], pPlayer->GetOrientation()); + // teleports within the keep + else if (i > 5 && i <= 11) + pPlayer->TeleportTo(bg->GetMapId(), SpawnLocation[i - 6][0], SpawnLocation[i - 6][1], SpawnLocation[i - 6][2], pPlayer->GetOrientation()); + // gunship teleports + else + { + } + return true; + } + + } + } + return false; +} + +struct MANGOS_DLL_DECL boss_bg_iocAI : public ScriptedAI +{ + boss_bg_iocAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiBrutalStrikeTimer; + uint32 m_uiDaggerThrowTimer; + + void Reset() + { + m_uiBrutalStrikeTimer = urand(5000, 10000); + m_uiDaggerThrowTimer = urand(15000, 20000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBrutalStrikeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0)) + DoCast(pTarget, SPELL_BRUTAL_STRIKE); + m_uiBrutalStrikeTimer = urand(5000, 10000); + } + else + m_uiBrutalStrikeTimer -= uiDiff; + + if (m_uiDaggerThrowTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_DAGGER_THROW); + m_uiDaggerThrowTimer = urand(15000, 20000); + } + else + m_uiDaggerThrowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_bg_ioc(Creature* pCreature) +{ + return new boss_bg_iocAI(pCreature); +} + +void AddSC_battlegroundIC() +{ + AutoScript s; + s.newScript("go_ic_teleport")->pGOUse = &GOHello_go_ic_teleport; + s.newScript("boss_bg_ioc")->GetAI = &GetAI_boss_bg_ioc; +} diff --git a/scripts/battlegrounds/battlegroundSA.cpp b/scripts/battlegrounds/battlegroundSA.cpp new file mode 100644 index 0000000000..6e861e179b --- /dev/null +++ b/scripts/battlegrounds/battlegroundSA.cpp @@ -0,0 +1,258 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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: Battleground_SA +SD%Complete: %? +SDComment: Battleground Strand of Ancients +SDCategory: Battleground_SA +EndScriptData */ + +#include "precompiled.h" +#include "BattleGround/BattleGroundSA.h" + + +#define GOSSIP_START_EVENT_1 "Start building the Demolisher." +#define GOSSIP_START_EVENT_2 "You have nothing to do now!" +#define GOSSIP_EVENT_STARTED "Im working on it." + +#define NPC_DEMILISHER 28781 + +#define SA_MESSAGE_0 "Begin the manufracture of Demolisher" +#define SA_MESSAGE_1 "Time Left: 1 minute" +#define SA_MESSAGE_1_1 "Time Left: 40 seconds" +#define SA_MESSAGE_1_2 "Time Left: 35 seconds" +#define SA_MESSAGE_2 "Time Left: 30 seconds" +#define SA_MESSAGE_3 "Time Left: 25 seconds" +#define SA_MESSAGE_4 "Time Left: 20 seconds" +#define SA_MESSAGE_5 "Time Left: 15 seconds" +#define SA_MESSAGE_6 "Time Left: 10 seconds" +#define SA_MESSAGE_7 "Time Left: 5 seconds" +#define SA_MESSAGE_8 "Ready!" + +static float SummonLocations[2][4]= +{ + {1371.06f, -317.046f, 35.001f, 1.916f}, + {1353.24f, 223.91f, 35.2535f, 4.366f}, +}; + +bool build[BG_SA_GRY_MAX]; + +struct MANGOS_DLL_DECL npc_sa_vendorAI : public ScriptedAI +{ + npc_sa_vendorAI(Creature* pCreature) : ScriptedAI(pCreature){Reset();} + uint32 build_time; + uint8 gydId; + void Reset() + { + for (uint8 i = 0; i < BG_SA_GRY_MAX; ++i) + build[i]=false; + } + void StartEvent(Player* pPlayer, uint8 gyd) + { + build_time = 60000; + gydId = gyd; + build[gydId] = true; + m_creature->MonsterSay(SA_MESSAGE_0,LANG_UNIVERSAL,0); + m_creature->MonsterSay(SA_MESSAGE_1,LANG_UNIVERSAL,0); + } + + void UpdateAI(const uint32 diff) + { + if (build[gydId]) + { + if (build_time < diff) + { + m_creature->SummonCreature(NPC_DEMILISHER,SummonLocations[gydId][0],SummonLocations[gydId][1],SummonLocations[gydId][2],SummonLocations[gydId][3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->MonsterSay(SA_MESSAGE_8,LANG_UNIVERSAL,0); + build[gydId]=false; + } + else build_time -= diff; +/* FIXME - need implement correct saying. + switch (build_time/2) + { + case 15000: m_creature->MonsterSay(SA_MESSAGE_2,LANG_UNIVERSAL,0); + break; + case 7500: m_creature->MonsterSay(SA_MESSAGE_5,LANG_UNIVERSAL,0); + break; + + } +*/ + } + } +}; + +CreatureAI* GetAI_npc_sa_vendor(Creature* pCreature) +{ + return new npc_sa_vendorAI(pCreature); +} + +bool GossipHello_npc_sa_vendor(Player* pPlayer, Creature* pCreature) +{ + uint8 gyd = 0; + if (pCreature->GetEntry() == 29260) + gyd = 0; + if (pCreature->GetEntry() == 29262) + gyd = 1; + + if (!build[gyd]) + { + if (pPlayer->GetMapId() == 607) + { + if (BattleGround *bg = pPlayer->GetBattleGround()) + { + if (bg->GetDefender() != pPlayer->GetTeam()) + { + if (bg->GetDefender() != ALLIANCE && bg->GetGydController(gyd) == BG_SA_GRAVE_STATUS_ALLY_OCCUPIED) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_START_EVENT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (bg->GetDefender() != HORDE && bg->GetGydController(gyd) == BG_SA_GRAVE_STATUS_HORDE_OCCUPIED) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_START_EVENT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + } + } + } + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_START_EVENT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + } + else + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_START_EVENT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_sa_vendor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + uint8 gyd = NULL; + if (pCreature->GetEntry() == 29260) + gyd = 0; + if (pCreature->GetEntry() == 29262) + gyd = 1; + + pPlayer->CLOSE_GOSSIP_MENU(); + ((npc_sa_vendorAI*)pCreature->AI())->StartEvent(pPlayer, gyd); + } + if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + pPlayer->CLOSE_GOSSIP_MENU(); + return true; +} + +/*###### +## go_sa_def_portal +######*/ + +static float SpawnLocation[7][3]= +{ + {1394.07f, 72.3632f, 31.0541f}, + {1468.12f, -225.7f, 30.8969f}, + {1216.12f, 47.7665f, 54.2785f}, + {1255.73f, -233.153f, 56.4357f}, + {1065.02f, -89.9522f, 81.0758f}, + {880.162f, -95.979f, 109.835f}, + {808.447f, -109.192f, 109.835f}, +}; + +static float TeleLocation[7][3]= +{ + {1401.6f, 88.6693f, 41.1833f}, + {1451.72f, -224.863f, 41.9564f}, + {1210.68f, 60.3558f, 64.7388f}, + {1245.03f, -226.439f, 66.7201f}, + {1062.83f, -87.1955f, 93.8061f}, + {808.447f, -109.192f, 109.835f}, + {880.68f, -120.799f, 109.835f}, +}; + +bool GOHello_go_sa_def_portal(Player* pPlayer, GameObject* pGo) +{ + if (pPlayer->GetMapId() == 607) + { + if (BattleGround *bg = pPlayer->GetBattleGround()) + { + if (pPlayer->GetTeam() == bg->GetDefender()) + { + for (uint32 i=0; i<7; ++i) + { + if ((pGo->GetPositionX() == SpawnLocation[i][0]) && + (pGo->GetPositionY() == SpawnLocation[i][1]) && + (pGo->GetPositionZ() == SpawnLocation[i][2])) + { + if(((BattleGroundSA*)bg)->GetGateStatus(i+1) != BG_SA_GO_GATES_DESTROY) + { + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i][0],TeleLocation[i][1],TeleLocation[i][2],0); + return true; + } + else if(i == 0 || i == 1) + { + if(i == 0) + if(((BattleGroundSA*)bg)->GetGateStatus(2) != BG_SA_GO_GATES_DESTROY) + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+1][0],TeleLocation[i+1][1],TeleLocation[i+1][2],0); + else + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+2][0],TeleLocation[i+2][1],TeleLocation[i+2][2],0); + + if(i == 1) + if(((BattleGroundSA*)bg)->GetGateStatus(1) != BG_SA_GO_GATES_DESTROY) + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i-1][0],TeleLocation[i-1][1],TeleLocation[i-1][2],0); + else + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+1][0],TeleLocation[i+1][1],TeleLocation[i+1][2],0); + + return true; + } + else if(i == 2 || i == 3) + { + if (i == 2) + if(((BattleGroundSA*)bg)->GetGateStatus(4) != BG_SA_GO_GATES_DESTROY) + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+1][0],TeleLocation[i+1][1],TeleLocation[i+1][2],0); + else + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+2][0],TeleLocation[i+2][1],TeleLocation[i+2][2],0); + + if (i == 3) + if(((BattleGroundSA*)bg)->GetGateStatus(3) != BG_SA_GO_GATES_DESTROY) + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i-1][0],TeleLocation[i-1][1],TeleLocation[i-1][2],0); + else + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+1][0],TeleLocation[i+1][1],TeleLocation[i+1][2],0); + + return true; + } + else if (i == 4 || i == 5) + { + pPlayer->TeleportTo(bg->GetMapId(),TeleLocation[i+1][0],TeleLocation[i+1][1],TeleLocation[i+1][2],0); + return true; + } + + } + } + } else + pPlayer->MonsterSay("You are not defender!",LANG_UNIVERSAL, pPlayer); + } + } + return false; +} + +void AddSC_battlegroundSA() +{ + AutoScript s; + + s.newScript("npc_sa_vendor"); + s->GetAI = &GetAI_npc_sa_vendor; + s->pGossipHello = &GossipHello_npc_sa_vendor; + s->pGossipSelect = &GossipSelect_npc_sa_vendor; + + s.newScript("go_sa_def_portal"); + s->pGOUse = &GOHello_go_sa_def_portal; +} diff --git a/scripts/custom/npc_arena_honor.cpp b/scripts/custom/npc_arena_honor.cpp new file mode 100644 index 0000000000..ec91b7d6f9 --- /dev/null +++ b/scripts/custom/npc_arena_honor.cpp @@ -0,0 +1,104 @@ +/* Copyright (C) 2006 - 2013 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: npc_arena_honor +SD%Complete: 100% +SDComment: by tempura, corrected by /dev/rsa +SDCategory: custom +EndScriptData */ +#include "precompiled.h" +#include "sc_creature.h" +#include "sc_gossip.h" + +#define GOSSIP_ITEM_ARENA_TO_HONOR -3000770 +#define GOSSIP_ITEM_ARENA_TO_HONOR1 -3000771 +#define GOSSIP_ITEM_HONOR_TO_ARENA -3000772 +#define GOSSIP_ITEM_HONOR_TO_ARENA1 -3000773 + +#define UNSUCCESSFUL_HONOR -1001007 +#define UNSUCCESSFUL_ARENA -1001008 + +bool GossipHello_npc_arena_honor(Player* pPlayer, Creature *pCreature) +{ +#ifdef SD2_WORLD_WOTLK + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_HONOR_TO_ARENA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_HONOR_TO_ARENA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ARENA_TO_HONOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ARENA_TO_HONOR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->SEND_GOSSIP_MENU(3961,pCreature->GetObjectGuid()); +#endif + return true; +} + +bool GossipSelect_npc_arena_honor(Player *pPlayer, Creature *pCreature, uint32 sender, uint32 action) +{ + +#ifdef SD2_WORLD_WOTLK + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + if (pPlayer->GetHonorPoints() >= 1000) + { + pPlayer->ModifyHonorPoints(-1000); + pPlayer->ModifyArenaPoints(+50); + } + else + DoScriptText(UNSUCCESSFUL_HONOR, pCreature); + } + if (action == GOSSIP_ACTION_INFO_DEF + 2) + { + if (pPlayer->GetHonorPoints() >= 10000) + { + pPlayer->ModifyHonorPoints(-10000); + pPlayer->ModifyArenaPoints(+500); + } + else + DoScriptText(UNSUCCESSFUL_HONOR, pCreature); + } + if (action == GOSSIP_ACTION_INFO_DEF + 3) + { + if (pPlayer->GetArenaPoints() >= 100) + { + pPlayer->ModifyArenaPoints(-100); + pPlayer->ModifyHonorPoints(+2000); + } + else + DoScriptText(UNSUCCESSFUL_ARENA, pCreature); + } + if (action == GOSSIP_ACTION_INFO_DEF + 4) + { + if (pPlayer->GetArenaPoints() >= 1000) + { + pPlayer->ModifyArenaPoints(-1000); + pPlayer->ModifyHonorPoints(+20000); + } + else + DoScriptText(UNSUCCESSFUL_ARENA, pCreature); + } +#endif + pPlayer->CLOSE_GOSSIP_MENU(); + return true; +} + +void AddSC_npc_arena_honor() +{ + Script *pNewScript; + pNewScript = new Script; + pNewScript->Name="npc_arena_honor"; + pNewScript->pGossipHello = &GossipHello_npc_arena_honor; + pNewScript->pGossipSelect = &GossipSelect_npc_arena_honor; + pNewScript->RegisterSelf(); +} diff --git a/scripts/custom/teleguy.cpp b/scripts/custom/teleguy.cpp new file mode 100644 index 0000000000..2175a4f899 --- /dev/null +++ b/scripts/custom/teleguy.cpp @@ -0,0 +1,1109 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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: npc_teleguy +SD%Complete: 100% +SDComment: by tempura, modify by Asprorpsa +SDCategory: custom +EndScriptData */ + +#include "precompiled.h" +long long int money; +int costo; + +bool GossipHello_mob_teleguy(Player* player, Creature* _Creature) +{ + if (player->GetTeam() == ALLIANCE) + { + player->ADD_GOSSIP_ITEM( 5, "Darnassus. 5 Silver" , GOSSIP_SENDER_MAIN, 1203); + player->ADD_GOSSIP_ITEM( 5, "Exodar. 5 Silver" , GOSSIP_SENDER_MAIN, 1216); + player->ADD_GOSSIP_ITEM( 5, "Stormwind. 5 Silver" , GOSSIP_SENDER_MAIN, 1206); + player->ADD_GOSSIP_ITEM( 5, "Ironforge. 5 Silver" , GOSSIP_SENDER_MAIN, 1224); + player->ADD_GOSSIP_ITEM( 5, "Shattrath City. 5 Silver" , GOSSIP_SENDER_MAIN, 1287); + player->ADD_GOSSIP_ITEM( 5, "Dalaran. 5 Silver" , GOSSIP_SENDER_MAIN, 1205); + player->ADD_GOSSIP_ITEM( 5, "Isle Of Quel'Danas. 5 Silver" , GOSSIP_SENDER_MAIN, 1288); + player->ADD_GOSSIP_ITEM( 7, "[Instances Normal] ->" , GOSSIP_SENDER_MAIN, 5550); + player->ADD_GOSSIP_ITEM( 7, "[Instances BC] ->" , GOSSIP_SENDER_MAIN, 5553); + player->ADD_GOSSIP_ITEM( 7, "[Instances WotLK] ->" , GOSSIP_SENDER_MAIN, 5554); + player->ADD_GOSSIP_ITEM( 7, "[Raids WotLK] ->" , GOSSIP_SENDER_MAIN, 5555); + } + else + { + player->ADD_GOSSIP_ITEM( 5, "Orgrimmar. 5 Silver" , GOSSIP_SENDER_MAIN, 1215); + player->ADD_GOSSIP_ITEM( 5, "Silvermoon. 5 Silver" , GOSSIP_SENDER_MAIN, 1217); + player->ADD_GOSSIP_ITEM( 5, "Undercity. 5 Silver" , GOSSIP_SENDER_MAIN, 1213); + player->ADD_GOSSIP_ITEM( 5, "Thunder Bluff. 5 Silver" , GOSSIP_SENDER_MAIN, 1225); + player->ADD_GOSSIP_ITEM( 5, "Shattrath City. 5 Silver" , GOSSIP_SENDER_MAIN, 1287); + player->ADD_GOSSIP_ITEM( 5, "Dalaran. 5 Silver" , GOSSIP_SENDER_MAIN, 1205); + player->ADD_GOSSIP_ITEM( 5, "Isle Of Quel'Danas. 5 Silver" , GOSSIP_SENDER_MAIN, 1288); + player->ADD_GOSSIP_ITEM( 7, "[Instances Normal] ->" , GOSSIP_SENDER_MAIN, 5550); + player->ADD_GOSSIP_ITEM( 7, "[Instances BC] ->" , GOSSIP_SENDER_MAIN, 5553); + player->ADD_GOSSIP_ITEM( 7, "[Instances WotLK] ->" , GOSSIP_SENDER_MAIN, 5554); + player->ADD_GOSSIP_ITEM( 7, "[Raids WotLK] ->" , GOSSIP_SENDER_MAIN, 5555); + } + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + return true; +} + +void SendDefaultMenu_mob_teleguy(Player* player, Creature* _Creature, uint32 action) +{ + if (player->IsInCombat()) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You are in combat!", LANG_UNIVERSAL); + return; + } + + if (player->getLevel() < 8) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be lvl 8+", LANG_UNIVERSAL); + return; + } + + money = player-> GetMoney(); + costo = 500; + + if (money < costo) + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You haven't enough money", LANG_UNIVERSAL); + return; + } + + switch(action) + { + case 5550: // Normal Instances + { + // Teleport to the points that are close to the enemy capital closed + if (player->GetTeam() == ALLIANCE) + { + player->ADD_GOSSIP_ITEM( 5, "The Stockade. 10 Silver" , GOSSIP_SENDER_MAIN, 1253); + player->ADD_GOSSIP_ITEM( 5, "Gnomeregan. 10 Silver" , GOSSIP_SENDER_MAIN, 1222); + } + else + { + player->ADD_GOSSIP_ITEM( 5, "Scarlet Monastery. 10 Silver" , GOSSIP_SENDER_MAIN, 1257); + player->ADD_GOSSIP_ITEM( 5, "Ragefire Chasm. 10 Silver" , GOSSIP_SENDER_MAIN, 1248); + } + player->ADD_GOSSIP_ITEM( 5, "The Wailing Caverns. 10 Silver" , GOSSIP_SENDER_MAIN, 1249); + player->ADD_GOSSIP_ITEM( 5, "Deadmines. 10 Silver" , GOSSIP_SENDER_MAIN, 1250); + player->ADD_GOSSIP_ITEM( 5, "Shadowfang Keep. 10 Silver" , GOSSIP_SENDER_MAIN, 1251); + player->ADD_GOSSIP_ITEM( 5, "Blackfathom Deeps. 10 Silver" , GOSSIP_SENDER_MAIN, 1252); + player->ADD_GOSSIP_ITEM( 5, "Razorfen Kraul. 20 Silver" , GOSSIP_SENDER_MAIN, 1254); + player->ADD_GOSSIP_ITEM( 5, "Razorfen Downs. 20 Silver" , GOSSIP_SENDER_MAIN, 1256); + player->ADD_GOSSIP_ITEM( 7, "[More] ->" , GOSSIP_SENDER_MAIN, 5551); + player->ADD_GOSSIP_ITEM( 7, "<- [Main Menu]" , GOSSIP_SENDER_MAIN, 5552); + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + } + break; + + case 5551: // More Normal Instances + { + player->ADD_GOSSIP_ITEM( 5, "Uldaman. 30 Silver" , GOSSIP_SENDER_MAIN, 1258); + player->ADD_GOSSIP_ITEM( 5, "Zul'Farrak. 30 Silver" , GOSSIP_SENDER_MAIN, 1259); + player->ADD_GOSSIP_ITEM( 5, "Maraudon. 40 Silver" , GOSSIP_SENDER_MAIN, 1260); + player->ADD_GOSSIP_ITEM( 5, "The Sunken Temple. 40 Silver" , GOSSIP_SENDER_MAIN, 1261); + player->ADD_GOSSIP_ITEM( 5, "Blackrock Depths. 40 Silver" , GOSSIP_SENDER_MAIN, 1262); + player->ADD_GOSSIP_ITEM( 5, "Dire Maul. 50 Silver" , GOSSIP_SENDER_MAIN, 1263); + player->ADD_GOSSIP_ITEM( 5, "Blackrock Spire. 50 Silver" , GOSSIP_SENDER_MAIN, 1264); + player->ADD_GOSSIP_ITEM( 5, "Stratholme. 50 Silver" , GOSSIP_SENDER_MAIN, 1265); + player->ADD_GOSSIP_ITEM( 5, "Scholomance. 50 Silver" , GOSSIP_SENDER_MAIN, 1266); + player->ADD_GOSSIP_ITEM( 5, "Ahn'Qiraj. 50 Silver" , GOSSIP_SENDER_MAIN, 1267); + player->ADD_GOSSIP_ITEM( 5, "Zul'Gurub. 50 Silver" , GOSSIP_SENDER_MAIN, 1268); + player->ADD_GOSSIP_ITEM( 7, "<- [Back]" , GOSSIP_SENDER_MAIN, 5550); + player->ADD_GOSSIP_ITEM( 7, "<- [Main Menu]" , GOSSIP_SENDER_MAIN, 5552); + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + } + break; + + case 5553: // Instances 60-70 BC + { + player->ADD_GOSSIP_ITEM( 5, "Auchindoun. 1 Gold" , GOSSIP_SENDER_MAIN, 4006); + player->ADD_GOSSIP_ITEM( 5, "Karazhan. 1 Gold" , GOSSIP_SENDER_MAIN, 4007); + player->ADD_GOSSIP_ITEM( 5, "Gruul's Lair. 1 Gold" , GOSSIP_SENDER_MAIN, 4008); + player->ADD_GOSSIP_ITEM( 5, "Hellfire Citadel. 1 Gold" , GOSSIP_SENDER_MAIN, 4009); + player->ADD_GOSSIP_ITEM( 5, "Coilfang Reservoir. 1 Gold" , GOSSIP_SENDER_MAIN, 4010); + player->ADD_GOSSIP_ITEM( 5, "Tempest Keep. 1 Gold" , GOSSIP_SENDER_MAIN, 4011); + player->ADD_GOSSIP_ITEM( 5, "Zul'Aman. 1 Gold" , GOSSIP_SENDER_MAIN, 4016); + player->ADD_GOSSIP_ITEM( 5, "Black Temple. 1 Gold" , GOSSIP_SENDER_MAIN, 4013); + player->ADD_GOSSIP_ITEM( 5, "Magister's Terrace. 2 Gold" , GOSSIP_SENDER_MAIN, 4017); + player->ADD_GOSSIP_ITEM( 7, "<- [Main Menu]" , GOSSIP_SENDER_MAIN, 5552); + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + } + break; + + case 5554: // Instances 70-80 WotLK + { + player->ADD_GOSSIP_ITEM( 5, "Caverns of Time. 20 Gold" , GOSSIP_SENDER_MAIN, 4012); + player->ADD_GOSSIP_ITEM( 5, "Utgarde Keep. 20 Gold" , GOSSIP_SENDER_MAIN, 4019); + player->ADD_GOSSIP_ITEM( 5, "Azjol-Nerub. 20 Gold" , GOSSIP_SENDER_MAIN, 4021); + player->ADD_GOSSIP_ITEM( 5, "The Old Kingdom. 20 Gold" , GOSSIP_SENDER_MAIN, 4022); + player->ADD_GOSSIP_ITEM( 5, "Drak'Tharon Keep. 20 Gold" , GOSSIP_SENDER_MAIN, 4023); + player->ADD_GOSSIP_ITEM( 5, "Gundrak. 20 Gold" , GOSSIP_SENDER_MAIN, 4025); + player->ADD_GOSSIP_ITEM( 5, "Utgarde Pinnacle. 20 Gold" , GOSSIP_SENDER_MAIN, 4026); + player->ADD_GOSSIP_ITEM( 5, "Halls of Stone. 20 Gold" , GOSSIP_SENDER_MAIN, 4032); + player->ADD_GOSSIP_ITEM( 5, "Halls of Lightning. 20 Gold" , GOSSIP_SENDER_MAIN, 4033); + player->ADD_GOSSIP_ITEM( 5, "Frozen Halls. 20 Gold" , GOSSIP_SENDER_MAIN, 4034); + player->ADD_GOSSIP_ITEM( 7, "<- [Main Menu]" , GOSSIP_SENDER_MAIN, 5552); + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + } + break; + + case 5555: // Raids 80 WotLK + { + player->ADD_GOSSIP_ITEM( 5, "The Nexus. 30 Gold" , GOSSIP_SENDER_MAIN, 4020); + player->ADD_GOSSIP_ITEM( 5, "Coliseum Vanguard. 30 Gold" , GOSSIP_SENDER_MAIN, 4024); + player->ADD_GOSSIP_ITEM( 5, "Ulduar. 30 Gold" , GOSSIP_SENDER_MAIN, 4027); + player->ADD_GOSSIP_ITEM( 5, "Wyrmrest Temple. 40 Gold" , GOSSIP_SENDER_MAIN, 4028); + player->ADD_GOSSIP_ITEM( 5, "Naxxramas. 30 Gold" , GOSSIP_SENDER_MAIN, 4029); + player->ADD_GOSSIP_ITEM( 5, "Icecrown Citadel. 40 Gold" , GOSSIP_SENDER_MAIN, 4030); + player->ADD_GOSSIP_ITEM( 5, "Vault of Archavon. 40 Gold" , GOSSIP_SENDER_MAIN, 4031); + player->ADD_GOSSIP_ITEM( 5, "Onyxia's Lair. 40 Gold" , GOSSIP_SENDER_MAIN, 4035); + player->ADD_GOSSIP_ITEM( 7, "<- [Main Menu]" , GOSSIP_SENDER_MAIN, 5552); + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + } + break; + + case 5552: // Back To Main Menu + { + if (player->GetTeam() == ALLIANCE) + { + player->ADD_GOSSIP_ITEM( 5, "Darnassus. 5 Silver" , GOSSIP_SENDER_MAIN, 1203); + player->ADD_GOSSIP_ITEM( 5, "Exodar. 5 Silver" , GOSSIP_SENDER_MAIN, 1216); + player->ADD_GOSSIP_ITEM( 5, "Stormwind. 5 Silver" , GOSSIP_SENDER_MAIN, 1206); + player->ADD_GOSSIP_ITEM( 5, "Ironforge. 5 Silver" , GOSSIP_SENDER_MAIN, 1224); + player->ADD_GOSSIP_ITEM( 5, "Shattrath City. 5 Silver" , GOSSIP_SENDER_MAIN, 1287); + player->ADD_GOSSIP_ITEM( 5, "Dalaran. 5 Silver" , GOSSIP_SENDER_MAIN, 1205); + player->ADD_GOSSIP_ITEM( 5, "Isle Of Quel'Danas. 5 Silver" , GOSSIP_SENDER_MAIN, 1288); + player->ADD_GOSSIP_ITEM( 7, "[Instances Normal] ->" , GOSSIP_SENDER_MAIN, 5550); + player->ADD_GOSSIP_ITEM( 7, "[Instances BC] ->" , GOSSIP_SENDER_MAIN, 5553); + player->ADD_GOSSIP_ITEM( 7, "[Instances WotLK] ->" , GOSSIP_SENDER_MAIN, 5554); + player->ADD_GOSSIP_ITEM( 7, "[Raids WotLK] ->" , GOSSIP_SENDER_MAIN, 5555); + } + else + { + player->ADD_GOSSIP_ITEM( 5, "Orgrimmar. 5 Silver" , GOSSIP_SENDER_MAIN, 1215); + player->ADD_GOSSIP_ITEM( 5, "Silvermoon. 5 Silver" , GOSSIP_SENDER_MAIN, 1217); + player->ADD_GOSSIP_ITEM( 5, "Undercity. 5 Silver" , GOSSIP_SENDER_MAIN, 1213); + player->ADD_GOSSIP_ITEM( 5, "Thunder Bluff. 5 Silver" , GOSSIP_SENDER_MAIN, 1225); + player->ADD_GOSSIP_ITEM( 5, "Shattrath City. 5 Silver" , GOSSIP_SENDER_MAIN, 1287); + player->ADD_GOSSIP_ITEM( 5, "Dalaran. 5 Silver" , GOSSIP_SENDER_MAIN, 1205); + player->ADD_GOSSIP_ITEM( 5, "Isle Of Quel'Danas. 5 Silver" , GOSSIP_SENDER_MAIN, 1288); + player->ADD_GOSSIP_ITEM( 7, "[Instances Normal] ->" , GOSSIP_SENDER_MAIN, 5550); + player->ADD_GOSSIP_ITEM( 7, "[Instances BC] ->" , GOSSIP_SENDER_MAIN, 5553); + player->ADD_GOSSIP_ITEM( 7, "[Instances WotLK] ->" , GOSSIP_SENDER_MAIN, 5554); + player->ADD_GOSSIP_ITEM( 7, "[Raids WotLK] ->" , GOSSIP_SENDER_MAIN, 5555); + } + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE,_Creature->GetObjectGuid()); + } + break; + + case 1203: // Darnassus + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, 9947.52f, 2482.73f, 1316.21f, 0.0f); + player->ModifyMoney(-1*costo); + } + break; + + case 1206: // Stormwind + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -8960.14f, 516.266f, 96.3568f, 0.0f); + player->ModifyMoney(-1*costo); + } + break; + + case 1205: // Dalaran + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 5804.14f, 624.770f, 647.7670f, 1.64f); + player->ModifyMoney(-1*costo); + } + break; + + case 1213: // Undercity + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, 1819.71f, 238.79f, 60.5321f, 0.0f); + player->ModifyMoney(-1*costo); + } + break; + + case 1215: // Orgrimmar + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, 1552.5f, -4420.66f, 8.94802f, 0.0f); + player->ModifyMoney(-1*costo); + } + break; + + case 1216: // Exodar + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, -4073.03f, -12020.4f, -1.47f, 0.0f); + player->ModifyMoney(-1*costo); + } + break; + + case 1217: // Silvermoon + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 9338.74f, -7277.27f, 13.7895f, 0.0f); + player->ModifyMoney(-1*costo); + } + break; + + case 1222: // Gnomeregan + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -5163.43f, 660.40f, 348.28f, 4.65f); + player->ModifyMoney(-2*costo); + } + break; + + case 1224: // Ironforge + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -4924.07f, -951.95f, 501.55f, 5.40f); + player->ModifyMoney(-1*costo); + } + break; + + case 1225: // Thunder Bluff + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -1280.19f, 127.21f, 131.35f, 5.16f); + player->ModifyMoney(-1*costo); + } + break; + + case 1287: // Shattrath City + { + + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, -1850.209961f, 5435.821777f, -10.961435f, 3.403913f); + player->ModifyMoney(-1*costo); + } + break; + + case 1288: // Isle Of Quel'Danas + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 12947.4f, -6893.31f, 5.68398f, 3.09154f); + player->ModifyMoney(-1*costo); + } + break; + + case 1248: // Ragefire Chasm + { + if(player->getLevel() >= 8) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, 1800.53f, -4394.68f, -17.93f, 5.49f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 8!", LANG_UNIVERSAL); + } + } + break; + + case 1249: // Wailing Caverns + { + if (player->getLevel() >= 10) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -722.53f, -2226.30f, 16.94f, 2.71f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 10!", LANG_UNIVERSAL); + } + } + break; + + case 1250: // Deadmines + { + if (player->getLevel() >= 10) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -11212.04f, 1658.58f, 25.67f, 1.45f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 10!", LANG_UNIVERSAL); + } + } + break; + + case 1251: // Shadowfang Keep + { + if (player->getLevel() >= 11) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -254.47f, 1524.68f, 76.89f, 1.56f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 11!", LANG_UNIVERSAL); + } + } + break; + + case 1252: // Blackfathom Deeps + { + if (player->getLevel() >= 15) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, 4254.58f, 664.74f, -29.04f, 1.97f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 15!", LANG_UNIVERSAL); + } + } + break; + + case 1253: // The Stockade + { + if (player->getLevel() >= 15) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -8769.76f, 813.08f, 97.63f, 2.26f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 15!", LANG_UNIVERSAL); + } + } + break; + + case 1254: // Razorfen Kraul + { + if (player->getLevel() >= 25) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -4484.04f, -1739.40f, 86.47f, 1.23f); + player->ModifyMoney(-4*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 25!", LANG_UNIVERSAL); + } + } + break; + + case 1255: // Gnomeregan + { + if (player->getLevel() >= 19) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -5162.62f, 667.81f, 248.05f, 1.48f); + player->ModifyMoney(-4*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 19!", LANG_UNIVERSAL); + } + } + break; + + case 1256: // Razorfen Downs + { + if (player->getLevel() >= 35) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -4645.08f, -2470.85f, 85.53f, 4.39f); + player->ModifyMoney(-4*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 35!", LANG_UNIVERSAL); + } + } + break; + + case 1257: // Scarlet Monastery + { + if (player->getLevel() >= 21) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, 2843.89f, -693.74f, 139.32f, 5.11f); + player->ModifyMoney(-2*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 21!", LANG_UNIVERSAL); + } + } + break; + + case 1258: // Uldaman + { + if (player->getLevel() >= 30) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -6119.70f, -2957.30f, 204.11f, 0.03f); + player->ModifyMoney(-6*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 30!", LANG_UNIVERSAL); + } + } + break; + + case 1259: // Zul'Farrak + { + if (player->getLevel() >= 39) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -6839.39f, -2911.03f, 8.87f, 0.41f); + player->ModifyMoney(-6*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 39!", LANG_UNIVERSAL); + } + } + break; + + case 1260: // Maraudon + { + if (player->getLevel() >= 25) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -1433.33f, 2955.34f, 96.21f, 4.82f); + player->ModifyMoney(-8*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 25!", LANG_UNIVERSAL); + } + } + break; + + case 1261: // Sunken Temple + { + if (player->getLevel() >= 45) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -10346.92f, -3851.90f, -43.41f, 6.09f); + player->ModifyMoney(-8*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 45!", LANG_UNIVERSAL); + } + } + break; + + case 1262: // Blackrock Depths + { + if (player->getLevel() >= 42) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -7301.03f, -913.19f, 165.37f, 0.08f); + player->ModifyMoney(-8*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 42!", LANG_UNIVERSAL); + } + } + break; + + case 1263: // Dire Maul + { + if (player->getLevel() >= 31) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -3982.47f, 1127.79f, 161.02f, 0.05f); + player->ModifyMoney(-10*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 31!", LANG_UNIVERSAL); + } + } + break; + + case 1264: // Blackrock Spire + { + if (player->getLevel() >= 48) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -7535.43f, -1212.04f, 285.45f, 5.29f); + player->ModifyMoney(-10*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 48!", LANG_UNIVERSAL); + } + } + break; + + case 1265: // Stratholme + { + if (player->getLevel() >= 37) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, 3263.54f, -3379.46f, 143.59f, 0.00f); + player->ModifyMoney(-10*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 37!", LANG_UNIVERSAL); + } + } + break; + + case 1266: // Scholomance + { + if (player->getLevel() >= 37) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, 1219.01f, -2604.66f, 85.61f, 0.50f); + player->ModifyMoney(-10*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 37!", LANG_UNIVERSAL); + } + } + break; + + case 1267: // Ahn'Qiraj + { + if (player->getLevel() >= 50) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -8169.81f, 1528.11f, 4.195f, 2.948f); + player->ModifyMoney(-10*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 50!", LANG_UNIVERSAL); + } + } + break; + + case 1268: // Zul'Gurub + { + if (player->getLevel() >= 50) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -11916.1f, -1223.97f, 92.288f, 4.707f); + player->ModifyMoney(-10*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 50!", LANG_UNIVERSAL); + } + } + break; + + case 4006: // Auchindoun + { + if (player->getLevel() >= 55) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, -3304.64f, 4916.23f, -105.125f, 2.53837f); + player->ModifyMoney(-40*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 55!", LANG_UNIVERSAL); + } + } + break; + + case 4007: // Karazhan + { + if (player->getLevel() >= 68) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(0, -11118.8f, -2010.84f, 47.0807f, 0.0f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 68!", LANG_UNIVERSAL); + } + } + break; + + case 4008: // Gruul's Lair + { + if (player->getLevel() >= 65) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 3539.007568f, 5082.357910f, 1.691071f, 0.0f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 65!", LANG_UNIVERSAL); + } + } + break; + + case 4009: // Hellfire Citadel + { + if (player->getLevel() >= 55) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, -305.816223f, 3056.401611f, -2.473183f, 2.01f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 55!", LANG_UNIVERSAL); + } + } + break; + + case 4010: // Coilfang Reservoir + { + if (player->getLevel() >= 55) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 517.288025f, 6976.279785f, 32.007198f, 0.0f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 55!", LANG_UNIVERSAL); + } + } + break; + + case 4011: // Tempest Keep + { + if (player->getLevel() >= 65) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 3089.579346f, 1399.046509f, 187.653458f, 4.794070f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 65!", LANG_UNIVERSAL); + } + } + break; + + case 4012: // Caverns of Time + { + if (player->getLevel() >= 66) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -8173.66f, -4746.36f, 33.8423f, 4.93989f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 66!", LANG_UNIVERSAL); + } + } + break; + + case 4016: // Zul'Aman + { + if (player->getLevel() >= 68) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 6846.95f, -7954.5f, 170.028f, 4.61501f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 68!", LANG_UNIVERSAL); + } + } + break; + + case 4013: // Black Temple + { + if (player->getLevel() >= 70) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, -3610.719482f, 324.987579f, 37.400028f, 3.282981f); + player->ModifyMoney(-20*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 70!", LANG_UNIVERSAL); + } + } + break; + + case 4017: // Magisters' Terrace + { + if (player->getLevel() >= 65) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(530, 12884.6f, -7317.69f, 65.5023f, 4.799f); + player->ModifyMoney(-40*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 65!", LANG_UNIVERSAL); + } + } + break; + + case 4019: // Utgarde Keep + { + if (player->getLevel() >= 68) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 1219.720f, -4865.28f, 41.25f, 0.31f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 68!", LANG_UNIVERSAL); + } + } + break; + + case 4020: // The Nexus + { + if (player->getLevel() >= 66) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 3776.950f, 6953.80f, 105.05f, 0.345f); + player->ModifyMoney(-600*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 66!", LANG_UNIVERSAL); + } + } + break; + + case 4021: // Azjol-Nerub + { + if (player->getLevel() >= 67) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 3675.430f, 2169.00f, 35.90f, 2.29f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 67!", LANG_UNIVERSAL); + } + } + break; + + case 4022: // The Old Kingdom + { + if (player->getLevel() >= 68) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 3646.760f, 2045.17f, 1.79f, 4.37f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 68!", LANG_UNIVERSAL); + } + } + break; + + case 4023: // Drak'Tharon Keep + { + if (player->getLevel() >= 69) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 4450.860f, -2045.25f, 162.83f, 0.00f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 69!", LANG_UNIVERSAL); + } + } + break; + + case 4024: // Coliseum Vanguard + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 8551.76f, 635.458f, 548.063f, 3.557f); + player->ModifyMoney(-600*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4025: // Gundrak + { + if (player->getLevel() >= 71) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 6937.540f, -4455.98f, 450.68f, 1.00f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 71!", LANG_UNIVERSAL); + } + } + break; + + case 4026: // Utgarde Pinnacle + { + if (player->getLevel() >= 75) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 1245.690f, -4856.59f, 216.86f, 3.45f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 75!", LANG_UNIVERSAL); + } + } + break; + + case 4027: // Ulduar + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 8976.240f, -1281.33f, 1059.01f, 0.58f); + player->ModifyMoney(-600*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4028: // Wyrmrest Temple + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 3625.780f, 280.40f, -120.14f, 3.25f); + player->ModifyMoney(-800*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4029: // Naxxramas + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 3668.719f, -1262.460f, 243.63f, 5.03f); + player->ModifyMoney(-600*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4030: // Icecrown Citadel + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 5809.48f, 2080.53f, 636.064f, 3.599f); + player->ModifyMoney(-800*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4031: // Vault of Archavon + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 5321.13f, 2843.42f, 409.283f, 6.255f); + player->ModifyMoney(-800*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4032: // Halls of Stone + { + if (player->getLevel() >= 72) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 8923.37f, -1036.56f, 1039.81f, 1.592f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 72!", LANG_UNIVERSAL); + } + } + break; + + case 4033: // Halls of Lightning + { + if (player->getLevel() >= 75) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 9121.08f, -1330.12f, 1060.32f, 5.577f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 75!", LANG_UNIVERSAL); + } + } + break; + + case 4034: // Frozen Halls + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(571, 5635.59f, 2052.15f, 798.045f, 4.580f); + player->ModifyMoney(-400*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + + case 4035: // Onyxia's Lair + { + if (player->getLevel() >= 80) + { + player->CLOSE_GOSSIP_MENU(); + player->TeleportTo(1, -4640.93f, -3623.18f, 39.461f, 4.474f); + player->ModifyMoney(-800*costo); + } + else + { + player->CLOSE_GOSSIP_MENU(); + _Creature->MonsterSay("You must be at least level 80!", LANG_UNIVERSAL); + } + } + break; + } +} + +bool GossipSelect_mob_teleguy(Player* player, Creature* _Creature, uint32 sender, uint32 action) +{ + // Main menu + if (sender == GOSSIP_SENDER_MAIN) + { + player->PlayerTalkClass->ClearMenus(); + SendDefaultMenu_mob_teleguy(player, _Creature, action); + } + return true; +} + +void AddSC_mob_teleguy() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_teleguy"; + pNewScript->pGossipHello = &GossipHello_mob_teleguy; + pNewScript->pGossipSelect = &GossipSelect_mob_teleguy; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/alterac_mountains.cpp b/scripts/eastern_kingdoms/alterac_mountains.cpp index e8f95e14e1..e46aa0688b 100644 --- a/scripts/eastern_kingdoms/alterac_mountains.cpp +++ b/scripts/eastern_kingdoms/alterac_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,7 +26,6 @@ EndContentData */ #include "precompiled.h" -/*void AddSC_alterac_mountains() +void AddSC_alterac_mountains() { - Script *newscript; -}*/ +} diff --git a/scripts/eastern_kingdoms/arathi_highlands.cpp b/scripts/eastern_kingdoms/arathi_highlands.cpp index a3f2df5227..32b57e8dbb 100644 --- a/scripts/eastern_kingdoms/arathi_highlands.cpp +++ b/scripts/eastern_kingdoms/arathi_highlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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" @@ -55,21 +56,21 @@ struct MANGOS_DLL_DECL npc_professor_phizzlethorpeAI : public npc_escortAI void Reset() { } - 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,11 +101,11 @@ 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())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest, true); + pEscortAI->Start(false, pPlayer, pQuest, true); } return true; } @@ -114,13 +115,151 @@ 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 MANGOS_DLL_DECL npc_kineloryAI : public npc_escortAI +{ + npc_kineloryAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiBearFormTimer; + uint32 m_uiHealTimer; + + void Reset() + { + 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 * newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_professor_phizzlethorpe"; + pNewScript->GetAI = &GetAI_npc_professor_phizzlethorpe; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_professor_phizzlethorpe; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_professor_phizzlethorpe"; - newscript->GetAI = &GetAI_npc_professor_phizzlethorpe; - newscript->pQuestAccept = &QuestAccept_npc_professor_phizzlethorpe; - newscript->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/bastion_of_twilight/ascendant_council.cpp b/scripts/eastern_kingdoms/bastion_of_twilight/ascendant_council.cpp new file mode 100644 index 0000000000..82a854bb54 --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/ascendant_council.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: ascendant_council +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Bastion of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_ascendant_council() +{ +} diff --git a/scripts/eastern_kingdoms/bastion_of_twilight/bastion_of_twilight.h b/scripts/eastern_kingdoms/bastion_of_twilight/bastion_of_twilight.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/bastion_of_twilight.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/eastern_kingdoms/bastion_of_twilight/boss_chogall.cpp b/scripts/eastern_kingdoms/bastion_of_twilight/boss_chogall.cpp new file mode 100644 index 0000000000..7512a7d048 --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/boss_chogall.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_chogall +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Bastion of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_chogall() +{ +} diff --git a/scripts/eastern_kingdoms/bastion_of_twilight/boss_halfus_wyrmbreaker.cpp b/scripts/eastern_kingdoms/bastion_of_twilight/boss_halfus_wyrmbreaker.cpp new file mode 100644 index 0000000000..aff3077d8b --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/boss_halfus_wyrmbreaker.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_halfus_wyrmbreaker +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Bastion of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_halfus_wyrmbreaker() +{ +} diff --git a/scripts/eastern_kingdoms/bastion_of_twilight/boss_sinestra.cpp b/scripts/eastern_kingdoms/bastion_of_twilight/boss_sinestra.cpp new file mode 100644 index 0000000000..2bb9556917 --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/boss_sinestra.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_sinestra +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Bastion of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_sinestra() +{ +} diff --git a/scripts/eastern_kingdoms/bastion_of_twilight/boss_valiona_and_theralion.cpp b/scripts/eastern_kingdoms/bastion_of_twilight/boss_valiona_and_theralion.cpp new file mode 100644 index 0000000000..7aa75ad337 --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/boss_valiona_and_theralion.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_valiona_and_theralion +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Bastion of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_valiona_and_theralion() +{ +} diff --git a/scripts/eastern_kingdoms/bastion_of_twilight/instance_bastion_of_twilight.cpp b/scripts/eastern_kingdoms/bastion_of_twilight/instance_bastion_of_twilight.cpp new file mode 100644 index 0000000000..4211e97e99 --- /dev/null +++ b/scripts/eastern_kingdoms/bastion_of_twilight/instance_bastion_of_twilight.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_bastion_of_twilight +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Bastion of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_bastion_of_twilight() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp b/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp deleted file mode 100644 index 780f89edce..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp +++ /dev/null @@ -1,754 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Blackrock_Depths -SD%Complete: 50 -SDComment: Quest support: 4001, 4342, 7604. Vendor Lokhtos Darkbargainer. -SDCategory: Blackrock Depths -EndScriptData */ - -/* ContentData -go_shadowforge_brazier -at_ring_of_law -npc_grimstone -mob_phalanx -npc_kharan_mighthammer -npc_lokhtos_darkbargainer -EndContentData */ - -#include "precompiled.h" -#include "blackrock_depths.h" -#include "escort_ai.h" - -/*###### -## go_shadowforge_brazier -######*/ - -bool GOHello_go_shadowforge_brazier(Player* pPlayer, GameObject* pGo) -{ - if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) - { - if (pInstance->GetData(TYPE_LYCEUM) == IN_PROGRESS) - pInstance->SetData(TYPE_LYCEUM, DONE); - else - pInstance->SetData(TYPE_LYCEUM, IN_PROGRESS); - } - return false; -} - -/*###### -## npc_grimstone -######*/ - -enum -{ - SAY_START_1 = -1230004, - SAY_START_2 = -1230005, - SAY_OPEN_EAST_GATE = -1230006, - SAY_SUMMON_BOSS_1 = -1230007, - SAY_SUMMON_BOSS_2 = -1230008, - SAY_OPEN_NORTH_GATE = -1230009, - - NPC_GRIMSTONE = 10096, - NPC_THELDREN = 16059, - - //4 or 6 in total? 1+2+1 / 2+2+2 / 3+3. Depending on this, code should be changed. - MAX_MOB_AMOUNT = 4 -}; - -static uint32 RingMob[]= -{ - 8925, // Dredge Worm - 8926, // Deep Stinger - 8927, // Dark Screecher - 8928, // Burrowing Thundersnout - 8933, // Cave Creeper - 8932, // Borer Beetle -}; - -static uint32 RingBoss[]= -{ - 9027, // Gorosh - 9028, // Grizzle - 9029, // Eviscerator - 9030, // Ok'thor - 9031, // Anub'shiah - 9032, // Hedrum -}; - -bool AreaTrigger_at_ring_of_law(Player* pPlayer, AreaTriggerEntry const* pAt) -{ - if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) - { - if (pInstance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || pInstance->GetData(TYPE_RING_OF_LAW) == DONE) - return false; - - pInstance->SetData(TYPE_RING_OF_LAW, IN_PROGRESS); - pPlayer->SummonCreature(NPC_GRIMSTONE, 625.559f, -205.618f, -52.735f, 2.609f, TEMPSUMMON_DEAD_DESPAWN, 0); - - return false; - } - return false; -} - -/*###### -## npc_grimstone -######*/ - -//TODO: implement quest part of event (different end boss) -struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI -{ - npc_grimstoneAI(Creature* pCreature) : npc_escortAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_uiMobSpawnId = urand(0, 5); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint8 m_uiEventPhase; - uint32 m_uiEventTimer; - - uint8 m_uiMobSpawnId; - uint8 m_uiMobCount; - uint32 m_uiMobDeathTimer; - - uint64 m_auiRingMobGUID[MAX_MOB_AMOUNT]; - uint64 m_uiRingBossGUID; - - bool m_bCanWalk; - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - memset(&m_auiRingMobGUID, 0, sizeof(m_auiRingMobGUID)); - - m_uiEventTimer = 1000; - m_uiEventPhase = 0; - m_uiMobCount = 0; - m_uiMobDeathTimer = 0; - m_uiRingBossGUID = 0; - - m_bCanWalk = false; - } - - void JustSummoned(Creature* pSummoned) - { - - } - - void SummonedCreatureJustDied(Creature* pSummoned) - { - - } - - void DoGate(uint32 id, uint32 state) - { - if (GameObject* pGo = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(id))) - pGo->SetGoState(GOState(state)); - - debug_log("SD2: npc_grimstone, arena gate update state."); - } - - //TODO: move them to center - void SummonRingMob() - { - if (Creature* pTmp = m_creature->SummonCreature(RingMob[m_uiMobSpawnId], 608.960f, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0)) - m_auiRingMobGUID[m_uiMobCount] = pTmp->GetGUID(); - - ++m_uiMobCount; - - if (m_uiMobCount == MAX_MOB_AMOUNT) - m_uiMobDeathTimer = 2500; - } - - //TODO: move them to center - void SummonRingBoss() - { - if (Creature* pTmp = m_creature->SummonCreature(RingBoss[urand(0, 5)], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0)) - m_uiRingBossGUID = pTmp->GetGUID(); - - m_uiMobDeathTimer = 2500; - } - - void WaypointReached(uint32 uiPointId) - { - switch(uiPointId) - { - case 0: // Middle reached first time - DoScriptText(urand(0, 1) ? SAY_START_1 : SAY_START_2, m_creature); - m_bCanWalk = false; - m_uiEventTimer = 5000; - break; - case 1: // Reached wall again - DoScriptText(SAY_OPEN_EAST_GATE, m_creature); - m_bCanWalk = false; - m_uiEventTimer = 5000; - break; - case 2: // walking along the wall, while door opened - m_bCanWalk = false; - break; - case 3: // Middle reached second time - DoScriptText(urand(0, 1) ? SAY_SUMMON_BOSS_1 : SAY_SUMMON_BOSS_2, m_creature); - break; - case 4: // Reached North Gate - DoScriptText(SAY_OPEN_NORTH_GATE, m_creature);//6 - m_bCanWalk = false; - m_uiEventTimer = 5000; - break; - case 5: - if (m_pInstance) - { - m_pInstance->SetData(TYPE_RING_OF_LAW, DONE); - debug_log("SD2: npc_grimstone: event reached end and set complete."); - } - break; - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_pInstance) - return; - - if (m_uiMobDeathTimer) - { - if (m_uiMobDeathTimer <= uiDiff) - { - m_uiMobDeathTimer = 2500; - - if (m_uiRingBossGUID) - { - Creature* pBoss = m_creature->GetMap()->GetCreature(m_uiRingBossGUID); - if (pBoss && !pBoss->isAlive() && pBoss->isDead()) - { - m_uiRingBossGUID = 0; - m_uiEventTimer = 5000; - m_uiMobDeathTimer = 0; - return; - } - return; - } - - for(uint8 i = 0; i < MAX_MOB_AMOUNT; ++i) - { - Creature* pMob = m_creature->GetMap()->GetCreature(m_auiRingMobGUID[i]); - if (pMob && !pMob->isAlive() && pMob->isDead()) - { - m_auiRingMobGUID[i] = 0; - --m_uiMobCount; - - //seems all are gone, so set timer to continue and discontinue this - if (!m_uiMobCount) - { - m_uiEventTimer = 5000; - m_uiMobDeathTimer = 0; - } - } - } - } - else - m_uiMobDeathTimer -= uiDiff; - } - - if (m_uiEventTimer) - { - if (m_uiEventTimer <= uiDiff) - { - switch(m_uiEventPhase) - { - case 0: - // Shortly after spawn, start walking - //DoScriptText(-1000000, m_creature); // no more text on spawn - DoGate(DATA_ARENA4, GO_STATE_READY); - Start(false); - m_bCanWalk = true; - m_uiEventTimer = 0; - break; - case 1: - // Start walking towards wall - m_bCanWalk = true; - m_uiEventTimer = 0; - break; - case 2: - m_uiEventTimer = 2000; - break; - case 3: - // Open East Gate - DoGate(DATA_ARENA1, GO_STATE_ACTIVE); - m_uiEventTimer = 3000; - break; - case 4: - m_bCanWalk = true; - m_creature->SetVisibility(VISIBILITY_OFF); - SummonRingMob(); - m_uiEventTimer = 8000; - break; - case 5: - SummonRingMob(); - SummonRingMob(); - m_uiEventTimer = 8000; - break; - case 6: - SummonRingMob(); - m_uiEventTimer = 0; - break; - case 7: - // Summoned Mobs are dead, continue event - m_creature->SetVisibility(VISIBILITY_ON); - DoGate(DATA_ARENA1, GO_STATE_READY); - //DoScriptText(-1000000, m_creature); // after killed the mobs, no say here - m_bCanWalk = true; - m_uiEventTimer = 0; - break; - case 8: - // Open North Gate - DoGate(DATA_ARENA2, GO_STATE_ACTIVE); - m_uiEventTimer = 5000; - break; - case 9: - // Summon Boss - m_creature->SetVisibility(VISIBILITY_OFF); - SummonRingBoss(); - m_uiEventTimer = 0; - break; - case 10: - // Boss dead - //if quest, complete - DoGate(DATA_ARENA2, GO_STATE_READY); - DoGate(DATA_ARENA3, GO_STATE_ACTIVE); - DoGate(DATA_ARENA4, GO_STATE_ACTIVE); - m_bCanWalk = true; - m_uiEventTimer = 0; - break; - } - ++m_uiEventPhase; - } - else - m_uiEventTimer -= uiDiff; - } - - if (m_bCanWalk) - npc_escortAI::UpdateAI(uiDiff); - } -}; - -CreatureAI* GetAI_npc_grimstone(Creature* pCreature) -{ - return new npc_grimstoneAI(pCreature); -} - -/*###### -## 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 -######*/ -enum -{ - QUEST_WHAT_IS_GOING_ON = 4001, - QUEST_KHARANS_TALE = 4342 -}; - -#define GOSSIP_ITEM_KHARAN_1 "I need to know where the princess are, Kharan!" -#define GOSSIP_ITEM_KHARAN_2 "All is not lost, Kharan!" - -#define GOSSIP_ITEM_KHARAN_3 "Gor'shak is my friend, you can trust me." -#define GOSSIP_ITEM_KHARAN_4 "Not enough, you need to tell me more." -#define GOSSIP_ITEM_KHARAN_5 "So what happened?" -#define GOSSIP_ITEM_KHARAN_6 "Continue..." -#define GOSSIP_ITEM_KHARAN_7 "So you suspect that someone on the inside was involved? That they were tipped off?" -#define GOSSIP_ITEM_KHARAN_8 "Continue with your story please." -#define GOSSIP_ITEM_KHARAN_9 "Indeed." -#define GOSSIP_ITEM_KHARAN_10 "The door is open, Kharan. You are a free man." - -bool GossipHello_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - 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); - - 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); - - if (pPlayer->GetTeam() == HORDE) - pPlayer->SEND_GOSSIP_MENU(2473, pCreature->GetGUID()); - else - pPlayer->SEND_GOSSIP_MENU(2474, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_kharan_mighthammer(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_KHARAN_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(2475, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2476, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2477, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2478, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2479, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2480, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2481, pCreature->GetGUID()); - 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->SEND_GOSSIP_MENU(2482, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - pPlayer->CLOSE_GOSSIP_MENU(); - if (pPlayer->GetTeam() == HORDE) - pPlayer->AreaExploredOrEventHappens(QUEST_WHAT_IS_GOING_ON); - else - pPlayer->AreaExploredOrEventHappens(QUEST_KHARANS_TALE); - break; - } - 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->GetGUID()); - - 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->GetGUID()); - else - pPlayer->SEND_GOSSIP_MENU(3677, pCreature->GetGUID()); - - 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->GetGUID()); - - return true; -} - -/*###### -## npc_rocknot -######*/ - -enum -{ - SAY_GOT_BEER = -1230000, - - SPELL_DRUNKEN_RAGE = 14872, - - QUEST_ALE = 4295 -}; - -struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI -{ - npc_rocknotAI(Creature* pCreature) : npc_escortAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiBreakKegTimer; - uint32 m_uiBreakDoorTimer; - - void Reset() - { - if (HasEscortState(STATE_ESCORT_ESCORTING)) - return; - - m_uiBreakKegTimer = 0; - m_uiBreakDoorTimer = 0; - } - - void DoGo(uint32 id, uint32 state) - { - if (GameObject* pGo = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(id))) - pGo->SetGoState(GOState(state)); - } - - void WaypointReached(uint32 uiPointId) - { - if (!m_pInstance) - return; - - switch(uiPointId) - { - case 1: - m_creature->HandleEmote(EMOTE_ONESHOT_KICK); - break; - case 2: - m_creature->HandleEmote(EMOTE_ONESHOT_ATTACKUNARMED); - break; - case 3: - m_creature->HandleEmote(EMOTE_ONESHOT_ATTACKUNARMED); - break; - case 4: - m_creature->HandleEmote(EMOTE_ONESHOT_KICK); - break; - case 5: - m_creature->HandleEmote(EMOTE_ONESHOT_KICK); - m_uiBreakKegTimer = 2000; - break; - } - } - - void UpdateEscortAI(const uint32 uiDiff) - { - if (!m_pInstance) - return; - - if (m_uiBreakKegTimer) - { - if (m_uiBreakKegTimer <= uiDiff) - { - DoGo(DATA_GO_BAR_KEG,0); - m_uiBreakKegTimer = 0; - m_uiBreakDoorTimer = 1000; - } - else - m_uiBreakKegTimer -= uiDiff; - } - - if (m_uiBreakDoorTimer) - { - if (m_uiBreakDoorTimer <= uiDiff) - { - DoGo(DATA_GO_BAR_DOOR, 2); - DoGo(DATA_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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_PHALANX))) - pTmp->setFaction(14); - - // for later, this event(s) has alot more to it. - // optionally, DONE can trigger bar to go hostile. - m_pInstance->SetData(TYPE_BAR, DONE); - - m_uiBreakDoorTimer = 0; - } - else - m_uiBreakDoorTimer -= uiDiff; - } - } -}; - -CreatureAI* GetAI_npc_rocknot(Creature* pCreature) -{ - return new npc_rocknotAI(pCreature); -} - -bool ChooseReward_npc_rocknot(Player* pPlayer, Creature* pCreature, const Quest* pQuest, uint32 item) -{ - ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - - if (!pInstance) - return true; - - if (pInstance->GetData(TYPE_BAR) == DONE || pInstance->GetData(TYPE_BAR) == SPECIAL) - return true; - - if (pQuest->GetQuestId() == QUEST_ALE) - { - if (pInstance->GetData(TYPE_BAR) != IN_PROGRESS) - pInstance->SetData(TYPE_BAR,IN_PROGRESS); - - 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) - { - DoScriptText(SAY_GOT_BEER, pCreature); - pCreature->CastSpell(pCreature, SPELL_DRUNKEN_RAGE, false); - - if (npc_rocknotAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, 0, NULL, true); - } - } - - return true; -} - -void AddSC_blackrock_depths() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "go_shadowforge_brazier"; - pNewScript->pGOHello = &GOHello_go_shadowforge_brazier; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_ring_of_law"; - pNewScript->pAreaTrigger = &AreaTrigger_at_ring_of_law; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_grimstone"; - pNewScript->GetAI = &GetAI_npc_grimstone; - 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->pChooseReward = &ChooseReward_npc_rocknot; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h b/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h deleted file mode 100644 index 439b97b3f1..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_BRD_H -#define DEF_BRD_H - -enum -{ - TYPE_RING_OF_LAW = 1, - TYPE_VAULT = 2, - TYPE_BAR = 3, - TYPE_TOMB_OF_SEVEN = 4, - TYPE_LYCEUM = 5, - TYPE_IRON_HALL = 6, - - DATA_EMPEROR = 10, - DATA_PRINCESS = 11, - DATA_PHALANX = 12, - DATA_HATEREL = 13, - DATA_ANGERREL = 14, - DATA_VILEREL = 15, - DATA_GLOOMREL = 16, - DATA_SEETHREL = 17, - DATA_DOOMREL = 18, - DATA_DOPEREL = 19, - - DATA_ARENA1 = 20, - DATA_ARENA2 = 21, - DATA_ARENA3 = 22, - DATA_ARENA4 = 23, - - DATA_GO_BAR_KEG = 24, - DATA_GO_BAR_KEG_TRAP = 25, - DATA_GO_BAR_DOOR = 26, - DATA_GO_CHALICE = 27, - DATA_GO_TOMB_EXIT = 28 -}; - -#endif diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp deleted file mode 100644 index 00786846a4..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Ambassador_Flamelash -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FIREBLAST 15573 - -struct MANGOS_DLL_DECL boss_ambassador_flamelashAI : public ScriptedAI -{ - boss_ambassador_flamelashAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 FireBlast_Timer; - uint32 Spirit_Timer; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - FireBlast_Timer = 2000; - Spirit_Timer = 24000; - } - - void SummonSpirits(Unit* victim) - { - Rand = rand()%10; - switch(urand(0, 1)) - { - case 0: RandX -= Rand; break; - case 1: RandX += Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch(urand(0, 1)) - { - case 0: RandY -= Rand; break; - case 1: RandY += Rand; break; - } - Summoned = DoSpawnCreature(9178, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - 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; - - //FireBlast_Timer - if (FireBlast_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FIREBLAST); - FireBlast_Timer = 7000; - }else FireBlast_Timer -= diff; - - //Spirit_Timer - if (Spirit_Timer < diff) - { - SummonSpirits(m_creature->getVictim()); - SummonSpirits(m_creature->getVictim()); - SummonSpirits(m_creature->getVictim()); - SummonSpirits(m_creature->getVictim()); - - Spirit_Timer = 30000; - }else Spirit_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ambassador_flamelash(Creature* pCreature) -{ - return new boss_ambassador_flamelashAI(pCreature); -} - -void AddSC_boss_ambassador_flamelash() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_ambassador_flamelash"; - newscript->GetAI = &GetAI_boss_ambassador_flamelash; - newscript->RegisterSelf(); -} 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 5c2063e098..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" - -#define SPELL_SHADOWBOLT 17228 -#define SPELL_CURSEOFTONGUES 15470 -#define SPELL_CURSEOFWEAKNESS 17227 -#define SPELL_DEMONARMOR 11735 -#define SPELL_ENVELOPINGWEB 15471 - -struct MANGOS_DLL_DECL boss_anubshiahAI : public ScriptedAI -{ - boss_anubshiahAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowBolt_Timer; - uint32 CurseOfTongues_Timer; - uint32 CurseOfWeakness_Timer; - uint32 DemonArmor_Timer; - uint32 EnvelopingWeb_Timer; - - void Reset() - { - ShadowBolt_Timer = 7000; - CurseOfTongues_Timer = 24000; - CurseOfWeakness_Timer = 12000; - DemonArmor_Timer = 3000; - EnvelopingWeb_Timer = 16000; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWBOLT); - ShadowBolt_Timer = 7000; - }else ShadowBolt_Timer -= diff; - - //CurseOfTongues_Timer - if (CurseOfTongues_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_CURSEOFTONGUES); - CurseOfTongues_Timer = 18000; - }else CurseOfTongues_Timer -= diff; - - //CurseOfWeakness_Timer - if (CurseOfWeakness_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); - CurseOfWeakness_Timer = 45000; - }else CurseOfWeakness_Timer -= diff; - - //DemonArmor_Timer - if (DemonArmor_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_DEMONARMOR); - DemonArmor_Timer = 300000; - }else DemonArmor_Timer -= diff; - - //EnvelopingWeb_Timer - if (EnvelopingWeb_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_ENVELOPINGWEB); - EnvelopingWeb_Timer = 12000; - }else EnvelopingWeb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_anubshiah(Creature* pCreature) -{ - return new boss_anubshiahAI(pCreature); -} - -void AddSC_boss_anubshiah() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_anubshiah"; - newscript->GetAI = &GetAI_boss_anubshiah; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp deleted file mode 100644 index 727ab35007..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_General_Angerforge -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_MIGHTYBLOW 14099 -#define SPELL_HAMSTRING 9080 -#define SPELL_CLEAVE 20691 - -struct MANGOS_DLL_DECL boss_general_angerforgeAI : public ScriptedAI -{ - boss_general_angerforgeAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 MightyBlow_Timer; - uint32 HamString_Timer; - uint32 Cleave_Timer; - uint32 Adds_Timer; - bool Medics; - int Rand1; - int Rand1X; - int Rand1Y; - int Rand2; - int Rand2X; - int Rand2Y; - Creature* SummonedAdds; - Creature* SummonedMedics; - - void Reset() - { - MightyBlow_Timer = 8000; - HamString_Timer = 12000; - Cleave_Timer = 16000; - Adds_Timer = 0; - Medics = false; - } - - void SummonAdds(Unit* victim) - { - Rand1 = rand()%15; - switch(urand(0, 1)) - { - case 0: Rand1X = 0 - Rand1; break; - case 1: Rand1X = 0 + Rand1; break; - } - Rand1 = 0; - Rand1 = rand()%15; - switch(urand(0, 1)) - { - case 0: Rand1Y = 0 - Rand1; break; - case 1: Rand1Y = 0 + Rand1; break; - } - Rand1 = 0; - SummonedAdds = DoSpawnCreature(8901, Rand1X, Rand1Y, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); - if (SummonedAdds) - SummonedAdds->AI()->AttackStart(victim); - } - - void SummonMedics(Unit* victim) - { - Rand2 = rand()%10; - switch(urand(0, 1)) - { - case 0: Rand2X = 0 - Rand2; break; - case 1: Rand2X = 0 + Rand2; break; - } - Rand2 = 0; - Rand2 = rand()%10; - switch(urand(0, 1)) - { - case 0: Rand2Y = 0 - Rand2; break; - case 1: Rand2Y = 0 + Rand2; break; - } - Rand2 = 0; - SummonedMedics = DoSpawnCreature(8894, Rand2X, Rand2Y, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); - if (SummonedMedics) - SummonedMedics->AI()->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //MightyBlow_Timer - if (MightyBlow_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MIGHTYBLOW); - MightyBlow_Timer = 18000; - }else MightyBlow_Timer -= diff; - - //HamString_Timer - if (HamString_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HAMSTRING); - HamString_Timer = 15000; - }else HamString_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 9000; - }else Cleave_Timer -= diff; - - //Adds_Timer - if (m_creature->GetHealthPercent() < 21.0f) - { - if (Adds_Timer < diff) - { - // summon 3 Adds every 25s - SummonAdds(m_creature->getVictim()); - SummonAdds(m_creature->getVictim()); - SummonAdds(m_creature->getVictim()); - - Adds_Timer = 25000; - } else Adds_Timer -= diff; - } - - //Summon Medics - if (!Medics && m_creature->GetHealthPercent() < 21.0f) - { - SummonMedics(m_creature->getVictim()); - SummonMedics(m_creature->getVictim()); - Medics = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_general_angerforge(Creature* pCreature) -{ - return new boss_general_angerforgeAI(pCreature); -} - -void AddSC_boss_general_angerforge() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_general_angerforge"; - newscript->GetAI = &GetAI_boss_general_angerforge; - newscript->RegisterSelf(); -} 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 4632c66a27..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" - -#define SPELL_WHIRLWIND 15589 -#define SPELL_MORTALSTRIKE 24573 - -struct MANGOS_DLL_DECL boss_gorosh_the_dervishAI : public ScriptedAI -{ - boss_gorosh_the_dervishAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 WhirlWind_Timer; - uint32 MortalStrike_Timer; - - void Reset() - { - WhirlWind_Timer = 12000; - MortalStrike_Timer = 22000; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //WhirlWind_Timer - if (WhirlWind_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_WHIRLWIND); - WhirlWind_Timer = 15000; - }else WhirlWind_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = 15000; - }else MortalStrike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gorosh_the_dervish(Creature* pCreature) -{ - return new boss_gorosh_the_dervishAI(pCreature); -} - -void AddSC_boss_gorosh_the_dervish() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_gorosh_the_dervish"; - newscript->GetAI = &GetAI_boss_gorosh_the_dervish; - newscript->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 94e97f4e5a..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" - -#define EMOTE_GENERIC_FRENZY_KILL -1000001 - -#define SPELL_GROUNDTREMOR 6524 -#define SPELL_FRENZY 28371 - -struct MANGOS_DLL_DECL boss_grizzleAI : public ScriptedAI -{ - boss_grizzleAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 GroundTremor_Timer; - uint32 Frenzy_Timer; - - void Reset() - { - GroundTremor_Timer = 12000; - Frenzy_Timer =0; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //GroundTremor_Timer - if (GroundTremor_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GROUNDTREMOR); - GroundTremor_Timer = 8000; - }else GroundTremor_Timer -= diff; - - //Frenzy_Timer - if (m_creature->GetHealthPercent() < 51.0f) - { - if (Frenzy_Timer < diff) - { - if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - Frenzy_Timer = 15000; - } - }else Frenzy_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_grizzle(Creature* pCreature) -{ - return new boss_grizzleAI(pCreature); -} - -void AddSC_boss_grizzle() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_grizzle"; - newscript->GetAI = &GetAI_boss_grizzle; - newscript->RegisterSelf(); -} 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 07d533fd2d..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_uiFieryBurst_Timer; - uint32 m_uiWarStomp_Timer; - - void Reset() - { - m_uiFieryBurst_Timer = 5000; - m_uiWarStomp_Timer = 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_uiFieryBurst_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FIERYBURST); - m_uiFieryBurst_Timer = 6000; - } - else - m_uiFieryBurst_Timer -= uiDiff; - - //WarStomp_Timer - if (m_creature->GetHealthPercent() < 51.0f) - { - if (m_uiWarStomp_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_WARSTOMP); - m_uiWarStomp_Timer = 8000; - } - else - m_uiWarStomp_Timer -= uiDiff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_magmus(Creature* pCreature) -{ - return new boss_magmusAI(pCreature); -} - -void AddSC_boss_magmus() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_magmus"; - newscript->GetAI = &GetAI_boss_magmus; - newscript->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 ccf1dba32d..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* Copyright (C) 2006 - 2010 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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(pInstance->GetData64(DATA_GO_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->instance->GetCreature(m_pInstance->GetData64(DATA_ANGERREL)); - case 1: - return m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_SEETHREL)); - case 2: - return m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_DOPEREL)); - case 3: - return m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_GLOOMREL)); - case 4: - return m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_VILEREL)); - case 5: - return m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_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->GetGUID()); - 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_gloomrel"; - newscript->pGossipHello = &GossipHello_boss_gloomrel; - newscript->pGossipSelect = &GossipSelect_boss_gloomrel; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_doomrel"; - newscript->GetAI = &GetAI_boss_doomrel; - newscript->pGossipHello = &GossipHello_boss_doomrel; - newscript->pGossipSelect = &GossipSelect_boss_doomrel; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp b/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp deleted file mode 100644 index b80aaee7e3..0000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Instance_Blackrock_Depths -SD%Complete: 20 -SDComment: events: ring of law -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" -#include "blackrock_depths.h" - -enum -{ - MAX_ENCOUNTER = 6, - - NPC_EMPEROR = 9019, - NPC_PRINCESS = 8929, - NPC_PHALANX = 9502, - NPC_HATEREL = 9034, - NPC_ANGERREL = 9035, - NPC_VILEREL = 9036, - NPC_GLOOMREL = 9037, - NPC_SEETHREL = 9038, - NPC_DOOMREL = 9039, - NPC_DOPEREL = 9040, - - GO_ARENA1 = 161525, - GO_ARENA2 = 161522, - GO_ARENA3 = 161524, - GO_ARENA4 = 161523, - GO_SHADOW_LOCK = 161460, - GO_SHADOW_MECHANISM = 161461, - GO_SHADOW_GIANT_DOOR = 157923, - GO_SHADOW_DUMMY = 161516, - GO_BAR_KEG_SHOT = 170607, - GO_BAR_KEG_TRAP = 171941, - GO_BAR_DOOR = 170571, - GO_TOMB_ENTER = 170576, - GO_TOMB_EXIT = 170577, - GO_LYCEUM = 170558, - GO_GOLEM_ROOM_N = 170573, - GO_GOLEM_ROOM_S = 170574, - GO_THRONE_ROOM = 170575, - - GO_SPECTRAL_CHALICE = 164869, - GO_CHEST_SEVEN = 169243 -}; - -struct MANGOS_DLL_DECL instance_blackrock_depths : public ScriptedInstance -{ - instance_blackrock_depths(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiEmperorGUID; - uint64 m_uiPrincessGUID; - uint64 m_uiPhalanxGUID; - uint64 m_uiHaterelGUID; - uint64 m_uiAngerrelGUID; - uint64 m_uiVilerelGUID; - uint64 m_uiGloomrelGUID; - uint64 m_uiSeethrelGUID; - uint64 m_uiDoomrelGUID; - uint64 m_uiDoperelGUID; - - uint64 m_uiGoArena1GUID; - uint64 m_uiGoArena2GUID; - uint64 m_uiGoArena3GUID; - uint64 m_uiGoArena4GUID; - uint64 m_uiGoShadowLockGUID; - uint64 m_uiGoShadowMechGUID; - uint64 m_uiGoShadowGiantGUID; - uint64 m_uiGoShadowDummyGUID; - uint64 m_uiGoBarKegGUID; - uint64 m_uiGoBarKegTrapGUID; - uint64 m_uiGoBarDoorGUID; - uint64 m_uiGoTombEnterGUID; - uint64 m_uiGoTombExitGUID; - uint64 m_uiGoLyceumGUID; - uint64 m_uiGoGolemNGUID; - uint64 m_uiGoGolemSGUID; - uint64 m_uiGoThroneGUID; - - uint64 m_uiSpectralChaliceGUID; - uint64 m_uiSevensChestGUID; - - uint32 m_uiBarAleCount; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiEmperorGUID = 0; - m_uiPrincessGUID = 0; - m_uiPhalanxGUID = 0; - m_uiHaterelGUID = 0; - m_uiAngerrelGUID = 0; - m_uiVilerelGUID = 0; - m_uiGloomrelGUID = 0; - m_uiSeethrelGUID = 0; - m_uiDoomrelGUID = 0; - m_uiDoperelGUID = 0; - - m_uiGoArena1GUID = 0; - m_uiGoArena2GUID = 0; - m_uiGoArena3GUID = 0; - m_uiGoArena4GUID = 0; - m_uiGoShadowLockGUID = 0; - m_uiGoShadowMechGUID = 0; - m_uiGoShadowGiantGUID = 0; - m_uiGoShadowDummyGUID = 0; - m_uiGoBarKegGUID = 0; - m_uiGoBarKegTrapGUID = 0; - m_uiGoBarDoorGUID = 0; - m_uiGoTombEnterGUID = 0; - m_uiGoTombExitGUID = 0; - m_uiGoLyceumGUID = 0; - m_uiGoGolemNGUID = 0; - m_uiGoGolemSGUID = 0; - m_uiGoThroneGUID = 0; - - m_uiSpectralChaliceGUID = 0; - m_uiSevensChestGUID = 0; - - m_uiBarAleCount = 0; - } - - void OnCreatureCreate(Creature* pCreature) - { - switch(pCreature->GetEntry()) - { - case NPC_EMPEROR: m_uiEmperorGUID = pCreature->GetGUID(); break; - case NPC_PRINCESS: m_uiPrincessGUID = pCreature->GetGUID(); break; - case NPC_PHALANX: m_uiPhalanxGUID = pCreature->GetGUID(); break; - case NPC_HATEREL: m_uiHaterelGUID = pCreature->GetGUID(); break; - case NPC_ANGERREL: m_uiAngerrelGUID = pCreature->GetGUID(); break; - case NPC_VILEREL: m_uiVilerelGUID = pCreature->GetGUID(); break; - case NPC_GLOOMREL: m_uiGloomrelGUID = pCreature->GetGUID(); break; - case NPC_SEETHREL: m_uiSeethrelGUID = pCreature->GetGUID(); break; - case NPC_DOOMREL: m_uiDoomrelGUID = pCreature->GetGUID(); break; - case NPC_DOPEREL: m_uiDoperelGUID = pCreature->GetGUID(); break; - } - } - - void OnObjectCreate(GameObject* pGo) - { - switch(pGo->GetEntry()) - { - case GO_ARENA1: m_uiGoArena1GUID = pGo->GetGUID(); break; - case GO_ARENA2: m_uiGoArena2GUID = pGo->GetGUID(); break; - case GO_ARENA3: m_uiGoArena3GUID = pGo->GetGUID(); break; - case GO_ARENA4: m_uiGoArena4GUID = pGo->GetGUID(); break; - case GO_SHADOW_LOCK: m_uiGoShadowLockGUID = pGo->GetGUID(); break; - case GO_SHADOW_MECHANISM: m_uiGoShadowMechGUID = pGo->GetGUID(); break; - case GO_SHADOW_GIANT_DOOR: m_uiGoShadowGiantGUID = pGo->GetGUID(); break; - case GO_SHADOW_DUMMY: m_uiGoShadowDummyGUID = pGo->GetGUID(); break; - case GO_BAR_KEG_SHOT: m_uiGoBarKegGUID = pGo->GetGUID(); break; - case GO_BAR_KEG_TRAP: m_uiGoBarKegTrapGUID = pGo->GetGUID(); break; - case GO_BAR_DOOR: m_uiGoBarDoorGUID = pGo->GetGUID(); break; - case GO_TOMB_ENTER: m_uiGoTombEnterGUID = pGo->GetGUID(); break; - case GO_TOMB_EXIT: m_uiGoTombExitGUID = pGo->GetGUID(); break; - case GO_LYCEUM: m_uiGoLyceumGUID = pGo->GetGUID(); break; - case GO_GOLEM_ROOM_N: m_uiGoGolemNGUID = pGo->GetGUID(); break; - case GO_GOLEM_ROOM_S: m_uiGoGolemSGUID = pGo->GetGUID(); break; - case GO_THRONE_ROOM: m_uiGoThroneGUID = pGo->GetGUID(); break; - case GO_SPECTRAL_CHALICE: m_uiSpectralChaliceGUID = pGo->GetGUID(); break; - case GO_CHEST_SEVEN: m_uiSevensChestGUID = pGo->GetGUID(); break; - } - } - - void SetData(uint32 uiType, uint32 uiData) - { - debug_log("SD2: Instance Blackrock Depths: SetData update (Type: %u Data %u)", uiType, uiData); - - switch(uiType) - { - case TYPE_RING_OF_LAW: - m_auiEncounter[0] = uiData; - break; - case TYPE_VAULT: - m_auiEncounter[1] = uiData; - break; - case TYPE_BAR: - if (uiData == SPECIAL) - ++m_uiBarAleCount; - else - m_auiEncounter[2] = uiData; - break; - case TYPE_TOMB_OF_SEVEN: - switch(uiData) - { - case IN_PROGRESS: - DoUseDoorOrButton(m_uiGoTombEnterGUID); - break; - case FAIL: - if (m_auiEncounter[3] == IN_PROGRESS)//prevent use more than one time - DoUseDoorOrButton(m_uiGoTombEnterGUID); - break; - case DONE: - DoRespawnGameObject(m_uiSevensChestGUID, HOUR*IN_MILLISECONDS); - DoUseDoorOrButton(m_uiGoTombExitGUID); - DoUseDoorOrButton(m_uiGoTombEnterGUID); - break; - } - m_auiEncounter[3] = uiData; - break; - case TYPE_LYCEUM: - if (uiData == DONE) - { - DoUseDoorOrButton(m_uiGoGolemNGUID); - DoUseDoorOrButton(m_uiGoGolemSGUID); - } - m_auiEncounter[4] = uiData; - break; - case TYPE_IRON_HALL: - switch(uiData) - { - case IN_PROGRESS: - DoUseDoorOrButton(m_uiGoGolemNGUID); - DoUseDoorOrButton(m_uiGoGolemSGUID); - break; - case FAIL: - DoUseDoorOrButton(m_uiGoGolemNGUID); - DoUseDoorOrButton(m_uiGoGolemSGUID); - break; - case DONE: - DoUseDoorOrButton(m_uiGoGolemNGUID); - DoUseDoorOrButton(m_uiGoGolemSGUID); - DoUseDoorOrButton(m_uiGoThroneGUID); - break; - } - m_auiEncounter[5] = 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]; - - strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } - - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_RING_OF_LAW: - return m_auiEncounter[0]; - case TYPE_VAULT: - return m_auiEncounter[1]; - case TYPE_BAR: - if (m_auiEncounter[2] == IN_PROGRESS && m_uiBarAleCount == 3) - return SPECIAL; - else - return m_auiEncounter[2]; - case TYPE_TOMB_OF_SEVEN: - return m_auiEncounter[3]; - case TYPE_LYCEUM: - return m_auiEncounter[4]; - case TYPE_IRON_HALL: - return m_auiEncounter[5]; - } - return 0; - } - - uint64 GetData64(uint32 uiData) - { - switch(uiData) - { - case DATA_EMPEROR: - return m_uiEmperorGUID; - case DATA_PRINCESS: - return m_uiPrincessGUID; - case DATA_PHALANX: - return m_uiPhalanxGUID; - case DATA_HATEREL: - return m_uiHaterelGUID; - case DATA_ANGERREL: - return m_uiAngerrelGUID; - case DATA_VILEREL: - return m_uiVilerelGUID; - case DATA_GLOOMREL: - return m_uiGloomrelGUID; - case DATA_SEETHREL: - return m_uiSeethrelGUID; - case DATA_DOOMREL: - return m_uiDoomrelGUID; - case DATA_DOPEREL: - return m_uiDoperelGUID; - - case DATA_ARENA1: - return m_uiGoArena1GUID; - case DATA_ARENA2: - return m_uiGoArena2GUID; - case DATA_ARENA3: - return m_uiGoArena3GUID; - case DATA_ARENA4: - return m_uiGoArena4GUID; - - case DATA_GO_BAR_KEG: - return m_uiGoBarKegGUID; - case DATA_GO_BAR_KEG_TRAP: - return m_uiGoBarKegTrapGUID; - case DATA_GO_BAR_DOOR: - return m_uiGoBarDoorGUID; - case DATA_GO_CHALICE: - return m_uiSpectralChaliceGUID; - case DATA_GO_TOMB_EXIT: - return m_uiGoTombExitGUID; - } - return 0; - } - - const char* Save() - { - return strInstData.c_str(); - } - - void Load(const char* in) - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - - std::istringstream loadStream(in); - 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) - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - - OUT_LOAD_INST_DATA_COMPLETE; - } -}; - -InstanceData* GetInstanceData_instance_blackrock_depths(Map* pMap) -{ - return new instance_blackrock_depths(pMap); -} - -void AddSC_instance_blackrock_depths() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_blackrock_depths"; - newscript->GetInstanceData = &GetInstanceData_instance_blackrock_depths; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/blackrock_caverns.h b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/blackrock_caverns.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/blackrock_caverns.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_beauty.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_beauty.cpp new file mode 100644 index 0000000000..78461206f4 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_beauty.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_beauty +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackrock Caverns +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_beauty() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_corla.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_corla.cpp new file mode 100644 index 0000000000..42f27d3fff --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_corla.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_corla +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackrock Caverns +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_corla() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_karsh_steelbender.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_karsh_steelbender.cpp new file mode 100644 index 0000000000..931fcfd8c0 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_karsh_steelbender.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_karsh_steelbender +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackrock Caverns +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_karsh_steelbender() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_lord_obsidius.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_lord_obsidius.cpp new file mode 100644 index 0000000000..8e021af6f6 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_lord_obsidius.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lord_obsidius +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackrock Caverns +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lord_obsidius() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_romogg.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_romogg.cpp new file mode 100644 index 0000000000..289ca8d4f3 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/boss_romogg.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_romogg +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackrock Caverns +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_romogg() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/instance_blackrock_caverns.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/instance_blackrock_caverns.cpp new file mode 100644 index 0000000000..0ed0c1dd9a --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_caverns/instance_blackrock_caverns.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_blackrock_caverns +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackrock Caverns +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_blackrock_caverns() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp new file mode 100644 index 0000000000..01e0a389e9 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp @@ -0,0 +1,1114 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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: Blackrock_Depths +SD%Complete: 80 +SDComment: Quest support: 4001, 4322, 4342, 7604, 9015. +SDCategory: Blackrock Depths +EndScriptData */ + +/* ContentData +go_shadowforge_brazier +go_relic_coffer_door +at_ring_of_law +npc_grimstone +npc_kharan_mighthammer +npc_marshal_windsor +npc_dughal_stormwing +npc_tobias_seecher +boss_doomrel +EndContentData */ + +#include "precompiled.h" +#include "blackrock_depths.h" +#include "escort_ai.h" + +/*###### +## go_shadowforge_brazier +######*/ + +bool GOUse_go_shadowforge_brazier(Player* /*pPlayer*/, GameObject* pGo) +{ + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) + { + if (pInstance->GetData(TYPE_LYCEUM) == IN_PROGRESS) + pInstance->SetData(TYPE_LYCEUM, DONE); + else + pInstance->SetData(TYPE_LYCEUM, IN_PROGRESS); + } + return false; +} + +/*###### +## go_relic_coffer_door +######*/ + +bool GOUse_go_relic_coffer_door(Player* /*pPlayer*/, GameObject* pGo) +{ + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) + { + // check if the event is already done + if (pInstance->GetData(TYPE_VAULT) != DONE && pInstance->GetData(TYPE_VAULT) != IN_PROGRESS) + pInstance->SetData(TYPE_VAULT, SPECIAL); + } + + return false; +} + +/*###### +## npc_grimstone +######*/ + +/* Notes about this event: + * Visual: Npc Grimstone should use some visual spell when appear/ disappear / opening/ closing doors + * Texts: The texts and their positions need confirmation + * Event timer might also need adjustment + * Quest-Event: This needs to be clearified - there is some suggestion, that Theldren&Adds also might come as first wave. + */ + +enum +{ + SAY_START_1 = -1230004, + SAY_START_2 = -1230005, + SAY_OPEN_EAST_GATE = -1230006, + SAY_SUMMON_BOSS_1 = -1230007, + SAY_SUMMON_BOSS_2 = -1230008, + SAY_OPEN_NORTH_GATE = -1230009, + + 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. + 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 + SPELL_ASHCROMBES_TELEPORT_B = 6422, + SPELL_ARENA_FLASH_A = 15737, + SPELL_ARENA_FLASH_B = 15739, + */ + + QUEST_THE_CHALLENGE = 9015, + NPC_THELDREN_QUEST_CREDIT = 16166, +}; + +enum SpawnPosition +{ + POS_EAST = 0, + POS_NORTH = 1, + POS_GRIMSTONE = 2, +}; + +static const float aSpawnPositions[3][4] = +{ + {608.960f, -235.322f, -53.907f, 1.857f}, // Ring mob spawn position + {644.300f, -175.989f, -53.739f, 3.418f}, // Ring boss spawn position + {625.559f, -205.618f, -52.735f, 2.609f} // Grimstone spawn position +}; + +static const uint32 aGladiator[MAX_POSSIBLE_THELDREN_ADDS] = {NPC_LEFTY, NPC_ROTFANG, NPC_SNOKH, NPC_MALGEN, NPC_KORV, NPC_REZZNIK, NPC_VAJASHNI, NPC_VOLIDA}; +static const uint32 aRingMob[] = {NPC_WORM, NPC_STINGER, NPC_SCREECHER, NPC_THUNDERSNOUT, NPC_CREEPER, NPC_BEETLE}; +static const uint32 aRingBoss[] = {NPC_GOROSH, NPC_GRIZZLE, NPC_EVISCERATOR, NPC_OKTHOR, NPC_ANUBSHIAH, NPC_HEDRUM}; + +enum Phases +{ + PHASE_MOBS = 0, + PHASE_BOSS = 2, + PHASE_GLADIATORS = 3, +}; + +bool AreaTrigger_at_ring_of_law(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (instance_blackrock_depths* pInstance = (instance_blackrock_depths*)pPlayer->GetInstanceData()) + { + if (pInstance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || pInstance->GetData(TYPE_RING_OF_LAW) == DONE || pInstance->GetData(TYPE_RING_OF_LAW) == SPECIAL) + return false; + + if (pPlayer->isGameMaster()) + return false; + + pInstance->SetData(TYPE_RING_OF_LAW, pInstance->GetData(TYPE_RING_OF_LAW) == DATA_BANNER_BEFORE_EVENT ? SPECIAL : IN_PROGRESS); + + pPlayer->SummonCreature(NPC_GRIMSTONE, aSpawnPositions[POS_GRIMSTONE][0], aSpawnPositions[POS_GRIMSTONE][1], aSpawnPositions[POS_GRIMSTONE][2], aSpawnPositions[POS_GRIMSTONE][3], TEMPSUMMON_DEAD_DESPAWN, 0); + pInstance->SetArenaCenterCoords(pAt->x, pAt->y, pAt->z); + + return false; + } + return false; +} + +/*###### +## npc_grimstone +######*/ + +struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI +{ + npc_grimstoneAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (instance_blackrock_depths*)pCreature->GetInstanceData(); + m_uiMobSpawnId = urand(0, 5); + // Select MAX_THELDREN_ADDS(4) random adds for Theldren encounter + uint8 uiCount = 0; + for (uint8 i = 0; i < MAX_POSSIBLE_THELDREN_ADDS && uiCount < MAX_THELDREN_ADDS; ++i) + { + if (urand(0, 1) || i >= MAX_POSSIBLE_THELDREN_ADDS - MAX_THELDREN_ADDS + uiCount) + { + m_uiGladiatorId[uiCount] = aGladiator[i]; + ++uiCount; + } + } + + Reset(); + } + + instance_blackrock_depths* m_pInstance; + + uint8 m_uiEventPhase; + uint32 m_uiEventTimer; + + uint8 m_uiMobSpawnId; + uint8 m_uiMobDeadCount; + + Phases m_uiPhase; + + uint32 m_uiGladiatorId[MAX_THELDREN_ADDS]; + + GuidList m_lSummonedGuidList; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_uiEventTimer = 1000; + m_uiEventPhase = 0; + m_uiMobDeadCount = 0; + + m_uiPhase = PHASE_MOBS; + } + + void JustSummoned(Creature* pSummoned) override + { + if (!m_pInstance) + return; + + // Ring mob or boss summoned + float fX, fY, fZ; + float fcX, fcY, fcZ; + m_pInstance->GetArenaCenterCoords(fX, fY, fZ); + m_creature->GetRandomPoint(fX, fY, fZ, 10.0f, fcX, fcY, fcZ); + pSummoned->GetMotionMaster()->MovePoint(1, fcX, fcY, fcZ); + + m_lSummonedGuidList.push_back(pSummoned->GetObjectGuid()); + } + + void DoChallengeQuestCredit() + { + 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_THE_CHALLENGE) == QUEST_STATUS_INCOMPLETE) + pPlayer->KilledMonsterCredit(NPC_THELDREN_QUEST_CREDIT); + } + } + + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override + { + ++m_uiMobDeadCount; + + switch (m_uiPhase) + { + case PHASE_MOBS: // Ring mob killed + if (m_uiMobDeadCount == MAX_MOB_AMOUNT) + { + m_uiEventTimer = 5000; + m_uiMobDeadCount = 0; + } + break; + case PHASE_BOSS: // Ring boss killed + // One Boss + if (m_uiMobDeadCount == 1) + { + m_uiEventTimer = 5000; + m_uiMobDeadCount = 0; + } + break; + case PHASE_GLADIATORS: // Theldren and his band killed + // Adds + Theldren + if (m_uiMobDeadCount == MAX_THELDREN_ADDS + 1) + { + m_uiEventTimer = 5000; + m_uiMobDeadCount = 0; + DoChallengeQuestCredit(); + } + break; + } + } + + void SummonRingMob(uint32 uiEntry, SpawnPosition uiPosition) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(aSpawnPositions[uiPosition][0], aSpawnPositions[uiPosition][1], aSpawnPositions[uiPosition][2], 2.0f, fX, fY, fZ); + m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: // Middle reached first time + DoScriptText(urand(0, 1) ? SAY_START_1 : SAY_START_2, m_creature); + SetEscortPaused(true); + m_uiEventTimer = 5000; + break; + case 1: // Reached wall again + DoScriptText(SAY_OPEN_EAST_GATE, m_creature); + SetEscortPaused(true); + m_uiEventTimer = 5000; + break; + case 2: // walking along the wall, while door opened + SetEscortPaused(true); + break; + case 3: // Middle reached second time + DoScriptText(urand(0, 1) ? SAY_SUMMON_BOSS_1 : SAY_SUMMON_BOSS_2, m_creature); + break; + case 4: // Reached North Gate + DoScriptText(SAY_OPEN_NORTH_GATE, m_creature); + SetEscortPaused(true); + m_uiEventTimer = 5000; + break; + case 5: + if (m_pInstance) + { + m_pInstance->SetData(TYPE_RING_OF_LAW, DONE); + debug_log("SD2: npc_grimstone: event reached end and set complete."); + } + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_RING_OF_LAW) == FAIL) + { + // Reset Doors + if (m_uiEventPhase >= 9) // North Gate is opened + { + m_pInstance->DoUseDoorOrButton(GO_ARENA_2); + m_pInstance->DoUseDoorOrButton(GO_ARENA_4); + } + else if (m_uiEventPhase >= 4) // East Gate is opened + { + m_pInstance->DoUseDoorOrButton(GO_ARENA_1); + m_pInstance->DoUseDoorOrButton(GO_ARENA_4); + } + + // Despawn Summoned Mobs + for (GuidList::const_iterator itr = m_lSummonedGuidList.begin(); itr != m_lSummonedGuidList.end(); ++itr) + { + if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) + pSummoned->ForcedDespawn(); + } + m_lSummonedGuidList.clear(); + + // Despawn NPC + m_creature->ForcedDespawn(); + return; + } + + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiEventPhase) + { + case 0: + // Shortly after spawn, start walking + // DoScriptText(-1000000, m_creature); // no more text on spawn + m_pInstance->DoUseDoorOrButton(GO_ARENA_4); + Start(false); + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + case 1: + // Start walking towards wall + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + case 2: + m_uiEventTimer = 2000; + break; + case 3: + // Open East Gate + m_pInstance->DoUseDoorOrButton(GO_ARENA_1); + m_uiEventTimer = 3000; + break; + case 4: + SetEscortPaused(false); + m_creature->SetVisibility(VISIBILITY_OFF); + // Summon Ring Mob(s) + SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); + m_uiEventTimer = 8000; + break; + case 5: + // Summon Ring Mob(s) + SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); + SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); + m_uiEventTimer = 8000; + break; + case 6: + // Summon Ring Mob(s) + SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); + m_uiEventTimer = 0; + break; + case 7: + // Summoned Mobs are dead, continue event + m_creature->SetVisibility(VISIBILITY_ON); + 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: + // Open North Gate + m_pInstance->DoUseDoorOrButton(GO_ARENA_2); + m_uiEventTimer = 5000; + break; + case 9: + // Summon Boss + m_creature->SetVisibility(VISIBILITY_OFF); + // If banner summoned after start, then summon Thelden after the creatures are dead + if (m_pInstance->GetData(TYPE_RING_OF_LAW) == SPECIAL && m_uiPhase == PHASE_MOBS) + { + m_uiPhase = PHASE_GLADIATORS; + SummonRingMob(NPC_THELDREN, POS_NORTH); + for (uint8 i = 0; i < MAX_THELDREN_ADDS; ++i) + SummonRingMob(m_uiGladiatorId[i], POS_NORTH); + } + else + { + m_uiPhase = PHASE_BOSS; + SummonRingMob(aRingBoss[urand(0, 5)], POS_NORTH); + } + m_uiEventTimer = 0; + break; + case 10: + // Boss dead + m_lSummonedGuidList.clear(); + m_pInstance->DoUseDoorOrButton(GO_ARENA_2); + m_pInstance->DoUseDoorOrButton(GO_ARENA_3); + m_pInstance->DoUseDoorOrButton(GO_ARENA_4); + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + } + ++m_uiEventPhase; + } + else + m_uiEventTimer -= uiDiff; + } + } +}; + +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, 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 ? uint32(SPECIAL) : uint32(DATA_BANNER_BEFORE_EVENT)); + + return true; + } + return false; +} + +/*###### +## npc_kharan_mighthammer +######*/ +enum +{ + QUEST_WHAT_IS_GOING_ON = 4001, + QUEST_KHARANS_TALE = 4342 +}; + +#define GOSSIP_ITEM_KHARAN_1 "I need to know where the princess are, Kharan!" +#define GOSSIP_ITEM_KHARAN_2 "All is not lost, Kharan!" + +#define GOSSIP_ITEM_KHARAN_3 "Gor'shak is my friend, you can trust me." +#define GOSSIP_ITEM_KHARAN_4 "Not enough, you need to tell me more." +#define GOSSIP_ITEM_KHARAN_5 "So what happened?" +#define GOSSIP_ITEM_KHARAN_6 "Continue..." +#define GOSSIP_ITEM_KHARAN_7 "So you suspect that someone on the inside was involved? That they were tipped off?" +#define GOSSIP_ITEM_KHARAN_8 "Continue with your story please." +#define GOSSIP_ITEM_KHARAN_9 "Indeed." +#define GOSSIP_ITEM_KHARAN_10 "The door is open, Kharan. You are a free man." + +bool GossipHello_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + 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); + + 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); + + if (pPlayer->GetTeam() == HORDE) + pPlayer->SEND_GOSSIP_MENU(2473, pCreature->GetObjectGuid()); + else + pPlayer->SEND_GOSSIP_MENU(2474, pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_kharan_mighthammer(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_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->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->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->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->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->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->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->SEND_GOSSIP_MENU(2482, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF+9: + pPlayer->CLOSE_GOSSIP_MENU(); + if (pPlayer->GetTeam() == HORDE) + pPlayer->AreaExploredOrEventHappens(QUEST_WHAT_IS_GOING_ON); + else + pPlayer->AreaExploredOrEventHappens(QUEST_KHARANS_TALE); + break; + } + return true; +} + +/*###### +## npc_rocknot +######*/ + +enum +{ + SAY_GOT_BEER = -1230000, + + SPELL_DRUNKEN_RAGE = 14872, + + QUEST_ALE = 4295 +}; + +struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI +{ + npc_rocknotAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiBreakKegTimer; + uint32 m_uiBreakDoorTimer; + + void Reset() + { + if (HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + m_uiBreakKegTimer = 0; + m_uiBreakDoorTimer = 0; + } + + void DoGo(uint32 id, uint32 state) + { + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(id)) + pGo->SetGoState(GOState(state)); + } + + void WaypointReached(uint32 uiPointId) override + { + if (!m_pInstance) + return; + + switch (uiPointId) + { + case 1: + m_creature->HandleEmote(EMOTE_ONESHOT_KICK); + break; + case 2: + m_creature->HandleEmote(EMOTE_ONESHOT_ATTACKUNARMED); + break; + case 3: + m_creature->HandleEmote(EMOTE_ONESHOT_ATTACKUNARMED); + break; + case 4: + m_creature->HandleEmote(EMOTE_ONESHOT_KICK); + break; + case 5: + m_creature->HandleEmote(EMOTE_ONESHOT_KICK); + m_uiBreakKegTimer = 2000; + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) + { + if (!m_pInstance) + return; + + if (m_uiBreakKegTimer) + { + if (m_uiBreakKegTimer <= uiDiff) + { + DoGo(GO_BAR_KEG_SHOT, 0); + m_uiBreakKegTimer = 0; + m_uiBreakDoorTimer = 1000; + } + else + m_uiBreakKegTimer -= uiDiff; + } + + if (m_uiBreakDoorTimer) + { + 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 + + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_PHALANX)) + pTmp->SetFactionTemporary(14, TEMPFACTION_NONE); + + // for later, this event(s) has alot more to it. + // optionally, DONE can trigger bar to go hostile. + m_pInstance->SetData(TYPE_BAR, DONE); + + m_uiBreakDoorTimer = 0; + } + else + m_uiBreakDoorTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_rocknot(Creature* pCreature) +{ + return new npc_rocknotAI(pCreature); +} + +bool QuestRewarded_npc_rocknot(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_BAR) == DONE || pInstance->GetData(TYPE_BAR) == SPECIAL) + return true; + + if (pQuest->GetQuestId() == QUEST_ALE) + { + if (pInstance->GetData(TYPE_BAR) != IN_PROGRESS) + pInstance->SetData(TYPE_BAR, IN_PROGRESS); + + 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) + { + DoScriptText(SAY_GOT_BEER, pCreature); + pCreature->CastSpell(pCreature, SPELL_DRUNKEN_RAGE, false); + + if (npc_rocknotAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, NULL, NULL, true); + } + } + + 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 MANGOS_DLL_DECL 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() + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_uiEventPhase = 0; + } + + void Aggro(Unit* pWho) + { + 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; + + pNewScript = new Script; + pNewScript->Name = "go_shadowforge_brazier"; + pNewScript->pGOUse = &GOUse_go_shadowforge_brazier; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_relic_coffer_door"; + pNewScript->pGOUse = &GOUse_go_relic_coffer_door; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_ring_of_law"; + pNewScript->pAreaTrigger = &AreaTrigger_at_ring_of_law; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_grimstone"; + pNewScript->GetAI = &GetAI_npc_grimstone; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_theldren_trigger"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_banner_of_provocation; + 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_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_mountain/blackrock_depths/blackrock_depths.h b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.h new file mode 100644 index 0000000000..c46112ab3d --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.h @@ -0,0 +1,165 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_BRD_H +#define DEF_BRD_H + +enum +{ + MAX_ENCOUNTER = 7, + MAX_RELIC_DOORS = 12, + MAX_DWARFS = 7, + + TYPE_RING_OF_LAW = 1, + TYPE_VAULT = 2, + TYPE_BAR = 3, + TYPE_TOMB_OF_SEVEN = 4, + TYPE_LYCEUM = 5, + TYPE_IRON_HALL = 6, + TYPE_QUEST_JAIL_BREAK = 7, + + NPC_EMPEROR = 9019, + NPC_PRINCESS = 8929, + NPC_PHALANX = 9502, + NPC_HATEREL = 9034, + NPC_ANGERREL = 9035, + NPC_VILEREL = 9036, + NPC_GLOOMREL = 9037, + NPC_SEETHREL = 9038, + 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, + + GO_ARENA_1 = 161525, + GO_ARENA_2 = 161522, + GO_ARENA_3 = 161524, + GO_ARENA_4 = 161523, + + GO_SHADOW_LOCK = 161460, + GO_SHADOW_MECHANISM = 161461, + GO_SHADOW_GIANT_DOOR = 157923, + GO_SHADOW_DUMMY = 161516, + GO_BAR_KEG_SHOT = 170607, + GO_BAR_KEG_TRAP = 171941, + GO_BAR_DOOR = 170571, + GO_TOMB_ENTER = 170576, + GO_TOMB_EXIT = 170577, + GO_LYCEUM = 170558, + GO_GOLEM_ROOM_N = 170573, + GO_GOLEM_ROOM_S = 170574, + GO_THRONE_ROOM = 170575, + + GO_SPECTRAL_CHALICE = 164869, + GO_CHEST_SEVEN = 169243, + GO_ARENA_SPOILS = 181074, + GO_SECRET_DOOR = 174553, + + // Jail break event related + GO_JAIL_DOOR_SUPPLY = 170561, + GO_JAIL_SUPPLY_CRATE = 166872, + + SPELL_STONED = 10255, // Aura of Warbringer Constructs in Relict Vault + + FACTION_DWARF_HOSTILE = 754, // Hostile faction for the Tomb of the Seven dwarfs +}; + +enum ArenaNPCs +{ + // Gladiators + NPC_LEFTY = 16049, + NPC_ROTFANG = 16050, + NPC_SNOKH = 16051, + NPC_MALGEN = 16052, + NPC_KORV = 16053, + NPC_REZZNIK = 16054, + NPC_VAJASHNI = 16055, + NPC_VOLIDA = 16058, + NPC_THELDREN = 16059, + // Ring mobs + NPC_WORM = 8925, + NPC_STINGER = 8926, + NPC_SCREECHER = 8927, + NPC_THUNDERSNOUT = 8928, + NPC_CREEPER = 8933, + NPC_BEETLE = 8932, + // Ring bosses + NPC_GOROSH = 9027, + NPC_GRIZZLE = 9028, + NPC_EVISCERATOR = 9029, + NPC_OKTHOR = 9030, + NPC_ANUBSHIAH = 9031, + NPC_HEDRUM = 9032 +}; + +static const uint32 aArenaNPCs[] = +{ + // Gladiators + NPC_LEFTY, NPC_ROTFANG, NPC_SNOKH, NPC_MALGEN, NPC_KORV, NPC_REZZNIK, NPC_VAJASHNI, NPC_VOLIDA, NPC_THELDREN, + // Ring mobs + NPC_WORM, NPC_STINGER, NPC_SCREECHER, NPC_THUNDERSNOUT, NPC_CREEPER, NPC_BEETLE, + // Ring bosses + NPC_GOROSH, NPC_GRIZZLE, NPC_EVISCERATOR, NPC_OKTHOR, NPC_ANUBSHIAH, NPC_HEDRUM +}; + +// Used to summon Watcher Doomgrip +static const float aVaultPositions[4] = {821.905f, -338.382f, -50.134f, 3.78736f}; + +// 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 MANGOS_DLL_DECL instance_blackrock_depths : public ScriptedInstance +{ + public: + instance_blackrock_depths(Map* pMap); + ~instance_blackrock_depths() {} + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureEnterCombat(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; + + 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; } + + private: + void DoCallNextDwarf(); + + 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; +}; + +#endif diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_ambassador_flamelash.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_ambassador_flamelash.cpp new file mode 100644 index 0000000000..52b0582a34 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_ambassador_flamelash.cpp @@ -0,0 +1,123 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_Ambassador_Flamelash +SD%Complete: 80 +SDComment: Texts missing, Add handling rather guesswork, Add spell Burning Spirit likely won't work +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +enum +{ + SPELL_FIREBLAST = 15573, + SPELL_BURNING_SPIRIT = 13489, + SPELL_BURNING_SPIRIT_BUFF = 14744, + + NPC_BURNING_SPIRIT = 9178, +}; + +struct MANGOS_DLL_DECL boss_ambassador_flamelashAI : public ScriptedAI +{ + boss_ambassador_flamelashAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiSpiritTimer; + int Rand; + int RandX; + int RandY; + + void Reset() + { + m_uiSpiritTimer = 12000; + } + + void SummonSpirits() + { + 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); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_FIREBLAST); + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + } + + void SummonedMovementInform(Creature* pSummoned, uint32 /*uiMotionType*/, uint32 uiPointId) override + { + if (uiPointId != 1) + return; + + pSummoned->CastSpell(m_creature, SPELL_BURNING_SPIRIT, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // m_uiSpiritTimer + if (m_uiSpiritTimer < uiDiff) + { + SummonSpirits(); + SummonSpirits(); + SummonSpirits(); + SummonSpirits(); + + m_uiSpiritTimer = 20000; + } + else + m_uiSpiritTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +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) + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_BURNING_SPIRIT_BUFF, true); + return true; + } + + return false; +} + +CreatureAI* GetAI_boss_ambassador_flamelash(Creature* pCreature) +{ + return new boss_ambassador_flamelashAI(pCreature); +} + +void AddSC_boss_ambassador_flamelash() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ambassador_flamelash"; + pNewScript->GetAI = &GetAI_boss_ambassador_flamelash; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_boss_ambassador_flamelash; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_coren_direbrew.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_coren_direbrew.cpp new file mode 100644 index 0000000000..ce732da9fb --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_coren_direbrew.cpp @@ -0,0 +1,181 @@ +/* Copyright (C) 2006 - 2013 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_coren_direbrew +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 MANGOS_DLL_DECL 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() + { + 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_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp similarity index 72% rename from scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp rename to scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp index ebf02a2b04..6d9ede38d0 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,70 +47,70 @@ struct MANGOS_DLL_DECL boss_emperor_dagran_thaurissanAI : public ScriptedAI uint32 m_uiHandOfThaurissan_Timer; uint32 m_uiAvatarOfFlame_Timer; - //uint32 m_uiCounter; + // uint32 m_uiCounter; void Reset() { m_uiHandOfThaurissan_Timer = 4000; m_uiAvatarOfFlame_Timer = 25000; - //m_uiCounter = 0; + // m_uiCounter = 0; } - 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->instance->GetCreature(m_pInstance->GetData64(DATA_PRINCESS))) + if (Creature* pPrincess = m_pInstance->GetSingleCreatureFromStorage(NPC_PRINCESS)) { 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 (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget,SPELL_HANDOFTHAURISSAN); + 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) + // 3 Hands of Thaurissan will be casted + // if (m_uiCounter < 3) //{ // m_uiHandOfThaurissan_Timer = 1000; // ++m_uiCounter; //} - //else + // else //{ - m_uiHandOfThaurissan_Timer = 5000; - //m_uiCounter = 0; + m_uiHandOfThaurissan_Timer = 5000; + // m_uiCounter = 0; //} } else m_uiHandOfThaurissan_Timer -= uiDiff; - //AvatarOfFlame_Timer + // AvatarOfFlame_Timer if (m_uiAvatarOfFlame_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_AVATAROFFLAME); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_AVATAROFFLAME); m_uiAvatarOfFlame_Timer = 18000; } else @@ -157,13 +158,13 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI void Reset() { - m_uiHeal_Timer = 12000; //These times are probably wrong + m_uiHeal_Timer = 12000; // These times are probably wrong m_uiMindBlast_Timer = 16000; m_uiShadowWordPain_Timer = 2000; m_uiSmite_Timer = 8000; } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, false)) { @@ -175,11 +176,11 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { - if (Creature* pEmperor = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_EMPEROR))) + if (Creature* pEmperor = m_pInstance->GetSingleCreatureFromStorage(NPC_EMPEROR)) { // if evade, then check if he is alive. If not, start make portal if (!pEmperor->isAlive()) @@ -188,43 +189,43 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI } } - 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 + // MindBlast_Timer if (m_uiMindBlast_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MINDBLAST); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MINDBLAST); m_uiMindBlast_Timer = 14000; } else m_uiMindBlast_Timer -= uiDiff; - //ShadowWordPain_Timer + // ShadowWordPain_Timer if (m_uiShadowWordPain_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWWORDPAIN); m_uiShadowWordPain_Timer = 18000; } else m_uiShadowWordPain_Timer -= uiDiff; - //Smite_Timer + // Smite_Timer if (m_uiSmite_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SMITE); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SMITE); m_uiSmite_Timer = 10000; } else m_uiSmite_Timer -= uiDiff; - //Heal_Timer + // Heal_Timer if (m_uiHeal_Timer < uiDiff) { - if (Creature* pEmperor = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_EMPEROR))) + if (Creature* pEmperor = m_pInstance->GetSingleCreatureFromStorage(NPC_EMPEROR)) { if (pEmperor->isAlive() && pEmperor->GetHealthPercent() != 100.0f) DoCastSpellIfCan(pEmperor, SPELL_HEAL); @@ -235,7 +236,7 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI else m_uiHeal_Timer -= uiDiff; - //No meele? + // No meele? } }; @@ -246,15 +247,15 @@ CreatureAI* GetAI_boss_moira_bronzebeard(Creature* pCreature) void AddSC_boss_draganthaurissan() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_emperor_dagran_thaurissan"; - newscript->GetAI = &GetAI_boss_emperor_dagran_thaurissan; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_emperor_dagran_thaurissan"; + pNewScript->GetAI = &GetAI_boss_emperor_dagran_thaurissan; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_moira_bronzebeard"; - newscript->GetAI = &GetAI_boss_moira_bronzebeard; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_moira_bronzebeard"; + pNewScript->GetAI = &GetAI_boss_moira_bronzebeard; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_general_angerforge.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_general_angerforge.cpp new file mode 100644 index 0000000000..440f442391 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_general_angerforge.cpp @@ -0,0 +1,143 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_General_Angerforge +SD%Complete: 100 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" + +enum +{ + SPELL_MIGHTYBLOW = 14099, + SPELL_HAMSTRING = 9080, + SPELL_CLEAVE = 20691, + + NPC_ANVILRAGE_RESERVIST = 8901, + NPC_ANVILRAGE_MEDIC = 8894, +}; + +struct MANGOS_DLL_DECL 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; + + void Reset() + { + m_uiMightyBlowTimer = 8000; + m_uiHamStringTimer = 12000; + m_uiCleaveTimer = 16000; + m_uiAddsTimer = 0; + m_bSummonedMedics = false; + } + + 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); + } + + 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 + { + // 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) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); + m_uiCleaveTimer = 9000; + } + else + m_uiCleaveTimer -= uiDiff; + + // Adds_Timer + if (m_creature->GetHealthPercent() < 21.0f) + { + if (m_uiAddsTimer < uiDiff) + { + // summon 3 Adds every 25s + SummonAdd(NPC_ANVILRAGE_RESERVIST); + SummonAdd(NPC_ANVILRAGE_RESERVIST); + SummonAdd(NPC_ANVILRAGE_RESERVIST); + + m_uiAddsTimer = 25000; + } + 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; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_general_angerforge(Creature* pCreature) +{ + return new boss_general_angerforgeAI(pCreature); +} + +void AddSC_boss_general_angerforge() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_general_angerforge"; + pNewScript->GetAI = &GetAI_boss_general_angerforge; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp similarity index 57% rename from scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp rename to scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp index d159bd06c9..24e85aa1af 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,64 +36,64 @@ struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI { boss_high_interrogator_gerstahnAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 m_uiShadowWordPain_Timer; - uint32 m_uiManaBurn_Timer; - uint32 m_uiPsychicScream_Timer; - uint32 m_uiShadowShield_Timer; + uint32 m_uiShadowWordPainTimer; + uint32 m_uiManaBurnTimer; + uint32 m_uiPsychicScreamTimer; + uint32 m_uiShadowShieldTimer; void Reset() { - m_uiShadowWordPain_Timer = 4000; - m_uiManaBurn_Timer = 14000; - m_uiPsychicScream_Timer = 32000; - m_uiShadowShield_Timer = 8000; + m_uiShadowWordPainTimer = 4000; + m_uiManaBurnTimer = 14000; + m_uiPsychicScreamTimer = 32000; + 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 - if (m_uiShadowWordPain_Timer < uiDiff) + // ShadowWordPain_Timer + if (m_uiShadowWordPainTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) DoCastSpellIfCan(pTarget, SPELL_SHADOWWORDPAIN); - m_uiShadowWordPain_Timer = 7000; + m_uiShadowWordPainTimer = 7000; } else - m_uiShadowWordPain_Timer -= uiDiff; + m_uiShadowWordPainTimer -= uiDiff; - //ManaBurn_Timer - if (m_uiManaBurn_Timer < uiDiff) + // ManaBurn_Timer + if (m_uiManaBurnTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANABURN, SELECT_FLAG_POWER_MANA)) DoCastSpellIfCan(pTarget, SPELL_MANABURN); - m_uiManaBurn_Timer = 10000; + m_uiManaBurnTimer = 10000; } else - m_uiManaBurn_Timer -= uiDiff; + m_uiManaBurnTimer -= uiDiff; - //PsychicScream_Timer - if (m_uiPsychicScream_Timer < uiDiff) + // PsychicScream_Timer + if (m_uiPsychicScreamTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHICSCREAM); - m_uiPsychicScream_Timer = 30000; + DoCastSpellIfCan(m_creature, SPELL_PSYCHICSCREAM); + m_uiPsychicScreamTimer = 30000; } else - m_uiPsychicScream_Timer -= uiDiff; + m_uiPsychicScreamTimer -= uiDiff; - //ShadowShield_Timer - if (m_uiShadowShield_Timer < uiDiff) + // ShadowShield_Timer + if (m_uiShadowShieldTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_SHADOWSHIELD); - m_uiShadowShield_Timer = 25000; + m_uiShadowShieldTimer = 25000; } else - m_uiShadowShield_Timer -= uiDiff; + m_uiShadowShieldTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -105,9 +106,10 @@ CreatureAI* GetAI_boss_high_interrogator_gerstahn(Creature* pCreature) void AddSC_boss_high_interrogator_gerstahn() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_high_interrogator_gerstahn"; - newscript->GetAI = &GetAI_boss_high_interrogator_gerstahn; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_high_interrogator_gerstahn"; + pNewScript->GetAI = &GetAI_boss_high_interrogator_gerstahn; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp new file mode 100644 index 0000000000..83299eab7f --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp @@ -0,0 +1,418 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_Blackrock_Depths +SD%Complete: 80 +SDComment: +SDCategory: Blackrock Depths +EndScriptData */ + +#include "precompiled.h" +#include "blackrock_depths.h" + +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), + m_fArenaCenterZ(0.0f) +{ + Initialize(); +} + +void instance_blackrock_depths::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +void instance_blackrock_depths::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_EMPEROR: + case NPC_PRINCESS: + 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; + + case NPC_WARBRINGER_CONST: + // Golems not in the Relict Vault? + if (std::abs(pCreature->GetPositionZ() - aVaultPositions[2]) > 1.0f || !pCreature->IsWithinDist2d(aVaultPositions[0], aVaultPositions[1], 20.0f)) + break; + // Golems in Relict Vault need to have a stoned aura, set manually to prevent reapply when reached home + pCreature->CastSpell(pCreature, SPELL_STONED, true); + // Store the Relict Vault Golems into m_sVaultNpcGuids + case NPC_WATCHER_DOOMGRIP: + m_sVaultNpcGuids.insert(pCreature->GetObjectGuid()); + break; + } +} + +void instance_blackrock_depths::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_ARENA_1: + case GO_ARENA_2: + case GO_ARENA_3: + case GO_ARENA_4: + case GO_SHADOW_LOCK: + case GO_SHADOW_MECHANISM: + case GO_SHADOW_GIANT_DOOR: + case GO_SHADOW_DUMMY: + case GO_BAR_KEG_SHOT: + case GO_BAR_KEG_TRAP: + case GO_BAR_DOOR: + case GO_TOMB_ENTER: + case GO_TOMB_EXIT: + case GO_LYCEUM: + case GO_GOLEM_ROOM_N: + case GO_GOLEM_ROOM_S: + case GO_THRONE_ROOM: + case GO_SPECTRAL_CHALICE: + case GO_CHEST_SEVEN: + case GO_ARENA_SPOILS: + case GO_SECRET_DOOR: + case GO_JAIL_DOOR_SUPPLY: + case GO_JAIL_SUPPLY_CRATE: + break; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) +{ + 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); + m_auiEncounter[0] = uiData; + break; + case TYPE_VAULT: + if (uiData == SPECIAL) + { + ++m_uiCofferDoorsOpened; + + if (m_uiCofferDoorsOpened == MAX_RELIC_DOORS) + { + SetData(TYPE_VAULT, IN_PROGRESS); + + Creature* pConstruct = NULL; + + // Activate vault constructs + for (GuidSet::const_iterator itr = m_sVaultNpcGuids.begin(); itr != m_sVaultNpcGuids.end(); ++itr) + { + pConstruct = instance->GetCreature(*itr); + if (pConstruct) + pConstruct->RemoveAurasDueToSpell(SPELL_STONED); + } + + if (!pConstruct) + return; + + // Summon doomgrip + pConstruct->SummonCreature(NPC_WATCHER_DOOMGRIP, aVaultPositions[0], aVaultPositions[1], aVaultPositions[2], aVaultPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); + } + // No need to store in this case + return; + } + if (uiData == DONE) + DoUseDoorOrButton(GO_SECRET_DOOR); + m_auiEncounter[1] = uiData; + break; + case TYPE_BAR: + if (uiData == SPECIAL) + ++m_uiBarAleCount; + else + m_auiEncounter[2] = uiData; + break; + case TYPE_TOMB_OF_SEVEN: + // 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) + { + // 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; + case TYPE_LYCEUM: + if (uiData == DONE) + { + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + } + m_auiEncounter[4] = uiData; + break; + case TYPE_IRON_HALL: + switch (uiData) + { + case IN_PROGRESS: + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + break; + case FAIL: + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + break; + case DONE: + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + DoUseDoorOrButton(GO_THRONE_ROOM); + break; + } + m_auiEncounter[5] = uiData; + break; + case TYPE_QUEST_JAIL_BREAK: + m_auiEncounter[6] = 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_blackrock_depths::GetData(uint32 uiType) const +{ + switch (uiType) + { + case TYPE_RING_OF_LAW: + return m_auiEncounter[0]; + case TYPE_VAULT: + return m_auiEncounter[1]; + case TYPE_BAR: + if (m_auiEncounter[2] == IN_PROGRESS && m_uiBarAleCount == 3) + return SPECIAL; + else + return m_auiEncounter[2]; + case TYPE_TOMB_OF_SEVEN: + return m_auiEncounter[3]; + case TYPE_LYCEUM: + return m_auiEncounter[4]; + case TYPE_IRON_HALL: + return m_auiEncounter[5]; + case TYPE_QUEST_JAIL_BREAK: + return m_auiEncounter[6]; + default: + return 0; + } +} + +void instance_blackrock_depths::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] >> 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; + + 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 < countof(aArenaNPCs); ++i) + { + if (pCreature->GetEntry() == aArenaNPCs[i]) + { + 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()) + { + case NPC_WARBRINGER_CONST: + case NPC_WATCHER_DOOMGRIP: + if (GetData(TYPE_VAULT) == IN_PROGRESS) + { + m_sVaultNpcGuids.erase(pCreature->GetObjectGuid()); + + // If all event npcs dead then set event to done + if (m_sVaultNpcGuids.empty()) + 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; +} + +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; + } +} + +InstanceData* GetInstanceData_instance_blackrock_depths(Map* pMap) +{ + return new instance_blackrock_depths(pMap); +} + +void AddSC_instance_blackrock_depths() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_blackrock_depths"; + pNewScript->GetInstanceData = &GetInstanceData_instance_blackrock_depths; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/blackrock_spire.h b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/blackrock_spire.h new file mode 100644 index 0000000000..468741f876 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/blackrock_spire.h @@ -0,0 +1,144 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_BLACKROCK_SPIRE_H +#define DEF_BLACKROCK_SPIRE_H + +enum +{ + MAX_ENCOUNTER = 6, + MAX_ROOMS = 7, + + 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_DRAKKISATH = 10363, + NPC_CHROMATIC_WHELP = 10442, // related to Gyth arena event + NPC_CHROMATIC_DRAGON = 10447, + NPC_BLACKHAND_HANDLER = 10742, + + // Doors + 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, + GO_DRAKKISATH_DOOR_1 = 175946, + GO_DRAKKISATH_DOOR_2 = 175947, + + GO_ROOM_7_RUNE = 175194, + GO_ROOM_3_RUNE = 175195, + GO_ROOM_6_RUNE = 175196, + GO_ROOM_1_RUNE = 175197, + GO_ROOM_5_RUNE = 175198, + GO_ROOM_2_RUNE = 175199, + GO_ROOM_4_RUNE = 175200, + + GO_ROOKERY_EGG = 175124, + + GO_EMBERSEER_RUNE_1 = 175266, + GO_EMBERSEER_RUNE_2 = 175267, + GO_EMBERSEER_RUNE_3 = 175268, + GO_EMBERSEER_RUNE_4 = 175269, + GO_EMBERSEER_RUNE_5 = 175270, + GO_EMBERSEER_RUNE_6 = 175271, + GO_EMBERSEER_RUNE_7 = 175272, + + MAX_STADIUM_WAVES = 7, + MAX_STADIUM_MOBS_PER_WAVE = 5, + + FACTION_BLACK_DRAGON = 103 +}; + +static const EVENTLOCATION aStadiumLocs[7] = +{ + {210.00f, -420.30f, 110.94f, 3.14f}, // dragons summon location + {210.14f, -397.54f, 111.1f}, // Gyth summon location + {163.62f, -420.33f, 110.47f}, // center of the stadium location (for movement) + {164.63f, -444.04f, 121.97f, 3.22f}, // Lord Nefarius summon position + {161.01f, -443.73f, 121.97f, 6.26f}, // Rend summon position + {164.64f, -443.30f, 121.97f, 1.61f}, // Nefarius move position + {165.74f, -466.46f, 116.80f}, // Rend move position +}; + +// Stadium event description +static const uint32 aStadiumEventNpcs[MAX_STADIUM_WAVES][5] = +{ + {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, 0}, + {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, 0}, + {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, NPC_BLACKHAND_HANDLER, 0}, + {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, NPC_BLACKHAND_HANDLER, 0}, + {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, NPC_BLACKHAND_HANDLER}, + {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, NPC_CHROMATIC_DRAGON, NPC_BLACKHAND_HANDLER}, + {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 +{ + public: + instance_blackrock_spire(Map* pMap); + ~instance_blackrock_spire() {} + + void Initialize() override; + + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureEnterCombat(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 DoUseEmberseerRunes(bool bReset = false); + void DoProcessEmberseerEvent(); + + void DoSortRoomEventMobs(); + void GetIncarceratorGUIDList(GuidList& lList) { lList = m_lIncarceratorGUIDList; } + + void StartflamewreathEventIfCan(); + + void Update(uint32 uiDiff) override; + + private: + 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_lEmberseerRunesGUIDList; +}; + +#endif diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_gyth.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_gyth.cpp new file mode 100644 index 0000000000..97ce65482a --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_gyth.cpp @@ -0,0 +1,148 @@ +/* Copyright (C) 2006 - 2013 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_Gyth +SD%Complete: 100 +SDComment: Timers may need adjustments +SDCategory: Blackrock Spire +EndScriptData */ + +#include "precompiled.h" +#include "blackrock_spire.h" + +enum +{ + SAY_NEFARIUS_BUFF_GYTH = -1229017, + EMOTE_KNOCKED_OFF = -1229019, + + SPELL_CHROMATIC_CHAOS = 16337, // casted by Nefarius at 50% + SPELL_REND_MOUNTS = 16167, + SPELL_SUMMON_REND = 16328, + SPELL_CORROSIVE_ACID = 16359, + SPELL_FREEZE = 16350, + SPELL_FLAME_BREATH = 16390, + SPELL_KNOCK_AWAY = 10101, +}; + +struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI +{ + boss_gythAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_blackrock_spire*) pCreature->GetInstanceData(); + Reset(); + } + + instance_blackrock_spire* m_pInstance; + + uint32 uiCorrosiveAcidTimer; + uint32 uiFreezeTimer; + uint32 uiFlamebreathTimer; + + bool m_bSummonedRend; + bool m_bHasChromaticChaos; + + void Reset() + { + uiCorrosiveAcidTimer = 8000; + uiFreezeTimer = 11000; + uiFlamebreathTimer = 4000; + m_bSummonedRend = false; + m_bHasChromaticChaos = false; + + DoCastSpellIfCan(m_creature, SPELL_REND_MOUNTS); + } + + void JustSummoned(Creature* pSummoned) override + { + DoScriptText(EMOTE_KNOCKED_OFF, pSummoned); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Chromatic Chaos at 50% + if (!m_bHasChromaticChaos && m_creature->GetHealthPercent() < 50.0f) + { + if (m_pInstance) + { + if (Creature* pNefarius = m_pInstance->GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) + { + pNefarius->CastSpell(m_creature, SPELL_CHROMATIC_CHAOS, true); + DoScriptText(SAY_NEFARIUS_BUFF_GYTH, pNefarius); + m_bHasChromaticChaos = true; + } + } + } + + // CorrosiveAcid_Timer + if (uiCorrosiveAcidTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CORROSIVE_ACID) == CAST_OK) + uiCorrosiveAcidTimer = 7000; + } + else + uiCorrosiveAcidTimer -= uiDiff; + + // Freeze_Timer + if (uiFreezeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FREEZE) == CAST_OK) + uiFreezeTimer = 16000; + } + else + uiFreezeTimer -= uiDiff; + + // Flamebreath_Timer + if (uiFlamebreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BREATH) == CAST_OK) + uiFlamebreathTimer = 10500; + } + else + uiFlamebreathTimer -= uiDiff; + + // Summon Rend + if (!m_bSummonedRend && m_creature->GetHealthPercent() < 11.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_REND) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_REND_MOUNTS); + m_bSummonedRend = true; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_gyth(Creature* pCreature) +{ + return new boss_gythAI(pCreature); +} + +void AddSC_boss_gyth() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_gyth"; + pNewScript->GetAI = &GetAI_boss_gyth; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_overlord_wyrmthalak.cpp similarity index 88% rename from scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp rename to scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_overlord_wyrmthalak.cpp index 4fbfb9f641..aaa18afc90 100644 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_overlord_wyrmthalak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,16 +29,15 @@ enum SPELL_SHOUT = 23511, SPELL_CLEAVE = 20691, SPELL_KNOCKAWAY = 20686, - + 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 @@ -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; @@ -71,8 +70,8 @@ struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI pSummoned->AI()->AttackStart(pTarget ? pTarget : m_creature->getVictim()); } } - - void UpdateAI(const uint32 uiDiff) + + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -134,9 +133,10 @@ CreatureAI* GetAI_boss_overlordwyrmthalak(Creature* pCreature) void AddSC_boss_overlordwyrmthalak() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_overlord_wyrmthalak"; - newscript->GetAI = &GetAI_boss_overlordwyrmthalak; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_overlord_wyrmthalak"; + pNewScript->GetAI = &GetAI_boss_overlordwyrmthalak; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_pyroguard_emberseer.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_pyroguard_emberseer.cpp new file mode 100644 index 0000000000..43049af448 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/boss_pyroguard_emberseer.cpp @@ -0,0 +1,213 @@ +/* Copyright (C) 2006 - 2013 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_Pyroguard_Emberseer +SD%Complete: 90 +SDComment: Dummy spells used during the transformation may need further research +SDCategory: Blackrock Spire +EndScriptData */ + +#include "precompiled.h" +#include "blackrock_spire.h" + +enum +{ + // Intro emote/say + EMOTE_NEAR = -1229001, + EMOTE_FULL = -1229002, + SAY_FREE = -1229003, + + MAX_GROWING_STACKS = 20, + + // Intro spells + SPELL_ENCAGE_EMBERSEER = 15281, // cast by Blackhand Incarcerator + + SPELL_FIRE_SHIELD = 13376, // not sure what's the purpose of this + SPELL_DESPAWN_EMBERSEER = 16078, // not sure what's the purpose of this + SPELL_FREEZE_ANIM = 16245, // not sure what's the purpose of this + SPELL_FULL_STRENGHT = 16047, + SPELL_GROWING = 16049, // stacking aura + SPELL_BONUS_DAMAGE = 16534, // triggered on full grow + SPELL_TRANSFORM = 16052, + + // Combat spells + SPELL_FIRENOVA = 23462, + SPELL_FLAMEBUFFET = 23341, + SPELL_PYROBLAST = 20228 // guesswork, but best fitting in spells-area, was 17274 (has mana cost) +}; + +struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI +{ + boss_pyroguard_emberseerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_blackrock_spire*) pCreature->GetInstanceData(); + Reset(); + } + + instance_blackrock_spire* m_pInstance; + + uint32 m_uiEncageTimer; + uint32 m_uiFireNovaTimer; + uint32 m_uiFlameBuffetTimer; + uint32 m_uiPyroBlastTimer; + uint8 m_uiGrowingStacks; + + void Reset() + { + m_uiEncageTimer = 10000; + m_uiFireNovaTimer = 6000; + m_uiFlameBuffetTimer = 3000; + m_uiPyroBlastTimer = 14000; + m_uiGrowingStacks = 0; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EMBERSEER, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EMBERSEER, FAIL); + } + + // Wrapper to handle the transformation + void DoHandleEmberseerGrowing() + { + ++m_uiGrowingStacks; + + if (m_uiGrowingStacks == MAX_GROWING_STACKS * 0.5f) + DoScriptText(EMOTE_NEAR, m_creature); + else if (m_uiGrowingStacks == MAX_GROWING_STACKS) + { + DoScriptText(EMOTE_FULL, m_creature); + DoScriptText(SAY_FREE, m_creature); + + // Note: the spell order needs further research + DoCastSpellIfCan(m_creature, SPELL_FULL_STRENGHT, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_BONUS_DAMAGE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TRANSFORM, CAST_TRIGGERED); + + // activate all runes + if (m_pInstance) + { + m_pInstance->DoUseEmberseerRunes(); + // Redundant check: if for some reason the event isn't set in progress until this point - avoid using the altar again when the boss is fully grown + m_pInstance->SetData(TYPE_EMBERSEER, IN_PROGRESS); + } + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Cast Encage spell on OOC timer + if (m_uiEncageTimer) + { + if (m_uiEncageTimer <= uiDiff) + { + 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) + { + if (Creature* pIncarcerator = m_creature->GetMap()->GetCreature(*itr)) + pIncarcerator->CastSpell(m_creature, SPELL_ENCAGE_EMBERSEER, false); + } + + m_uiEncageTimer = 0; + } + else + m_uiEncageTimer -= uiDiff; + } + + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // FireNova Timer + if (m_uiFireNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FIRENOVA) == CAST_OK) + m_uiFireNovaTimer = 6000; + } + else + m_uiFireNovaTimer -= uiDiff; + + // FlameBuffet Timer + if (m_uiFlameBuffetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAMEBUFFET) == CAST_OK) + m_uiFlameBuffetTimer = 14000; + } + else + m_uiFlameBuffetTimer -= uiDiff; + + // PyroBlast Timer + if (m_uiPyroBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_PYROBLAST) == CAST_OK) + m_uiPyroBlastTimer = 15000; + } + } + else + m_uiPyroBlastTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +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, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_GROWING && uiEffIndex == EFFECT_INDEX_0) + { + if (boss_pyroguard_emberseerAI* pEmberseerAI = dynamic_cast(pCreatureTarget->AI())) + pEmberseerAI->DoHandleEmberseerGrowing(); + } + + return false; +} + +void AddSC_boss_pyroguard_emberseer() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_pyroguard_emberseer"; + pNewScript->GetAI = &GetAI_boss_pyroguard_emberseer; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_pyroguard_emberseer; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/instance_blackrock_spire.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/instance_blackrock_spire.cpp new file mode 100644 index 0000000000..199476ffa5 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackrock_spire/instance_blackrock_spire.cpp @@ -0,0 +1,715 @@ +/* Copyright (C) 2006 - 2013 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: instance_blackrock_spire +SD%Complete: 75 +SDComment: The Stadium event is missing some yells. Seal of Ascension related event NYI +SDCategory: Blackrock Spire +EndScriptData */ + +#include "precompiled.h" +#include "blackrock_spire.h" + +enum +{ + AREATRIGGER_ENTER_UBRS = 2046, + AREATRIGGER_STADIUM = 2026, + + // Arena event dialogue - handled by instance + SAY_NEFARIUS_INTRO_1 = -1229004, + SAY_NEFARIUS_INTRO_2 = -1229005, + SAY_NEFARIUS_ATTACK_1 = -1229006, + SAY_REND_JOIN = -1229007, + SAY_NEFARIUS_ATTACK_2 = -1229008, + SAY_NEFARIUS_ATTACK_3 = -1229009, + SAY_NEFARIUS_ATTACK_4 = -1229010, + SAY_REND_LOSE_1 = -1229011, + SAY_REND_LOSE_2 = -1229012, + SAY_NEFARIUS_LOSE_3 = -1229013, + SAY_NEFARIUS_LOSE_4 = -1229014, + SAY_REND_ATTACK = -1229015, + SAY_NEFARIUS_WARCHIEF = -1229016, + SAY_NEFARIUS_VICTORY = -1229018, + + // 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, +}; + +/* Areatrigger +1470 Instance Entry +1628 LBRS, between Spiders and Ogres +1946 LBRS, ubrs pre-quest giver (1) +1986 LBRS, ubrs pre-quest giver (2) +1987 LBRS, ubrs pre-quest giver (3) +2026 UBRS, stadium event trigger +2046 UBRS, way to upper +2066 UBRS, The Beast - Exit (to the dark chamber) +2067 UBRS, The Beast - Entry +2068 LBRS, fall out of map +3726 UBRS, entrance to BWL +*/ + +static const DialogueEntry aStadiumDialogue[] = +{ + {NPC_LORD_VICTOR_NEFARIUS, 0, 1000}, + {SAY_NEFARIUS_INTRO_1, NPC_LORD_VICTOR_NEFARIUS, 7000}, + {SAY_NEFARIUS_INTRO_2, NPC_LORD_VICTOR_NEFARIUS, 5000}, + {NPC_BLACKHAND_HANDLER, 0, 0}, + {SAY_NEFARIUS_LOSE_4, NPC_LORD_VICTOR_NEFARIUS, 3000}, + {SAY_REND_ATTACK, NPC_REND_BLACKHAND, 2000}, + {SAY_NEFARIUS_WARCHIEF, NPC_LORD_VICTOR_NEFARIUS, 0}, + {SAY_NEFARIUS_VICTORY, NPC_LORD_VICTOR_NEFARIUS, 5000}, + {NPC_REND_BLACKHAND, 0, 0}, + {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_uiStadiumWaves(0), + m_uiStadiumMobsAlive(0) +{ + Initialize(); +} + +void instance_blackrock_spire::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + memset(&m_aRoomRuneGuid, 0, sizeof(m_aRoomRuneGuid)); + InitializeDialogueHelper(this); +} + +void instance_blackrock_spire::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_EMBERSEER_IN: + if (GetData(TYPE_ROOM_EVENT) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOORS: + break; + case GO_EMBERSEER_OUT: + 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: + case GO_DRAKKISATH_DOOR_2: + break; + case GO_GYTH_EXIT_DOOR: + if (GetData(TYPE_STADIUM) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + + case GO_ROOM_1_RUNE: m_aRoomRuneGuid[0] = pGo->GetObjectGuid(); return; + case GO_ROOM_2_RUNE: m_aRoomRuneGuid[1] = pGo->GetObjectGuid(); return; + case GO_ROOM_3_RUNE: m_aRoomRuneGuid[2] = pGo->GetObjectGuid(); return; + case GO_ROOM_4_RUNE: m_aRoomRuneGuid[3] = pGo->GetObjectGuid(); return; + case GO_ROOM_5_RUNE: m_aRoomRuneGuid[4] = pGo->GetObjectGuid(); return; + case GO_ROOM_6_RUNE: m_aRoomRuneGuid[5] = pGo->GetObjectGuid(); return; + case GO_ROOM_7_RUNE: m_aRoomRuneGuid[6] = pGo->GetObjectGuid(); return; + + case GO_EMBERSEER_RUNE_1: + case GO_EMBERSEER_RUNE_2: + case GO_EMBERSEER_RUNE_3: + case GO_EMBERSEER_RUNE_4: + case GO_EMBERSEER_RUNE_5: + case GO_EMBERSEER_RUNE_6: + case GO_EMBERSEER_RUNE_7: + m_lEmberseerRunesGUIDList.push_back(pGo->GetObjectGuid()); + return; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_blackrock_spire::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_PYROGUARD_EMBERSEER: + case NPC_SOLAKAR_FLAMEWREATH: + case NPC_LORD_VICTOR_NEFARIUS: + case NPC_GYTH: + case NPC_REND_BLACKHAND: + case NPC_SCARSHIELD_INFILTRATOR: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + case NPC_BLACKHAND_SUMMONER: + case NPC_BLACKHAND_VETERAN: m_lRoomEventMobGUIDList.push_back(pCreature->GetObjectGuid()); break; + case NPC_BLACKHAND_INCARCERATOR: m_lIncarceratorGUIDList.push_back(pCreature->GetObjectGuid()); break; + } +} + +void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_ROOM_EVENT: + if (uiData == DONE) + DoUseDoorOrButton(GO_EMBERSEER_IN); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_EMBERSEER: + // Don't set the same data twice + 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) + { + if (Creature* pIncarcerator = instance->GetCreature(*itr)) + { + if (!pIncarcerator->isAlive()) + pIncarcerator->Respawn(); + pIncarcerator->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + + DoUseEmberseerRunes(true); + } + else if (uiData == DONE) + { + DoUseEmberseerRunes(); + DoUseDoorOrButton(GO_EMBERSEER_OUT); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_FLAMEWREATH: + 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[uiType] == uiData) + break; + // Combat door + DoUseDoorOrButton(GO_GYTH_ENTRY_DOOR); + // Start event + if (uiData == IN_PROGRESS) + StartNextDialogueText(SAY_NEFARIUS_INTRO_1); + else if (uiData == DONE) + DoUseDoorOrButton(GO_GYTH_EXIT_DOOR); + else if (uiData == FAIL) + { + // Despawn Nefarius and Rend on fail (the others are despawned OnCreatureEvade()) + if (Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) + pNefarius->ForcedDespawn(); + if (Creature* pRend = GetSingleCreatureFromStorage(NPC_REND_BLACKHAND)) + pRend->ForcedDespawn(); + if (Creature* pGyth = GetSingleCreatureFromStorage(NPC_GYTH)) + pGyth->ForcedDespawn(); + + m_uiStadiumEventTimer = 0; + m_uiStadiumMobsAlive = 0; + m_uiStadiumWaves = 0; + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_DRAKKISATH: + case TYPE_VALTHALAK: + 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_auiEncounter[5]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +void instance_blackrock_spire::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] >> m_auiEncounter[5]; + + 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_blackrock_spire::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_blackrock_spire::DoSortRoomEventMobs() +{ + if (GetData(TYPE_ROOM_EVENT) != NOT_STARTED) + return; + + for (uint8 i = 0; i < MAX_ROOMS; ++i) + { + if (GameObject* pRune = instance->GetGameObject(m_aRoomRuneGuid[i])) + { + 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) + m_alRoomEventMobGUIDSorted[i].push_back(*itr); + } + } + } + + SetData(TYPE_ROOM_EVENT, IN_PROGRESS); +} + +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: + SetData(TYPE_DRAKKISATH, DONE); + DoUseDoorOrButton(GO_DRAKKISATH_DOOR_1); + DoUseDoorOrButton(GO_DRAKKISATH_DOOR_2); + break; + case NPC_CHROMATIC_WHELP: + case NPC_CHROMATIC_DRAGON: + case NPC_BLACKHAND_HANDLER: + // check if it's summoned - some npcs with the same entry are already spawned in the instance + if (!pCreature->IsTemporarySummon()) + break; + --m_uiStadiumMobsAlive; + if (m_uiStadiumMobsAlive == 0) + DoSendNextStadiumWave(); + break; + case NPC_GYTH: + case NPC_REND_BLACKHAND: + --m_uiStadiumMobsAlive; + if (m_uiStadiumMobsAlive == 0) + StartNextDialogueText(SAY_NEFARIUS_VICTORY); + break; + } +} + +void instance_blackrock_spire::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + // 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: + case NPC_GYTH: + case NPC_REND_BLACKHAND: + // check if it's summoned - some npcs with the same entry are already spawned in the instance + if (!pCreature->IsTemporarySummon()) + break; + SetData(TYPE_STADIUM, FAIL); + pCreature->ForcedDespawn(); + break; + } +} + +void instance_blackrock_spire::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + // 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::DoProcessEmberseerEvent() +{ + if (GetData(TYPE_EMBERSEER) == DONE || GetData(TYPE_EMBERSEER) == IN_PROGRESS) + return; + + if (m_lIncarceratorGUIDList.empty()) + { + script_error_log("Npc %u couldn't be found. Please check your DB content!", NPC_BLACKHAND_INCARCERATOR); + return; + } + + // start to grow + if (Creature* pEmberseer = GetSingleCreatureFromStorage(NPC_PYROGUARD_EMBERSEER)) + { + // If already casting, return + if (pEmberseer->HasAura(SPELL_EMBERSEER_GROWING)) + return; + + DoScriptText(EMOTE_BEGIN, pEmberseer); + pEmberseer->CastSpell(pEmberseer, SPELL_EMBERSEER_GROWING, true); + } + + // remove the incarcerators flags and stop casting + for (GuidList::const_iterator itr = m_lIncarceratorGUIDList.begin(); itr != m_lIncarceratorGUIDList.end(); ++itr) + { + if (Creature* pCreature = instance->GetCreature(*itr)) + { + if (pCreature->isAlive()) + { + pCreature->InterruptNonMeleeSpells(false); + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + } +} + +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) + { + if (bReset) + { + if (GameObject* pRune = instance->GetGameObject(*itr)) + pRune->ResetDoorOrButton(); + } + else + DoUseDoorOrButton(*itr); + } +} + +void instance_blackrock_spire::JustDidDialogueStep(int32 iEntry) +{ + switch (iEntry) + { + case NPC_BLACKHAND_HANDLER: + m_uiStadiumEventTimer = 1000; + // Move the two near the balcony + if (Creature* pRend = GetSingleCreatureFromStorage(NPC_REND_BLACKHAND)) + pRend->SetFacingTo(aStadiumLocs[5].m_fO); + if (Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) + pNefarius->GetMotionMaster()->MovePoint(0, aStadiumLocs[5].m_fX, aStadiumLocs[5].m_fY, aStadiumLocs[5].m_fZ); + break; + case SAY_NEFARIUS_WARCHIEF: + // Prepare for Gyth - note: Nefarius should be moving around the balcony + if (Creature* pRend = GetSingleCreatureFromStorage(NPC_REND_BLACKHAND)) + { + pRend->ForcedDespawn(5000); + pRend->SetWalk(false); + pRend->GetMotionMaster()->MovePoint(0, aStadiumLocs[6].m_fX, aStadiumLocs[6].m_fY, aStadiumLocs[6].m_fZ); + } + m_uiStadiumEventTimer = 30000; + break; + case SAY_NEFARIUS_VICTORY: + SetData(TYPE_STADIUM, DONE); + break; + case NPC_REND_BLACKHAND: + // Despawn Nefarius + if (Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) + { + pNefarius->ForcedDespawn(5000); + pNefarius->GetMotionMaster()->MovePoint(0, aStadiumLocs[6].m_fX, aStadiumLocs[6].m_fY, aStadiumLocs[6].m_fZ); + } + break; + } +} + +void instance_blackrock_spire::DoSendNextStadiumWave() +{ + if (m_uiStadiumWaves < MAX_STADIUM_WAVES) + { + // Send current wave mobs + if (Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) + { + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_STADIUM_MOBS_PER_WAVE; ++i) + { + if (aStadiumEventNpcs[m_uiStadiumWaves][i] == 0) + 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 + 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 + + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + ++m_uiStadiumMobsAlive; + } + } + } + + DoUseDoorOrButton(GO_GYTH_COMBAT_DOOR); + } + // All waves are cleared - start Gyth intro + else if (m_uiStadiumWaves == MAX_STADIUM_WAVES) + StartNextDialogueText(SAY_NEFARIUS_LOSE_4); + else + { + // 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)) + pTemp->GetMotionMaster()->MovePoint(0, aStadiumLocs[2].m_fX, aStadiumLocs[2].m_fY, aStadiumLocs[2].m_fZ); + } + + // Set this to 2, because Rend will be summoned later during the fight + m_uiStadiumMobsAlive = 2; + + DoUseDoorOrButton(GO_GYTH_COMBAT_DOOR); + } + + ++m_uiStadiumWaves; + + // Stop the timer when all the waves have been sent + if (m_uiStadiumWaves >= MAX_STADIUM_WAVES) + m_uiStadiumEventTimer = 0; + else + 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); + + if (m_uiStadiumEventTimer) + { + if (m_uiStadiumEventTimer <= uiDiff) + DoSendNextStadiumWave(); + 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) +{ + return new instance_blackrock_spire(pMap); +} + +bool AreaTrigger_at_blackrock_spire(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (!pPlayer->isAlive() || pPlayer->isGameMaster()) + return false; + + switch (pAt->id) + { + case AREATRIGGER_ENTER_UBRS: + if (instance_blackrock_spire* pInstance = (instance_blackrock_spire*) pPlayer->GetInstanceData()) + pInstance->DoSortRoomEventMobs(); + break; + case AREATRIGGER_STADIUM: + if (instance_blackrock_spire* pInstance = (instance_blackrock_spire*) pPlayer->GetInstanceData()) + { + if (pInstance->GetData(TYPE_STADIUM) == IN_PROGRESS || pInstance->GetData(TYPE_STADIUM) == DONE) + return false; + + // 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->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); + + pInstance->SetData(TYPE_STADIUM, IN_PROGRESS); + } + break; + } + return false; +} + +bool ProcessEventId_event_spell_altar_emberseer(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + { + if (instance_blackrock_spire* pInstance = (instance_blackrock_spire*)((Player*)pSource)->GetInstanceData()) + { + pInstance->DoProcessEmberseerEvent(); + return true; + } + } + 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; + + pNewScript = new Script; + pNewScript->Name = "instance_blackrock_spire"; + pNewScript->GetInstanceData = &GetInstanceData_instance_blackrock_spire; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_blackrock_spire"; + pNewScript->pAreaTrigger = &AreaTrigger_at_blackrock_spire; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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/blackrock_mountain/blackwing_descent/blackwing_descent.h b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/blackwing_descent.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/blackwing_descent.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_atramedes.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_atramedes.cpp new file mode 100644 index 0000000000..b1de0cf8aa --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_atramedes.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_atramedes +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_adramedes() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_chimaeron.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_chimaeron.cpp new file mode 100644 index 0000000000..2059943132 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_chimaeron.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_chimaeron +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_chimaeron() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_magmaw.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_magmaw.cpp new file mode 100644 index 0000000000..501adc8ddc --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_magmaw.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_magmaw +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_magmaw() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_maloriak.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_maloriak.cpp new file mode 100644 index 0000000000..2aa5afce62 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_maloriak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_maloriak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_maloriak() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_nefarian_descent.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_nefarian_descent.cpp new file mode 100644 index 0000000000..050d6b7f9a --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/boss_nefarian_descent.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_nefarian_descent +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_nefarian_descent() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/instance_blackwing_descent.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/instance_blackwing_descent.cpp new file mode 100644 index 0000000000..cfac7421b3 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/instance_blackwing_descent.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_blackwing_descent +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_blackwing_descent() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/omnotron_defense.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/omnotron_defense.cpp new file mode 100644 index 0000000000..1a901ce74a --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_descent/omnotron_defense.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: omnotron_defense +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Blackwing Descent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_omnotron_defense() +{ +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/blackwing_lair.h b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/blackwing_lair.h new file mode 100644 index 0000000000..becb76adf7 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/blackwing_lair.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_BLACKWING_LAIR +#define DEF_BLACKWING_LAIR + +enum +{ + MAX_ENCOUNTER = 8, + + TYPE_RAZORGORE = 0, + TYPE_VAELASTRASZ = 1, + TYPE_LASHLAYER = 2, + TYPE_FIREMAW = 3, + TYPE_EBONROC = 4, + TYPE_FLAMEGOR = 5, + TYPE_CHROMAGGUS = 6, + TYPE_NEFARIAN = 7, + + DATA_DRAGON_EGG = 1, // track the used eggs + + NPC_RAZORGORE = 12435, + NPC_VAELASTRASZ = 13020, + NPC_LASHLAYER = 12017, + NPC_FIREMAW = 11983, + NPC_EBONROC = 14601, + NPC_FLAMEGOR = 11981, + NPC_CHROMAGGUS = 14020, + 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_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 uint32 aRazorgoreSpawns[MAX_EGGS_DEFENDERS] = {NPC_BLACKWING_LEGIONNAIRE, NPC_BLACKWING_MAGE, NPC_DRAGONSPAWN, NPC_DRAGONSPAWN}; + +class MANGOS_DLL_DECL instance_blackwing_lair : public ScriptedInstance +{ + public: + instance_blackwing_lair(Map* pMap); + ~instance_blackwing_lair() {} + + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + + 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]; + + 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/blackrock_mountain/blackwing_lair/boss_broodlord_lashlayer.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_broodlord_lashlayer.cpp new file mode 100644 index 0000000000..0b24f6a58b --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_broodlord_lashlayer.cpp @@ -0,0 +1,144 @@ +/* Copyright (C) 2006 - 2013 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_Broodlord_Lashlayer +SD%Complete: 100 +SDComment: +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + SAY_AGGRO = -1469000, + SAY_LEASH = -1469001, + + SPELL_CLEAVE = 26350, + SPELL_BLAST_WAVE = 23331, + SPELL_MORTAL_STRIKE = 24573, + SPELL_KNOCK_AWAY = 25778 +}; + +struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI +{ + boss_broodlordAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiCleaveTimer; + uint32 m_uiBlastWaveTimer; + uint32 m_uiMortalStrikeTimer; + uint32 m_uiKnockAwayTimer; + + void Reset() + { + m_uiCleaveTimer = 8000; // These times are probably wrong + m_uiBlastWaveTimer = 12000; + m_uiMortalStrikeTimer = 20000; + m_uiKnockAwayTimer = 30000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LASHLAYER, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LASHLAYER, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LASHLAYER, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Cleave Timer + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 7000; + } + else + m_uiCleaveTimer -= uiDiff; + + // Blast Wave + if (m_uiBlastWaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE) == CAST_OK) + m_uiBlastWaveTimer = urand(8000, 16000); + } + else + m_uiBlastWaveTimer -= uiDiff; + + // Mortal Strike Timer + if (m_uiMortalStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiMortalStrikeTimer = urand(25000, 35000); + } + else + m_uiMortalStrikeTimer -= uiDiff; + + if (m_uiKnockAwayTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_KNOCK_AWAY); + // Drop 50% aggro - TODO should be scriptedEffect? + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -50); + + m_uiKnockAwayTimer = urand(15000, 30000); + } + else + m_uiKnockAwayTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + if (EnterEvadeIfOutOfCombatArea(uiDiff)) + DoScriptText(SAY_LEASH, m_creature); + } +}; +CreatureAI* GetAI_boss_broodlord(Creature* pCreature) +{ + return new boss_broodlordAI(pCreature); +} + +void AddSC_boss_broodlord() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_broodlord"; + pNewScript->GetAI = &GetAI_boss_broodlord; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_chromaggus.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_chromaggus.cpp new file mode 100644 index 0000000000..73eb714511 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_chromaggus.cpp @@ -0,0 +1,258 @@ +/* Copyright (C) 2006 - 2013 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_Chromaggus +SD%Complete: 95 +SDComment: Chromatic Mutation disabled due to lack of core support +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + EMOTE_GENERIC_FRENZY_KILL = -1000001, + EMOTE_SHIMMER = -1469003, + + // These spells are actually called elemental shield + // What they do is decrease all damage by 75% then they increase + // One school of damage by 1100% + SPELL_FIRE_VULNERABILITY = 22277, + SPELL_FROST_VULNERABILITY = 22278, + SPELL_SHADOW_VULNERABILITY = 22279, + SPELL_NATURE_VULNERABILITY = 22280, + SPELL_ARCANE_VULNERABILITY = 22281, + + MAX_BREATHS = 5, + SPELL_INCINERATE = 23308, // Incinerate 23308,23309 + SPELL_TIME_LAPSE = 23310, // Time lapse 23310, 23311(old threat mod that was removed in 2.01) + SPELL_CORROSIVE_ACID = 23313, // Corrosive Acid 23313, 23314 + SPELL_IGNITE_FLESH = 23315, // Ignite Flesh 23315,23316 + SPELL_FROST_BURN = 23187, // Frost burn 23187, 23189 + + // Brood Affliction 23173 - Scripted Spell that cycles through all targets within 100 yards and has a chance to cast one of the afflictions on them + // Since Scripted spells arn't coded I'll just write a function that does the same thing + SPELL_BROODAF_BLUE = 23153, // Blue affliction 23153 + SPELL_BROODAF_BLACK = 23154, // Black affliction 23154 + SPELL_BROODAF_RED = 23155, // Red affliction 23155 (23168 on death) + SPELL_BROODAF_BRONZE = 23170, // Bronze Affliction 23170 + SPELL_BROODAF_GREEN = 23169, // Brood Affliction Green 23169 + + SPELL_CHROMATIC_MUT_1 = 23174, // Spell cast on player if they get all 5 debuffs + + SPELL_FRENZY = 28371, // The frenzy spell may be wrong + SPELL_ENRAGE = 28747 +}; + +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 +{ + boss_chromaggusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + // Select the 2 different breaths that we are going to use until despawned + // 5 possiblities for the first breath, 4 for the second, 20 total possiblites + + // select two different numbers between 0..MAX_BREATHS-1 + uint8 uiPos1 = urand(0, MAX_BREATHS - 1); + uint8 uiPos2 = (uiPos1 + urand(1, MAX_BREATHS - 1)) % MAX_BREATHS; + + m_uiBreathOneSpell = aPossibleBreaths[uiPos1]; + m_uiBreathTwoSpell = aPossibleBreaths[uiPos2]; + + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiBreathOneSpell; + uint32 m_uiBreathTwoSpell; + uint32 m_uiCurrentVulnerabilitySpell; + + uint32 m_uiShimmerTimer; + uint32 m_uiBreathOneTimer; + uint32 m_uiBreathTwoTimer; + uint32 m_uiAfflictionTimer; + uint32 m_uiFrenzyTimer; + bool m_bEnraged; + + void Reset() + { + m_uiCurrentVulnerabilitySpell = 0; // We use this to store our last vulnerability spell so we can remove it later + + m_uiShimmerTimer = 0; // Time till we change vurlnerabilites + m_uiBreathOneTimer = 30000; // First breath is 30 seconds + m_uiBreathTwoTimer = 60000; // Second is 1 minute so that we can alternate + m_uiAfflictionTimer = 10000; // This is special - 5 seconds means that we cast this on 1 pPlayer every 5 sconds + m_uiFrenzyTimer = 15000; + + m_bEnraged = false; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CHROMAGGUS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CHROMAGGUS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CHROMAGGUS, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Shimmer Timer Timer + if (m_uiShimmerTimer < uiDiff) + { + // Remove old vulnerability spell + if (m_uiCurrentVulnerabilitySpell) + m_creature->RemoveAurasDueToSpell(m_uiCurrentVulnerabilitySpell); + + // Cast new random vurlnabilty on self + uint32 aSpellId[] = {SPELL_FIRE_VULNERABILITY, SPELL_FROST_VULNERABILITY, SPELL_SHADOW_VULNERABILITY, SPELL_NATURE_VULNERABILITY, SPELL_ARCANE_VULNERABILITY}; + uint32 uiSpell = aSpellId[urand(0, 4)]; + + if (DoCastSpellIfCan(m_creature, uiSpell) == CAST_OK) + { + m_uiCurrentVulnerabilitySpell = uiSpell; + + DoScriptText(EMOTE_SHIMMER, m_creature); + m_uiShimmerTimer = 45000; + } + } + else + m_uiShimmerTimer -= uiDiff; + + // Breath One Timer + if (m_uiBreathOneTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_uiBreathOneSpell) == CAST_OK) + m_uiBreathOneTimer = 60000; + } + else + m_uiBreathOneTimer -= uiDiff; + + // Breath Two Timer + if (m_uiBreathTwoTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_uiBreathTwoSpell) == CAST_OK) + m_uiBreathTwoTimer = 60000; + } + else + m_uiBreathTwoTimer -= uiDiff; + + // Affliction Timer + if (m_uiAfflictionTimer < uiDiff) + { + uint32 m_uiSpellAfflict = 0; + + switch (urand(0, 4)) + { + case 0: m_uiSpellAfflict = SPELL_BROODAF_BLUE; break; + case 1: m_uiSpellAfflict = SPELL_BROODAF_BLACK; break; + case 2: m_uiSpellAfflict = SPELL_BROODAF_RED; break; + case 3: m_uiSpellAfflict = SPELL_BROODAF_BRONZE; break; + case 4: m_uiSpellAfflict = SPELL_BROODAF_GREEN; break; + } + + GuidVector vGuids; + m_creature->FillGuidsListFromThreatList(vGuids); + for (GuidVector::const_iterator i = vGuids.begin(); i != vGuids.end(); ++i) + { + Unit* pUnit = m_creature->GetMap()->GetUnit(*i); + + if (pUnit) + { + // Cast affliction + DoCastSpellIfCan(pUnit, m_uiSpellAfflict, CAST_TRIGGERED); + + // 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)) + { + // 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 + // So instead we instant kill our target + + // WORKAROUND + if (pUnit->GetTypeId() == TYPEID_PLAYER) + m_creature->CastSpell(pUnit, 5, false); + } + } + } + + m_uiAfflictionTimer = 10000; + } + else + m_uiAfflictionTimer -= uiDiff; + + // Frenzy Timer + if (m_uiFrenzyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); + m_uiFrenzyTimer = urand(10000, 15000); + } + } + else + m_uiFrenzyTimer -= uiDiff; + + // Enrage if not already enraged and below 20% + if (!m_bEnraged && m_creature->GetHealthPercent() < 20.0f) + { + DoCastSpellIfCan(m_creature, SPELL_ENRAGE); + m_bEnraged = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_chromaggus(Creature* pCreature) +{ + return new boss_chromaggusAI(pCreature); +} + +void AddSC_boss_chromaggus() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_chromaggus"; + pNewScript->GetAI = &GetAI_boss_chromaggus; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_ebonroc.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_ebonroc.cpp new file mode 100644 index 0000000000..5f0ff5eeb6 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_ebonroc.cpp @@ -0,0 +1,123 @@ +/* Copyright (C) 2006 - 2013 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_Ebonroc +SD%Complete: 90 +SDComment: Thrash is missing +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + SPELL_SHADOW_FLAME = 22539, + SPELL_WING_BUFFET = 18500, + SPELL_SHADOW_OF_EBONROC = 23340, + SPELL_THRASH = 3391, // TODO missing +}; + +struct MANGOS_DLL_DECL boss_ebonrocAI : public ScriptedAI +{ + boss_ebonrocAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShadowFlameTimer; + uint32 m_uiWingBuffetTimer; + uint32 m_uiShadowOfEbonrocTimer; + + void Reset() + { + m_uiShadowFlameTimer = 15000; // These times are probably wrong + m_uiWingBuffetTimer = 30000; + m_uiShadowOfEbonrocTimer = 45000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EBONROC, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EBONROC, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EBONROC, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Shadow Flame Timer + if (m_uiShadowFlameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_FLAME) == CAST_OK) + m_uiShadowFlameTimer = urand(12000, 15000); + } + else + m_uiShadowFlameTimer -= uiDiff; + + // Wing Buffet Timer + if (m_uiWingBuffetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WING_BUFFET) == CAST_OK) + m_uiWingBuffetTimer = 25000; + } + else + m_uiWingBuffetTimer -= uiDiff; + + // Shadow of Ebonroc Timer + if (m_uiShadowOfEbonrocTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_OF_EBONROC) == CAST_OK) + m_uiShadowOfEbonrocTimer = urand(25000, 35000); + } + else + m_uiShadowOfEbonrocTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ebonroc(Creature* pCreature) +{ + return new boss_ebonrocAI(pCreature); +} + +void AddSC_boss_ebonroc() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ebonroc"; + pNewScript->GetAI = &GetAI_boss_ebonroc; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_firemaw.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_firemaw.cpp new file mode 100644 index 0000000000..375bade812 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_firemaw.cpp @@ -0,0 +1,127 @@ +/* Copyright (C) 2006 - 2013 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_Firemaw +SD%Complete: 80 +SDComment: Thrash missing +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + SPELL_SHADOW_FLAME = 22539, + SPELL_WING_BUFFET = 23339, + SPELL_FLAME_BUFFET = 23341, + SPELL_THRASH = 3391, // TODO, missing +}; + +struct MANGOS_DLL_DECL boss_firemawAI : public ScriptedAI +{ + boss_firemawAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShadowFlameTimer; + uint32 m_uiWingBuffetTimer; + uint32 m_uiFlameBuffetTimer; + + void Reset() + { + m_uiShadowFlameTimer = 30000; // These times are probably wrong + m_uiWingBuffetTimer = 24000; + m_uiFlameBuffetTimer = 5000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FIREMAW, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FIREMAW, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FIREMAW, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Shadow Flame Timer + if (m_uiShadowFlameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_FLAME) == CAST_OK) + m_uiShadowFlameTimer = urand(15000, 18000); + } + else + m_uiShadowFlameTimer -= uiDiff; + + // Wing Buffet Timer + if (m_uiWingBuffetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WING_BUFFET) == CAST_OK) + { + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -75); + + m_uiWingBuffetTimer = 25000; + } + } + else + m_uiWingBuffetTimer -= uiDiff; + + // Flame Buffet Timer + if (m_uiFlameBuffetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BUFFET) == CAST_OK) + m_uiFlameBuffetTimer = 5000; + } + else + m_uiFlameBuffetTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_firemaw(Creature* pCreature) +{ + return new boss_firemawAI(pCreature); +} + +void AddSC_boss_firemaw() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_firemaw"; + pNewScript->GetAI = &GetAI_boss_firemaw; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_flamegor.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_flamegor.cpp new file mode 100644 index 0000000000..a5a31eebb1 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_flamegor.cpp @@ -0,0 +1,132 @@ +/* Copyright (C) 2006 - 2013 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_Flamegor +SD%Complete: 90 +SDComment: Thrash is missing +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + EMOTE_GENERIC_FRENZY = -1000002, + + SPELL_SHADOW_FLAME = 22539, + SPELL_WING_BUFFET = 23339, + SPELL_FRENZY = 23342, // This spell periodically triggers fire nova + SPELL_THRASH = 3391, // TODO missing +}; + +struct MANGOS_DLL_DECL boss_flamegorAI : public ScriptedAI +{ + boss_flamegorAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShadowFlameTimer; + uint32 m_uiWingBuffetTimer; + uint32 m_uiFrenzyTimer; + + void Reset() + { + m_uiShadowFlameTimer = 21000; // These times are probably wrong + m_uiWingBuffetTimer = 35000; + m_uiFrenzyTimer = 10000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FLAMEGOR, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FLAMEGOR, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FLAMEGOR, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Shadow Flame Timer + if (m_uiShadowFlameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_FLAME) == CAST_OK) + m_uiShadowFlameTimer = urand(15000, 22000); + } + else + m_uiShadowFlameTimer -= uiDiff; + + // Wing Buffet Timer + if (m_uiWingBuffetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WING_BUFFET) == CAST_OK) + { + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -75); + + m_uiWingBuffetTimer = 25000; + } + } + else + m_uiWingBuffetTimer -= uiDiff; + + // Frenzy Timer + if (m_uiFrenzyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); + m_uiFrenzyTimer = urand(8000, 10000); + } + } + else + m_uiFrenzyTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_flamegor(Creature* pCreature) +{ + return new boss_flamegorAI(pCreature); +} + +void AddSC_boss_flamegor() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_flamegor"; + pNewScript->GetAI = &GetAI_boss_flamegor; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_nefarian.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_nefarian.cpp new file mode 100644 index 0000000000..3892157600 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_nefarian.cpp @@ -0,0 +1,281 @@ +/* Copyright (C) 2006 - 2013 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_Nefarian +SD%Complete: 80 +SDComment: Some issues with class calls effecting more than one class +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" +#include "TemporarySummon.h" + +enum +{ + SAY_XHEALTH = -1469008, // at 5% hp + SAY_AGGRO = -1469009, + SAY_RAISE_SKELETONS = -1469010, + SAY_SLAY = -1469011, + SAY_DEATH = -1469012, + + SAY_MAGE = -1469013, + SAY_WARRIOR = -1469014, + SAY_DRUID = -1469015, + SAY_PRIEST = -1469016, + SAY_PALADIN = -1469017, + SAY_SHAMAN = -1469018, + SAY_WARLOCK = -1469019, + SAY_HUNTER = -1469020, + SAY_ROGUE = -1469021, + SAY_DEATH_KNIGHT = -1469031, // spell unk for the moment + + SPELL_SHADOWFLAME_INITIAL = 22992, // old spell id 22972 -> wrong + SPELL_SHADOWFLAME = 22539, + SPELL_BELLOWING_ROAR = 22686, + 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_MAGE = 23410, // wild magic + SPELL_WARRIOR = 23397, // beserk + SPELL_DRUID = 23398, // cat form + SPELL_PRIEST = 23401, // corrupted healing + SPELL_PALADIN = 23418, // syphon blessing + SPELL_SHAMAN = 23425, // totems + SPELL_WARLOCK = 23427, // infernals -> should trigger 23426 + SPELL_HUNTER = 23436, // bow broke + SPELL_ROGUE = 23414, // Paralise +}; + +struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI +{ + boss_nefarianAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShadowFlameTimer; + uint32 m_uiBellowingRoarTimer; + uint32 m_uiVeilOfShadowTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiTailLashTimer; + uint32 m_uiClassCallTimer; + bool m_bPhase3; + bool m_bHasEndYell; + + void Reset() + { + 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_bPhase3 = false; + m_bHasEndYell = false; + } + + void KilledUnit(Unit* pVictim) override + { + if (urand(0, 4)) + return; + + DoScriptText(SAY_SLAY, m_creature, pVictim); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_NEFARIAN, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_NEFARIAN, FAIL); + + // Cleanup encounter + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Creature* pNefarius = m_creature->GetMap()->GetCreature(pTemporary->GetSummonerGuid())) + pNefarius->AI()->EnterEvadeMode(); + } + + m_creature->ForcedDespawn(); + } + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + // Remove flying in case Nefarian aggroes before his combat point was reached + if (m_creature->IsLevitating()) + { + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); + m_creature->SetLevitate(false); + } + + DoCastSpellIfCan(m_creature, SPELL_SHADOWFLAME_INITIAL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // ShadowFlame_Timer + if (m_uiShadowFlameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOWFLAME) == CAST_OK) + m_uiShadowFlameTimer = 12000; + } + else + m_uiShadowFlameTimer -= uiDiff; + + // BellowingRoar_Timer + if (m_uiBellowingRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BELLOWING_ROAR) == CAST_OK) + m_uiBellowingRoarTimer = 30000; + } + else + m_uiBellowingRoarTimer -= uiDiff; + + // VeilOfShadow_Timer + if (m_uiVeilOfShadowTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_VEIL_OF_SHADOW) == CAST_OK) + m_uiVeilOfShadowTimer = 15000; + } + else + m_uiVeilOfShadowTimer -= uiDiff; + + // Cleave_Timer + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 7000; + } + else + m_uiCleaveTimer -= uiDiff; + + // TailLash_Timer + if (m_uiTailLashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = 10000; + } + else + m_uiTailLashTimer -= uiDiff; + + // 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 + + switch (urand(0, 8)) + { + case 0: + DoScriptText(SAY_MAGE, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MAGE); + break; + case 1: + DoScriptText(SAY_WARRIOR, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WARRIOR); + break; + case 2: + DoScriptText(SAY_DRUID, m_creature); + DoCastSpellIfCan(m_creature, SPELL_DRUID); + break; + case 3: + DoScriptText(SAY_PRIEST, m_creature); + DoCastSpellIfCan(m_creature, SPELL_PRIEST); + break; + case 4: + DoScriptText(SAY_PALADIN, m_creature); + DoCastSpellIfCan(m_creature, SPELL_PALADIN); + break; + case 5: + DoScriptText(SAY_SHAMAN, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SHAMAN); + break; + case 6: + DoScriptText(SAY_WARLOCK, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WARLOCK); + break; + case 7: + DoScriptText(SAY_HUNTER, m_creature); + DoCastSpellIfCan(m_creature, SPELL_HUNTER); + break; + case 8: + DoScriptText(SAY_ROGUE, m_creature); + DoCastSpellIfCan(m_creature, SPELL_ROGUE); + break; + } + + m_uiClassCallTimer = urand(35000, 40000); + } + else + m_uiClassCallTimer -= uiDiff; + + // Phase3 begins when we are below X health + if (!m_bPhase3 && m_creature->GetHealthPercent() < 20.0f) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NEFARIAN, SPECIAL); + m_bPhase3 = true; + DoScriptText(SAY_RAISE_SKELETONS, m_creature); + } + + // 5% hp yell + if (!m_bHasEndYell && m_creature->GetHealthPercent() < 5.0f) + { + m_bHasEndYell = true; + DoScriptText(SAY_XHEALTH, m_creature); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_nefarian(Creature* pCreature) +{ + return new boss_nefarianAI(pCreature); +} + +void AddSC_boss_nefarian() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_nefarian"; + pNewScript->GetAI = &GetAI_boss_nefarian; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_razorgore.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_razorgore.cpp new file mode 100644 index 0000000000..f26cfdc6e2 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_razorgore.cpp @@ -0,0 +1,248 @@ +/* Copyright (C) 2006 - 2013 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_Razorgore +SD%Complete: 95 +SDComment: Timers may be improved. +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + SAY_EGGS_BROKEN_1 = -1469022, + SAY_EGGS_BROKEN_2 = -1469023, + SAY_EGGS_BROKEN_3 = -1469024, + SAY_DEATH = -1469025, + + SPELL_POSSESS = 23014, // visual effect and increase the damage taken + 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, +}; + +struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI +{ + boss_razorgoreAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_blackwing_lair*)pCreature->GetInstanceData(); + Reset(); + } + + instance_blackwing_lair* m_pInstance; + + uint32 m_uiIntroVisualTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiWarStompTimer; + uint32 m_uiFireballVolleyTimer; + uint32 m_uiConflagrationTimer; + + bool m_bEggsExploded; + + void Reset() + { + m_uiIntroVisualTimer = 5000; + m_bEggsExploded = false; + + m_uiCleaveTimer = urand(4000, 8000); + m_uiWarStompTimer = 30000; + m_uiConflagrationTimer = urand(10000, 15000); + m_uiFireballVolleyTimer = urand(15000, 20000); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + { + // Don't set instance data unless all eggs are destroyed + if (m_pInstance->GetData(TYPE_RAZORGORE) != SPECIAL) + return; + + m_pInstance->SetData(TYPE_RAZORGORE, DONE); + } + + DoScriptText(SAY_DEATH, m_creature); + } + + 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 JustSummoned(Creature* pSummoned) override + { + // 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()) + { + // Set visual only on OOC timer + if (m_uiIntroVisualTimer) + { + 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; + } + + return; + } + + // Cleave + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(4000, 8000); + } + else + m_uiCleaveTimer -= uiDiff; + + // War Stomp + if (m_uiWarStompTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WARSTOMP) == CAST_OK) + m_uiWarStompTimer = 30000; + } + else + m_uiWarStompTimer -= uiDiff; + + // Fireball Volley + if (m_uiFireballVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FIREBALL_VOLLEY) == CAST_OK) + m_uiFireballVolleyTimer = urand(15000, 20000); + } + else + m_uiFireballVolleyTimer -= uiDiff; + + // Conflagration + if (m_uiConflagrationTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CONFLAGRATION) == CAST_OK) + m_uiConflagrationTimer = urand(15000, 25000); + } + else + m_uiConflagrationTimer -= uiDiff; + + /* This is obsolete code, not working anymore, keep as reference, should be handled in core though + * // Aura Check. If the gamer is affected by confliguration we attack a random gamer. + * if (m_creature->getVictim()->HasAura(SPELL_CONFLAGRATION, EFFECT_INDEX_0)) + * { + * if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + * m_creature->TauntApply(pTarget); + * } + */ + + DoMeleeAttackIfReady(); + } +}; + +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; + + pNewScript = new Script; + 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/blackrock_mountain/blackwing_lair/boss_vaelastrasz.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_vaelastrasz.cpp new file mode 100644 index 0000000000..8667a00647 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_vaelastrasz.cpp @@ -0,0 +1,390 @@ +/* Copyright (C) 2006 - 2013 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_Vaelastrasz +SD%Complete: 75 +SDComment: Burning Adrenaline not correctly implemented in core +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + SAY_LINE_1 = -1469026, + SAY_LINE_2 = -1469027, + SAY_LINE_3 = -1469028, + SAY_HALFLIFE = -1469029, + SAY_KILLTARGET = -1469030, + SAY_NEFARIUS_CORRUPT_1 = -1469006, // When he corrupts Vaelastrasz + SAY_NEFARIUS_CORRUPT_2 = -1469032, + SAY_TECHNICIAN_RUN = -1469034, + + SPELL_ESSENCE_OF_THE_RED = 23513, + SPELL_FLAME_BREATH = 23461, + SPELL_FIRE_NOVA = 23462, + SPELL_TAIL_SWEEP = 15847, + SPELL_BURNING_ADRENALINE = 23620, + SPELL_CLEAVE = 20684, // Chain cleave is most likely named something different and contains a dummy effect + + SPELL_NEFARIUS_CORRUPTION = 23642, + + GOSSIP_ITEM_VAEL_1 = -3469003, + GOSSIP_ITEM_VAEL_2 = -3469004, + // Vael Gossip texts might be 7156 and 7256; At the moment are missing from DB + // For the moment add the default values + GOSSIP_TEXT_VAEL_1 = 384, + GOSSIP_TEXT_VAEL_2 = 384, + + FACTION_HOSTILE = 14, + + AREATRIGGER_VAEL_INTRO = 3626, +}; + +struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI +{ + boss_vaelastraszAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + + // Set stand state to dead before the intro event + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + } + + ScriptedInstance* m_pInstance; + + ObjectGuid m_nefariusGuid; + uint32 m_uiIntroTimer; + uint8 m_uiIntroPhase; + + ObjectGuid m_playerGuid; + uint32 m_uiSpeechTimer; + uint8 m_uiSpeechNum; + + uint32 m_uiCleaveTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiFireNovaTimer; + uint32 m_uiBurningAdrenalineCasterTimer; + uint32 m_uiBurningAdrenalineTankTimer; + uint32 m_uiTailSweepTimer; + bool m_bHasYelled; + + void Reset() + { + m_playerGuid.Clear(); + + m_uiIntroTimer = 0; + m_uiIntroPhase = 0; + m_uiSpeechTimer = 0; + m_uiSpeechNum = 0; + m_uiCleaveTimer = 8000; // These times are probably wrong + m_uiFlameBreathTimer = 11000; + m_uiBurningAdrenalineCasterTimer = 15000; + m_uiBurningAdrenalineTankTimer = 45000; + m_uiFireNovaTimer = 5000; + m_uiTailSweepTimer = 20000; + m_bHasYelled = false; + + // Creature should have only 1/3 of hp + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.3)); + } + + void BeginIntro() + { + // Start Intro delayed + m_uiIntroTimer = 1000; + + if (m_pInstance) + m_pInstance->SetData(TYPE_VAELASTRASZ, SPECIAL); + } + + void BeginSpeech(Player* pTarget) + { + // Stand up and begin speach + m_playerGuid = pTarget->GetObjectGuid(); + + // 10 seconds + DoScriptText(SAY_LINE_1, m_creature); + + // Make boss stand + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + m_uiSpeechTimer = 10000; + m_uiSpeechNum = 0; + } + + void KilledUnit(Unit* pVictim) override + { + if (urand(0, 4)) + return; + + DoScriptText(SAY_KILLTARGET, m_creature, pVictim); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VAELASTRASZ, IN_PROGRESS); + + // Buff players on aggro + DoCastSpellIfCan(m_creature, SPELL_ESSENCE_OF_THE_RED); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VAELASTRASZ, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VAELASTRASZ, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_LORD_VICTOR_NEFARIUS) + { + // Set not selectable, so players won't interact with it + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_nefariusGuid = pSummoned->GetObjectGuid(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiIntroTimer) + { + if (m_uiIntroTimer <= uiDiff) + { + switch (m_uiIntroPhase) + { + case 0: + m_creature->SummonCreature(NPC_LORD_VICTOR_NEFARIUS, aNefariusSpawnLoc[0], aNefariusSpawnLoc[1], aNefariusSpawnLoc[2], aNefariusSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 25000); + m_uiIntroTimer = 1000; + break; + case 1: + if (Creature* pNefarius = m_creature->GetMap()->GetCreature(m_nefariusGuid)) + { + pNefarius->CastSpell(m_creature, SPELL_NEFARIUS_CORRUPTION, true); + DoScriptText(SAY_NEFARIUS_CORRUPT_1, pNefarius); + } + m_uiIntroTimer = 16000; + break; + case 2: + if (Creature* pNefarius = m_creature->GetMap()->GetCreature(m_nefariusGuid)) + DoScriptText(SAY_NEFARIUS_CORRUPT_2, pNefarius); + + // Set npc flags now + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_uiIntroTimer = 0; + break; + } + ++m_uiIntroPhase; + } + else + m_uiIntroTimer -= uiDiff; + } + + // Speech + if (m_uiSpeechTimer) + { + if (m_uiSpeechTimer <= uiDiff) + { + switch (m_uiSpeechNum) + { + case 0: + // 16 seconds till next line + DoScriptText(SAY_LINE_2, m_creature); + m_uiSpeechTimer = 16000; + ++m_uiSpeechNum; + break; + case 1: + // This one is actually 16 seconds but we only go to 10 seconds because he starts attacking after he says "I must fight this!" + DoScriptText(SAY_LINE_3, m_creature); + m_uiSpeechTimer = 10000; + ++m_uiSpeechNum; + break; + case 2: + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN); + + if (m_playerGuid) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + AttackStart(pPlayer); + } + m_uiSpeechTimer = 0; + break; + } + } + else + m_uiSpeechTimer -= uiDiff; + } + + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Yell if hp lower than 15% + if (m_creature->GetHealthPercent() < 15.0f && !m_bHasYelled) + { + DoScriptText(SAY_HALFLIFE, m_creature); + m_bHasYelled = true; + } + + // Cleave Timer + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 15000; + } + else + m_uiCleaveTimer -= uiDiff; + + // Flame Breath Timer + if (m_uiFlameBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BREATH) == CAST_OK) + m_uiFlameBreathTimer = urand(4000, 8000); + } + else + m_uiFlameBreathTimer -= uiDiff; + + // Burning Adrenaline Caster Timer + if (m_uiBurningAdrenalineCasterTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BURNING_ADRENALINE, SELECT_FLAG_PLAYER | SELECT_FLAG_POWER_MANA)) + { + pTarget->CastSpell(pTarget, SPELL_BURNING_ADRENALINE, true, NULL, NULL, m_creature->GetObjectGuid()); + m_uiBurningAdrenalineCasterTimer = 15000; + } + } + else + m_uiBurningAdrenalineCasterTimer -= uiDiff; + + // Burning Adrenaline Tank Timer + if (m_uiBurningAdrenalineTankTimer < uiDiff) + { + // have the victim cast the spell on himself otherwise the third effect aura will be applied + // to Vael instead of the player + m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_BURNING_ADRENALINE, true, NULL, NULL, m_creature->GetObjectGuid()); + + m_uiBurningAdrenalineTankTimer = 45000; + } + else + m_uiBurningAdrenalineTankTimer -= uiDiff; + + // Fire Nova Timer + if (m_uiFireNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FIRE_NOVA) == CAST_OK) + m_uiFireNovaTimer = 5000; + } + else + m_uiFireNovaTimer -= uiDiff; + + // Tail Sweep Timer + if (m_uiTailSweepTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_SWEEP) == CAST_OK) + m_uiTailSweepTimer = 20000; + } + else + m_uiTailSweepTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +bool GossipSelect_boss_vaelastrasz(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF + 1: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VAEL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_VAEL_2, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + pPlayer->CLOSE_GOSSIP_MENU(); + if (boss_vaelastraszAI* pVaelAI = dynamic_cast(pCreature->AI())) + pVaelAI->BeginSpeech(pPlayer); + break; + } + + return true; +} + +bool GossipHello_boss_vaelastrasz(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VAEL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_VAEL_1, pCreature->GetObjectGuid()); + + return true; +} + +CreatureAI* GetAI_boss_vaelastrasz(Creature* pCreature) +{ + return new boss_vaelastraszAI(pCreature); +} + +bool AreaTrigger_at_vaelastrasz(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_VAEL_INTRO) + { + if (pPlayer->isGameMaster() || pPlayer->isDead()) + return false; + + if (instance_blackwing_lair* pInstance = (instance_blackwing_lair*)pPlayer->GetInstanceData()) + { + // Handle intro event + if (pInstance->GetData(TYPE_VAELASTRASZ) == NOT_STARTED) + { + if (Creature* pVaelastrasz = pInstance->GetSingleCreatureFromStorage(NPC_VAELASTRASZ)) + if (boss_vaelastraszAI* pVaelAI = dynamic_cast(pVaelastrasz->AI())) + pVaelAI->BeginIntro(); + } + + // ToDo: make goblins flee + } + } + + return false; +} + +void AddSC_boss_vaelastrasz() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_vaelastrasz"; + pNewScript->GetAI = &GetAI_boss_vaelastrasz; + pNewScript->pGossipHello = &GossipHello_boss_vaelastrasz; + pNewScript->pGossipSelect = &GossipSelect_boss_vaelastrasz; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_vaelastrasz"; + pNewScript->pAreaTrigger = &AreaTrigger_at_vaelastrasz; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_victor_nefarius.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_victor_nefarius.cpp new file mode 100644 index 0000000000..da057a7575 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/boss_victor_nefarius.cpp @@ -0,0 +1,413 @@ +/* Copyright (C) 2006 - 2013 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_Victor_Nefarius +SD%Complete: 90 +SDComment: Small adjustments needed; Timers +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +enum +{ + SAY_GAMESBEGIN_1 = -1469004, + SAY_GAMESBEGIN_2 = -1469005, + SAY_NEFARIAN_INTRO = -1469007, + + GOSSIP_ITEM_NEFARIUS_1 = -3469000, + GOSSIP_ITEM_NEFARIUS_2 = -3469001, + GOSSIP_ITEM_NEFARIUS_3 = -3469002, + GOSSIP_TEXT_NEFARIUS_1 = 7134, + GOSSIP_TEXT_NEFARIUS_2 = 7198, + GOSSIP_TEXT_NEFARIUS_3 = 7199, + + MAX_DRAKES = 5, + MAX_DRAKE_SUMMONS = 42, + NPC_BRONZE_DRAKANOID = 14263, + NPC_BLUE_DRAKANOID = 14261, + NPC_RED_DRAKANOID = 14264, + NPC_GREEN_DRAKANOID = 14262, + NPC_BLACK_DRAKANOID = 14265, + NPC_CHROMATIC_DRAKANOID = 14302, + + SPELL_NEFARIUS_BARRIER = 22663, // immunity in phase 1 + SPELL_SHADOWBLINK_INTRO = 22664, + SPELL_SHADOWBOLT_VOLLEY = 22665, + SPELL_SILENCE = 22666, + SPELL_SHADOW_COMMAND = 22667, + SPELL_SHADOWBOLT = 22677, + 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 +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_GAMESBEGIN_1, NPC_LORD_VICTOR_NEFARIUS, 4000}, + {SAY_GAMESBEGIN_2, NPC_LORD_VICTOR_NEFARIUS, 5000}, + {SPELL_SHADOWBLINK, 0, 0}, + {0, 0, 0}, +}; + +static const LOCATION 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 +}; + +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 + +// 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 +{ + boss_victor_nefariusAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + // Select the 2 different drakes that we are going to use until despawned + // 5 possiblities for the first drake, 4 for the second, 20 total possiblites + + // select two different numbers between 0..MAX_DRAKES-1 + uint8 uiPos1 = urand(0, MAX_DRAKES - 1); + uint8 uiPos2 = (uiPos1 + urand(1, MAX_DRAKES - 1)) % MAX_DRAKES; + + m_uiDrakeTypeOne = aPossibleDrake[uiPos1]; + m_uiDrakeTypeTwo = aPossibleDrake[uiPos2]; + + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiSpawnedAdds; + uint32 m_uiAddSpawnTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiFearTimer; + uint32 m_uiDrakeTypeOne; + uint32 m_uiDrakeTypeTwo; + uint32 m_uiShadowboltVolleyTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiShadowCommandTimer; + uint32 m_uiShadowBlinkTimer; + + void Reset() + { + // 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) + return; + + m_uiSpawnedAdds = 0; + m_uiAddSpawnTimer = 10000; + m_uiShadowBoltTimer = 3000; + m_uiFearTimer = 8000; + m_uiShadowboltVolleyTimer = 13000; + m_uiSilenceTimer = 23000; + m_uiShadowCommandTimer = 30000; + m_uiShadowBlinkTimer = 40000; + + // set gossip flag to begin the event + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + // Make visible if needed + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NEFARIAN, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NEFARIAN, FAIL); + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + // Only range attack - ToDo: research the distance + m_creature->GetMotionMaster()->MoveChase(pWho, 30.0f); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (m_creature->GetMapId() != MAP_ID_BWL) + return; + + if (pSummoned->GetEntry() == NPC_NEFARIAN) + { + 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_HOVER); + pSummoned->SetLevitate(true); + + // Let Nefarian fly towards combat area + pSummoned->GetMotionMaster()->MovePoint(1, aNefarianLocs[3].x, aNefarianLocs[3].y, aNefarianLocs[3].z); + DoScriptText(SAY_NEFARIAN_INTRO, pSummoned); + } + else + { + ++m_uiSpawnedAdds; + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (m_creature->GetMapId() != MAP_ID_BWL) + return; + + // If Nefarian has reached combat area, let him attack + if (pSummoned->GetEntry() == NPC_NEFARIAN && uiMotionType == POINT_MOTION_TYPE && uiPointId == 1) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) + { + if (m_creature->GetMapId() != MAP_ID_BWL) + return; + + // 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) + { + // Start combat after the dialogue is finished + if (iEntry == SPELL_SHADOWBLINK) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFactionTemporary(FACTION_BLACK_DRAGON, TEMPFACTION_RESTORE_REACH_HOME); + DoCastSpellIfCan(m_creature, SPELL_NEFARIUS_BARRIER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SHADOWBLINK_INTRO, CAST_TRIGGERED); + m_creature->SetInCombatWithZone(); + } + } + + void DoStartIntro() + { + StartNextDialogueText(SAY_GAMESBEGIN_1); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_creature->GetMapId() != MAP_ID_BWL) + return; + + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Only do this if we haven't spawned nef yet + if (m_uiSpawnedAdds < MAX_DRAKE_SUMMONS) + { + // Shadowbolt Timer + if (m_uiShadowBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOWBOLT) == CAST_OK) + m_uiShadowBoltTimer = urand(2000, 4000); + } + } + else + m_uiShadowBoltTimer -= uiDiff; + + // Fear Timer + if (m_uiFearTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = urand(10000, 20000); + } + } + else + m_uiFearTimer -= uiDiff; + + // Shadowbolt Volley + if (m_uiShadowboltVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOWBOLT_VOLLEY) == CAST_OK) + m_uiShadowboltVolleyTimer = urand(19000, 28000); + } + else + m_uiShadowboltVolleyTimer -= uiDiff; + + // Silence + if (m_uiSilenceTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = urand(14000, 23000); + } + } + else + m_uiSilenceTimer -= uiDiff; + + // Shadow Command + if (m_uiShadowCommandTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_COMMAND) == CAST_OK) + m_uiShadowCommandTimer = urand(24000, 30000); + } + } + else + m_uiShadowCommandTimer -= uiDiff; + + // ShadowBlink + if (m_uiShadowBlinkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOWBLINK) == CAST_OK) + m_uiShadowBlinkTimer = urand(30000, 40000); + } + else + m_uiShadowBlinkTimer -= uiDiff; + + // Add spawning mechanism + if (m_uiAddSpawnTimer < uiDiff) + { + // 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 : uint32(NPC_CHROMATIC_DRAKANOID); + m_creature->SummonCreature(uiCreatureId, aNefarianLocs[0].x, aNefarianLocs[0].y, aNefarianLocs[0].z, 5.000f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + + // 1 in 3 chance it will be a chromatic + uiCreatureId = urand(0, 2) ? m_uiDrakeTypeTwo : uint32(NPC_CHROMATIC_DRAKANOID); + m_creature->SummonCreature(uiCreatureId, aNefarianLocs[1].x, aNefarianLocs[1].y, aNefarianLocs[1].z, 5.000, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + + // Begin phase 2 by spawning Nefarian + if (m_uiSpawnedAdds >= MAX_DRAKE_SUMMONS) + { + // Inturrupt any spell casting + m_creature->InterruptNonMeleeSpells(false); + + // Make super invis + if (m_creature->GetVisibility() != VISIBILITY_OFF) + m_creature->SetVisibility(VISIBILITY_OFF); + + // Spawn Nefarian + // Summon as active, to be able to work proper! + m_creature->SummonCreature(NPC_NEFARIAN, aNefarianLocs[2].x, aNefarianLocs[2].y, aNefarianLocs[2].z, 0, TEMPSUMMON_DEAD_DESPAWN, 0, true); + } + + m_uiAddSpawnTimer = 4000; + } + else + m_uiAddSpawnTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_victor_nefarius(Creature* pCreature) +{ + return new boss_victor_nefariusAI(pCreature); +} + +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->SEND_GOSSIP_MENU(GOSSIP_TEXT_NEFARIUS_1, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_boss_victor_nefarius(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (pCreature->GetMapId() != MAP_ID_BWL) + return true; + + 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->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->SEND_GOSSIP_MENU(GOSSIP_TEXT_NEFARIUS_3, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + // Start the intro event + if (boss_victor_nefariusAI* pBossAI = dynamic_cast(pCreature->AI())) + pBossAI->DoStartIntro(); + break; + } + return true; +} + +void AddSC_boss_victor_nefarius() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_victor_nefarius"; + pNewScript->GetAI = &GetAI_boss_victor_nefarius; + pNewScript->pGossipHello = &GossipHello_boss_victor_nefarius; + pNewScript->pGossipSelect = &GossipSelect_boss_victor_nefarius; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/instance_blackwing_lair.cpp b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/instance_blackwing_lair.cpp new file mode 100644 index 0000000000..b8c3a3c61a --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/blackwing_lair/instance_blackwing_lair.cpp @@ -0,0 +1,380 @@ +/* Copyright (C) 2006 - 2013 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: Instance_Blackwing_Lair +SD%Complete: 90 +SDComment: +SDCategory: Blackwing Lair +EndScriptData */ + +#include "precompiled.h" +#include "blackwing_lair.h" + +instance_blackwing_lair::instance_blackwing_lair(Map* pMap) : ScriptedInstance(pMap), + m_uiResetTimer(0), + m_uiDefenseTimer(0) +{ + Initialize(); +} + +void instance_blackwing_lair::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +bool instance_blackwing_lair::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + return false; +} + +void instance_blackwing_lair::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_BLACKWING_TECHNICIAN: + // Sort creatures so we can get only the ones near Vaelastrasz + if (pCreature->IsWithinDist2d(aNefariusSpawnLoc[0], aNefariusSpawnLoc[1], 50.0f)) + m_lTechnicianGuids.push_back(pCreature->GetObjectGuid()); + break; + case NPC_MONSTER_GENERATOR: + 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: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} + +void instance_blackwing_lair::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_DOOR_RAZORGORE_ENTER: + case GO_ORB_OF_DOMINATION: + case GO_DOOR_NEFARIAN: + break; + case GO_DOOR_RAZORGORE_EXIT: + if (m_auiEncounter[TYPE_RAZORGORE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOOR_CHROMAGGUS_EXIT: + if (m_auiEncounter[TYPE_CHROMAGGUS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOOR_VAELASTRASZ: + if (m_auiEncounter[TYPE_VAELASTRASZ] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOOR_LASHLAYER: + if (m_auiEncounter[TYPE_LASHLAYER] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_BLACK_DRAGON_EGG: + m_lDragonEggsGuids.push_back(pGo->GetObjectGuid()); + return; + case GO_DRAKONID_BONES: + m_lDrakonidBonesGuids.push_back(pGo->GetObjectGuid()); + return; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_blackwing_lair::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_RAZORGORE: + m_auiEncounter[uiType] = uiData; + 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); + + // 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: + m_auiEncounter[uiType] = uiData; + // Prevent the players from running back to the first room; use if the encounter is not special + if (uiData != SPECIAL) + DoUseDoorOrButton(GO_DOOR_RAZORGORE_EXIT); + if (uiData == DONE) + DoUseDoorOrButton(GO_DOOR_VAELASTRASZ); + break; + case TYPE_LASHLAYER: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_DOOR_LASHLAYER); + break; + case TYPE_FIREMAW: + case TYPE_EBONROC: + case TYPE_FLAMEGOR: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_CHROMAGGUS: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + 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; + } + + 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +void instance_blackwing_lair::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] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; + + 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_blackwing_lair::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[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)) + pOrbTrigger->InterruptNonMeleeSpells(false); + } +} + +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); +} + +void AddSC_instance_blackwing_lair() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_blackwing_lair"; + pNewScript->GetInstanceData = &GetInstanceData_instance_blackwing_lair; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_baron_geddon.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_baron_geddon.cpp new file mode 100644 index 0000000000..81420728c9 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_baron_geddon.cpp @@ -0,0 +1,144 @@ +/* Copyright (C) 2006 - 2013 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_Geddon +SD%Complete: 100 +SDComment: Armaggedon is not working properly (core issue) +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + EMOTE_SERVICE = -1409000, + + SPELL_INFERNO = 19695, + SPELL_IGNITE_MANA = 19659, + SPELL_LIVING_BOMB = 20475, + SPELL_ARMAGEDDON = 20478 +}; + +struct MANGOS_DLL_DECL boss_baron_geddonAI : public ScriptedAI +{ + boss_baron_geddonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsArmageddon; + uint32 m_uiInfernoTimer; + uint32 m_uiIgniteManaTimer; + uint32 m_uiLivingBombTimer; + + void Reset() + { + m_bIsArmageddon = false; + m_uiInfernoTimer = 45000; + m_uiIgniteManaTimer = 30000; + m_uiLivingBombTimer = 35000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GEDDON, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GEDDON, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GEDDON, NOT_STARTED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bIsArmageddon) // Do nothing untill armageddon triggers + return; + + // If we are <2% hp cast Armageddom + if (m_creature->GetHealthPercent() <= 2.0f && !m_bIsArmageddon) + { + if (DoCastSpellIfCan(m_creature, SPELL_ARMAGEDDON, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(EMOTE_SERVICE, m_creature); + m_bIsArmageddon = true; + return; + } + } + + // Inferno_Timer + if (m_uiInfernoTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INFERNO) == CAST_OK) + m_uiInfernoTimer = 45000; + } + else + m_uiInfernoTimer -= uiDiff; + + // Ignite Mana Timer + if (m_uiIgniteManaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_IGNITE_MANA) == CAST_OK) + m_uiIgniteManaTimer = 30000; + } + else + m_uiIgniteManaTimer -= uiDiff; + + // Living Bomb Timer + if (m_uiLivingBombTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_LIVING_BOMB) == CAST_OK) + m_uiLivingBombTimer = 35000; + } + } + else + m_uiLivingBombTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_baron_geddon(Creature* pCreature) +{ + return new boss_baron_geddonAI(pCreature); +} + +void AddSC_boss_baron_geddon() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_baron_geddon"; + pNewScript->GetAI = &GetAI_boss_baron_geddon; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp new file mode 100644 index 0000000000..a9a184085a --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_garr.cpp @@ -0,0 +1,187 @@ +/* Copyright (C) 2006 - 2013 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_Garr +SD%Complete: 50 +SDComment: Garr's enrage is missing +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + // Garr spells + SPELL_ANTIMAGICPULSE = 19492, + SPELL_MAGMASHACKLES = 19496, + SPELL_ENRAGE = 19516, // TODO Stacking enrage (stacks to 10 times) + + // 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. +}; + +struct MANGOS_DLL_DECL boss_garrAI : public ScriptedAI +{ + boss_garrAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiAntiMagicPulseTimer; + uint32 m_uiMagmaShacklesTimer; + + void Reset() + { + m_uiAntiMagicPulseTimer = 25000; + m_uiMagmaShacklesTimer = 15000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GARR, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GARR, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GARR, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // AntiMagicPulse_Timer + if (m_uiAntiMagicPulseTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ANTIMAGICPULSE) == CAST_OK) + m_uiAntiMagicPulseTimer = urand(10000, 15000); + } + else + m_uiAntiMagicPulseTimer -= uiDiff; + + // MagmaShackles_Timer + if (m_uiMagmaShacklesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MAGMASHACKLES) == CAST_OK) + m_uiMagmaShacklesTimer = urand(8000, 12000); + } + else + m_uiMagmaShacklesTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI +{ + mob_fireswornAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiImmolateTimer; + uint32 m_uiSeparationCheckTimer; + + void Reset() + { + m_uiImmolateTimer = urand(4000, 8000); // These times are probably wrong + m_uiSeparationCheckTimer = 5000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Immolate_Timer + if (m_uiImmolateTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_IMMOLATE) == CAST_OK) + m_uiImmolateTimer = urand(5000, 10000); + } + } + else m_uiImmolateTimer -= uiDiff; + + if (m_uiSeparationCheckTimer < uiDiff) + { + // 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)) + DoCastSpellIfCan(m_creature, SPELL_SEPARATION_ANXIETY, CAST_TRIGGERED); + + m_uiSeparationCheckTimer = 5000; + } + else + m_uiSeparationCheckTimer -= uiDiff; + + // Cast Erruption and let them die + if (m_creature->GetHealthPercent() <= 10.0f) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_ERUPTION); + m_creature->SetDeathState(JUST_DIED); + m_creature->RemoveCorpse(); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_garr(Creature* pCreature) +{ + return new boss_garrAI(pCreature); +} + +CreatureAI* GetAI_mob_firesworn(Creature* pCreature) +{ + return new mob_fireswornAI(pCreature); +} + +void AddSC_boss_garr() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_garr"; + pNewScript->GetAI = &GetAI_boss_garr; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_firesworn"; + pNewScript->GetAI = &GetAI_mob_firesworn; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_gehennas.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_gehennas.cpp new file mode 100644 index 0000000000..730fd16d9c --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_gehennas.cpp @@ -0,0 +1,130 @@ +/* Copyright (C) 2006 - 2013 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_Gehennas +SD%Complete: 90 +SDComment: +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + SPELL_SHADOW_BOLT = 19728, // 19729 exists too, but can be reflected + SPELL_RAIN_OF_FIRE = 19717, + SPELL_GEHENNAS_CURSE = 19716 +}; + +struct MANGOS_DLL_DECL boss_gehennasAI : public ScriptedAI +{ + boss_gehennasAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShadowBoltTimer; + uint32 m_uiRainOfFireTimer; + uint32 m_uiGehennasCurseTimer; + + void Reset() + { + m_uiShadowBoltTimer = 6000; + m_uiRainOfFireTimer = 10000; + m_uiGehennasCurseTimer = 12000; + } + + void Aggro(Unit* /*pwho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GEHENNAS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GEHENNAS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GEHENNAS, FAIL); + } + + 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 + 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); + } + } + else + m_uiRainOfFireTimer -= uiDiff; + + // GehennasCurse Timer + if (m_uiGehennasCurseTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GEHENNAS_CURSE) == CAST_OK) + m_uiGehennasCurseTimer = 30000; + } + else + m_uiGehennasCurseTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_gehennas(Creature* pCreature) +{ + return new boss_gehennasAI(pCreature); +} + +void AddSC_boss_gehennas() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_gehennas"; + pNewScript->GetAI = &GetAI_boss_gehennas; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp similarity index 61% rename from scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp rename to scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp index 2c776fca8d..66f0a74811 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_golemagg.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Golemagg -SD%Complete: 75 -SDComment: Timers need to be confirmed, Golemagg's Trust need to be checked +SD%Complete: 80 +SDComment: Rager need to be tied to boss (Despawn on boss-death) SDCategory: Molten Core EndScriptData */ @@ -26,14 +26,14 @@ EndScriptData */ enum { - SPELL_MAGMASPLASH = 13879, + SPELL_MAGMA_SPLASH = 13879, SPELL_PYROBLAST = 20228, SPELL_EARTHQUAKE = 19798, SPELL_ENRAGE = 19953, SPELL_GOLEMAGG_TRUST = 20553, // Core Rager - EMOTE_LOWHP = -1409002, + EMOTE_LOW_HP = -1409002, SPELL_MANGLE = 19820 }; @@ -54,21 +54,33 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI void Reset() { - m_uiPyroblastTimer = 7*IN_MILLISECONDS; // These timers are probably wrong - m_uiEarthquakeTimer = 3*IN_MILLISECONDS; - m_uiBuffTimer = 2.5*IN_MILLISECONDS; + 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_MAGMASPLASH, true); + m_creature->CastSpell(m_creature, SPELL_MAGMA_SPLASH, true); } - void JustDied(Unit* pKiller) + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GOLEMAGG, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override { if (m_pInstance) m_pInstance->SetData(TYPE_GOLEMAGG, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GOLEMAGG, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -77,9 +89,10 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI if (m_uiPyroblastTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_PYROBLAST); - - m_uiPyroblastTimer = 7*IN_MILLISECONDS; + { + if (DoCastSpellIfCan(pTarget, SPELL_PYROBLAST) == CAST_OK) + m_uiPyroblastTimer = 7 * IN_MILLISECONDS; + } } else m_uiPyroblastTimer -= uiDiff; @@ -87,8 +100,8 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI // Enrage if (!m_bEnraged && m_creature->GetHealthPercent() < 10.0f) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - m_bEnraged = true; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bEnraged = true; } // Earthquake @@ -96,23 +109,21 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI { if (m_uiEarthquakeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_EARTHQUAKE); - m_uiEarthquakeTimer = 3*IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature, SPELL_EARTHQUAKE) == CAST_OK) + m_uiEarthquakeTimer = 3 * IN_MILLISECONDS; } else m_uiEarthquakeTimer -= uiDiff; } - /* // Golemagg's Trust if (m_uiBuffTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_GOLEMAGG_TRUST); - m_uiBuffTimer = 2.5*IN_MILLISECONDS; + m_uiBuffTimer = 1.5 * IN_MILLISECONDS; } else m_uiBuffTimer -= uiDiff; - */ DoMeleeAttackIfReady(); } @@ -131,30 +142,23 @@ struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI void Reset() { - 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) { - if (m_pInstance) + if (m_pInstance && m_pInstance->GetData(TYPE_GOLEMAGG) != DONE) { - if (Creature* pGolemagg = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_GOLEMAGG))) - { - if (pGolemagg->isAlive()) - { - DoScriptText(EMOTE_LOWHP, m_creature); - m_creature->SetHealth(m_creature->GetMaxHealth()); - } - else - uiDamage = m_creature->GetHealth(); - } + DoScriptText(EMOTE_LOW_HP, m_creature); + m_creature->SetHealth(m_creature->GetMaxHealth()); + uiDamage = 0; } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -162,8 +166,8 @@ struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI // Mangle if (m_uiMangleTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE); - m_uiMangleTimer = 10*IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE) == CAST_OK) + m_uiMangleTimer = 10 * IN_MILLISECONDS; } else m_uiMangleTimer -= uiDiff; @@ -184,15 +188,15 @@ CreatureAI* GetAI_mob_core_rager(Creature* pCreature) void AddSC_boss_golemagg() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_golemagg"; - newscript->GetAI = &GetAI_boss_golemagg; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_golemagg"; + pNewScript->GetAI = &GetAI_boss_golemagg; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_core_rager"; - newscript->GetAI = &GetAI_mob_core_rager; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_core_rager"; + pNewScript->GetAI = &GetAI_mob_core_rager; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_lucifron.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_lucifron.cpp new file mode 100644 index 0000000000..b8d56b7f22 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_lucifron.cpp @@ -0,0 +1,125 @@ +/* Copyright (C) 2006 - 2013 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_Lucifron +SD%Complete: 100 +SDComment: +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + SPELL_IMPENDINGDOOM = 19702, + SPELL_LUCIFRONCURSE = 19703, + SPELL_SHADOWSHOCK = 19460 +}; + +struct MANGOS_DLL_DECL boss_lucifronAI : public ScriptedAI +{ + boss_lucifronAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiImpendingDoomTimer; + uint32 m_uiLucifronCurseTimer; + uint32 m_uiShadowShockTimer; + + void Reset() + { + m_uiImpendingDoomTimer = 10000; + m_uiLucifronCurseTimer = 20000; + m_uiShadowShockTimer = 6000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LUCIFRON, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LUCIFRON, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LUCIFRON, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Impending doom timer + if (m_uiImpendingDoomTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_IMPENDINGDOOM) == CAST_OK) + m_uiImpendingDoomTimer = 20000; + } + else + m_uiImpendingDoomTimer -= uiDiff; + + // Lucifron's curse timer + if (m_uiLucifronCurseTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LUCIFRONCURSE) == CAST_OK) + m_uiLucifronCurseTimer = 20000; + } + else + m_uiLucifronCurseTimer -= uiDiff; + + // Shadowshock + if (m_uiShadowShockTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOWSHOCK) == CAST_OK) + m_uiShadowShockTimer = 6000; + } + } + else + m_uiShadowShockTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_lucifron(Creature* pCreature) +{ + return new boss_lucifronAI(pCreature); +} + +void AddSC_boss_lucifron() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lucifron"; + pNewScript->GetAI = &GetAI_boss_lucifron; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_magmadar.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_magmadar.cpp new file mode 100644 index 0000000000..4637dc3042 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_magmadar.cpp @@ -0,0 +1,134 @@ +/* Copyright (C) 2006 - 2013 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_Magmadar +SD%Complete: 75 +SDComment: Lavabomb needs still core support +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + EMOTE_GENERIC_FRENZY_KILL = -1000001, + + SPELL_FRENZY = 19451, + SPELL_MAGMASPIT = 19449, // This is actually a buff he gives himself + SPELL_PANIC = 19408, + SPELL_LAVABOMB = 19411, // This calls a dummy server side effect that isn't implemented yet + SPELL_LAVABOMB_ALT = 19428 +}; + +struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI +{ + boss_magmadarAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiFrenzyTimer; + uint32 m_uiPanicTimer; + uint32 m_uiLavabombTimer; + + void Reset() + { + m_uiFrenzyTimer = 30000; + m_uiPanicTimer = 7000; + m_uiLavabombTimer = 12000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_MAGMASPIT, true); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MAGMADAR, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MAGMADAR, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MAGMADAR, NOT_STARTED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Frenzy_Timer + 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; + + // Panic_Timer + if (m_uiPanicTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PANIC) == CAST_OK) + m_uiPanicTimer = 30000; + } + else + m_uiPanicTimer -= uiDiff; + + // Lavabomb_Timer + if (m_uiLavabombTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_LAVABOMB) == CAST_OK) + m_uiLavabombTimer = 12000; + } + } + else + m_uiLavabombTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_magmadar(Creature* pCreature) +{ + return new boss_magmadarAI(pCreature); +} + +void AddSC_boss_magmadar() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_magmadar"; + pNewScript->GetAI = &GetAI_boss_magmadar; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_majordomo_executus.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_majordomo_executus.cpp new file mode 100644 index 0000000000..2e00bdba3e --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_majordomo_executus.cpp @@ -0,0 +1,478 @@ +/* Copyright (C) 2006 - 2013 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_Majordomo_Executus +SD%Complete: 95 +SDComment: Minor weaknesses +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" +#include "TemporarySummon.h" + +enum +{ + SAY_AGGRO = -1409003, + SAY_SLAY = -1409005, + SAY_SPECIAL = -1409006, // Use unknown + SAY_LAST_ADD = -1409019, // When only one add remaining + SAY_DEFEAT_1 = -1409007, + SAY_DEFEAT_2 = -1409020, + SAY_DEFEAT_3 = -1409021, + + SAY_SUMMON_0 = -1409023, + SAY_SUMMON_1 = -1409024, + SAY_SUMMON_MAJ = -1409008, + SAY_ARRIVAL1_RAG = -1409009, + SAY_ARRIVAL2_MAJ = -1409010, + SAY_ARRIVAL3_RAG = -1409011, + SAY_ARRIVAL4_MAJ = -1409022, + + GOSSIP_ITEM_SUMMON_1 = -3409000, + GOSSIP_ITEM_SUMMON_2 = -3409001, + GOSSIP_ITEM_SUMMON_3 = -3409002, + + TEXT_ID_SUMMON_1 = 4995, + TEXT_ID_SUMMON_2 = 5011, + TEXT_ID_SUMMON_3 = 5012, + + SPELL_MAGIC_REFLECTION = 20619, + SPELL_DAMAGE_REFLECTION = 21075, + SPELL_BLASTWAVE = 20229, + SPELL_AEGIS = 20620, + SPELL_TELEPORT = 20618, + + SPELL_TELEPORT_SELF = 19484, + SPELL_SUMMON_RAGNAROS = 19774, + SPELL_ELEMENTAL_FIRE = 19773, + SPELL_RAGNA_EMERGE = 20568, +}; + +struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI +{ + boss_majordomoAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_molten_core*)pCreature->GetInstanceData(); + m_bHasEncounterFinished = false; + Reset(); + } + + instance_molten_core* m_pInstance; + + uint32 m_uiMagicReflectionTimer; + uint32 m_uiDamageReflectionTimer; + uint32 m_uiBlastwaveTimer; + uint32 m_uiTeleportTimer; + uint32 m_uiAegisTimer; + uint32 m_uiSpeechTimer; + + ObjectGuid m_ragnarosGuid; + bool m_bHasEncounterFinished; + uint8 m_uiAddsKilled; + uint8 m_uiSpeech; + GuidList m_luiMajordomoAddsGUIDs; + + void Reset() + { + m_uiMagicReflectionTimer = 30000; // Damage reflection first so we alternate + m_uiDamageReflectionTimer = 15000; + m_uiBlastwaveTimer = 10000; + m_uiTeleportTimer = 20000; + m_uiAegisTimer = 5000; + m_uiSpeechTimer = 1000; + + m_uiAddsKilled = 0; + m_uiSpeech = 0; + } + + void KilledUnit(Unit* pVictim) override + { + if (urand(0, 4)) + return; + + DoScriptText(SAY_SLAY, m_creature); + } + + void Aggro(Unit* pWho) + { + if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_RAGNAROS) + return; + + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MAJORDOMO, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (!m_bHasEncounterFinished) // Normal reached home, FAIL + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MAJORDOMO, FAIL); + } + else // Finished the encounter, DONE + { + // Exit combat + 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->SetFactionTemporary(FACTION_MAJORDOMO_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + + // Reset orientation + m_creature->SetFacingTo(m_aMajordomoLocations[0].m_fO); + + // Start his speech + m_uiSpeechTimer = 1; // At next tick + m_uiSpeech = 1; + + m_pInstance->SetData(TYPE_MAJORDOMO, DONE); + } + } + + void StartSummonEvent(Player* pPlayer) + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + // Prevent possible exploits with double summoning + if (m_creature->GetMap()->GetCreature(m_ragnarosGuid)) + return; + + DoScriptText(SAY_SUMMON_0, m_creature, pPlayer); + + m_uiSpeechTimer = 5000; + m_uiSpeech = 10; + } + + void JustRespawned() override + { + // Encounter finished, need special treatment + if (m_bHasEncounterFinished) + { + // This needs to be set to be able to resummon Ragnaros + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + // Relocate here + debug_log("SD2: boss_majordomo_executus: Relocate to Ragnaros' Lair on respawn"); + m_creature->GetMap()->CreatureRelocation(m_creature, m_aMajordomoLocations[1].m_fX, m_aMajordomoLocations[1].m_fY, m_aMajordomoLocations[1].m_fZ, m_aMajordomoLocations[1].m_fO); + m_creature->SetActiveObjectState(false); + } + } + + 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); + } + else if (pSummoned->GetEntry() == NPC_RAGNAROS) + { + m_ragnarosGuid = pSummoned->GetObjectGuid(); + pSummoned->CastSpell(pSummoned, SPELL_RAGNA_EMERGE, false); + } + } + + void JustDied(Unit* pKiller) override + { + if (pKiller->GetTypeId() == TYPEID_UNIT && pKiller->GetEntry() == NPC_RAGNAROS) + DoScriptText(SAY_ARRIVAL4_MAJ, m_creature); + } + + void CorpseRemoved(uint32& uiRespawnDelay) override + { + uiRespawnDelay = urand(2 * HOUR, 3 * HOUR); + + if (m_bHasEncounterFinished) + { + // Needed for proper respawn handling + debug_log("SD2: boss_majordomo_executus: Set active"); + m_creature->SetActiveObjectState(true); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) + { + if (pSummoned->GetEntry() == NPC_FLAMEWAKER_HEALER || pSummoned->GetEntry() == NPC_FLAMEWAKER_ELITE) + { + m_uiAddsKilled += 1; + + // Yell if only one Add alive + if (m_uiAddsKilled == m_luiMajordomoAddsGUIDs.size() - 1) + DoScriptText(SAY_LAST_ADD, m_creature); + + // All adds are killed, retreat + else if (m_uiAddsKilled == m_luiMajordomoAddsGUIDs.size()) + { + m_bHasEncounterFinished = true; + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + } + } + + // Unsummon Majordomo adds + void UnsummonMajordomoAdds() + { + for (GuidList::const_iterator itr = m_luiMajordomoAddsGUIDs.begin(); itr != m_luiMajordomoAddsGUIDs.end(); ++itr) + { + if (Creature* pAdd = m_creature->GetMap()->GetCreature(*itr)) + if (pAdd->IsTemporarySummon()) + ((TemporarySummon*)pAdd)->UnSummon(); + } + + m_luiMajordomoAddsGUIDs.clear(); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + { + uiDamage = 0; + DoCastSpellIfCan(m_creature, SPELL_AEGIS, CAST_TRIGGERED); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Handling of his combat-end speech and Ragnaros summoning + if (m_uiSpeech) + { + if (m_uiSpeechTimer < uiDiff) + { + switch (m_uiSpeech) + { + // Majordomo retreat event + case 1: + DoScriptText(SAY_DEFEAT_1, m_creature); + m_uiSpeechTimer = 7500; + ++m_uiSpeech; + break; + case 2: + DoScriptText(SAY_DEFEAT_2, m_creature); + m_uiSpeechTimer = 8000; + ++m_uiSpeech; + break; + case 3: + DoScriptText(SAY_DEFEAT_3, m_creature); + m_uiSpeechTimer = 21500; + ++m_uiSpeech; + break; + case 4: + DoCastSpellIfCan(m_creature, SPELL_TELEPORT_SELF); + // TODO - when should they be unsummoned? + // TODO - also unclear how this should be handled, as of range issues + m_uiSpeechTimer = 900; + ++m_uiSpeech; + break; + case 5: + // Majordomo is away now, remove his adds + UnsummonMajordomoAdds(); + m_uiSpeech = 0; + break; + + // Ragnaros Summon Event + case 10: + DoScriptText(SAY_SUMMON_1, m_creature); + ++m_uiSpeech; + m_uiSpeechTimer = 1000; + break; + case 11: + DoCastSpellIfCan(m_creature, SPELL_SUMMON_RAGNAROS); + // TODO - Move along, this expects to be handled with mmaps + m_creature->GetMotionMaster()->MovePoint(1, 831.079590f, -816.023193f, -229.023270f); + ++m_uiSpeech; + m_uiSpeechTimer = 7000; + break; + case 12: + // Reset orientation + if (GameObject* pLavaSteam = m_pInstance->GetSingleGameObjectFromStorage(GO_LAVA_STEAM)) + m_creature->SetFacingToObject(pLavaSteam); + m_uiSpeechTimer = 4500; + ++m_uiSpeech; + break; + case 13: + DoScriptText(SAY_SUMMON_MAJ, m_creature); + ++m_uiSpeech; + m_uiSpeechTimer = 8000; + break; + case 14: + // 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_uiSpeech; + m_uiSpeechTimer = 8700; + break; + case 15: + if (Creature* pRagnaros = m_creature->GetMap()->GetCreature(m_ragnarosGuid)) + DoScriptText(SAY_ARRIVAL1_RAG, pRagnaros); + ++m_uiSpeech; + m_uiSpeechTimer = 11700; + break; + case 16: + DoScriptText(SAY_ARRIVAL2_MAJ, m_creature); + ++m_uiSpeech; + m_uiSpeechTimer = 8700; + break; + case 17: + if (Creature* pRagnaros = m_creature->GetMap()->GetCreature(m_ragnarosGuid)) + DoScriptText(SAY_ARRIVAL3_RAG, pRagnaros); + ++m_uiSpeech; + m_uiSpeechTimer = 16500; + break; + case 18: + if (Creature* pRagnaros = m_creature->GetMap()->GetCreature(m_ragnarosGuid)) + pRagnaros->CastSpell(m_creature, SPELL_ELEMENTAL_FIRE, false); + // Rest of summoning speech is handled by Ragnaros, as Majordomo will be dead + m_uiSpeech = 0; + break; + } + } + else + m_uiSpeechTimer -= uiDiff; + } + + // When encounter finished, no need to do anything anymore (important for moving home after victory) + if (m_bHasEncounterFinished) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Cast Ageis to heal self + if (m_uiAegisTimer <= uiDiff) + m_uiAegisTimer = 0; + else + m_uiAegisTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 90.0f && !m_uiAegisTimer) + { + DoCastSpellIfCan(m_creature, SPELL_AEGIS); + m_uiAegisTimer = 10000; + } + + // Magic Reflection Timer + if (m_uiMagicReflectionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MAGIC_REFLECTION) == CAST_OK) + m_uiMagicReflectionTimer = 30000; + } + else + m_uiMagicReflectionTimer -= uiDiff; + + // Damage Reflection Timer + if (m_uiDamageReflectionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DAMAGE_REFLECTION) == CAST_OK) + m_uiDamageReflectionTimer = 30000; + } + else + m_uiDamageReflectionTimer -= uiDiff; + + // Teleports the target to the heated rock in the center of the area + if (m_uiTeleportTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_TELEPORT) == CAST_OK) + m_uiTeleportTimer = 20000; + } + } + else + m_uiTeleportTimer -= uiDiff; + + // Blastwave Timer + if (m_uiBlastwaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLASTWAVE) == CAST_OK) + m_uiBlastwaveTimer = 10000; + } + else + m_uiBlastwaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_majordomo(Creature* pCreature) +{ + return new boss_majordomoAI(pCreature); +} + +bool GossipHello_boss_majordomo(Player* pPlayer, Creature* pCreature) +{ + if (instance_molten_core* pInstance = (instance_molten_core*)pCreature->GetInstanceData()) + { + 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->SEND_GOSSIP_MENU(TEXT_ID_SUMMON_1, pCreature->GetObjectGuid()); + } + } + return true; +} + +bool GossipSelect_boss_majordomo(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_SUMMON_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SUMMON_2, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SUMMON_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SUMMON_3, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF + 3: + pPlayer->CLOSE_GOSSIP_MENU(); + if (boss_majordomoAI* pMajoAI = dynamic_cast(pCreature->AI())) + pMajoAI->StartSummonEvent(pPlayer); + break; + } + + return true; +} + +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; + + pCreatureTarget->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pCreatureTarget->NearTeleportTo(m_aMajordomoLocations[1].m_fX, m_aMajordomoLocations[1].m_fY, m_aMajordomoLocations[1].m_fZ, m_aMajordomoLocations[1].m_fO, true); + // TODO - some visibility update? + return true; +} + +void AddSC_boss_majordomo() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_majordomo"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_boss_majordomo; + pNewScript->pGossipHello = &GossipHello_boss_majordomo; + pNewScript->pGossipSelect = &GossipSelect_boss_majordomo; + pNewScript->GetAI = &GetAI_boss_majordomo; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_ragnaros.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_ragnaros.cpp new file mode 100644 index 0000000000..878a36b886 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_ragnaros.cpp @@ -0,0 +1,343 @@ +/* Copyright (C) 2006 - 2013 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_Ragnaros +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 */ + +#include "precompiled.h" +#include "molten_core.h" + +/* There have been quite some bugs about his spells, keep this as reference untill all finished + * Missing features (based on wowwiki) + * Lava Burst - this spell is handled by Go 178088 which is summoned by spells 21886, 21900 - 21907 + */ + +enum +{ + SAY_ARRIVAL5_RAG = -1409012, + SAY_REINFORCEMENTS_1 = -1409013, + SAY_REINFORCEMENTS_2 = -1409014, + SAY_HAMMER = -1409015, + SAY_WRATH = -1409016, + SAY_KILL = -1409017, + SAY_MAGMABURST = -1409018, + + SPELL_WRATH_OF_RAGNAROS = 20566, + SPELL_ELEMENTAL_FIRE = 20564, + SPELL_MAGMA_BLAST = 20565, // Ranged attack if nobody is in melee range + SPELL_MELT_WEAPON = 21387, + SPELL_RAGNA_SUBMERGE = 21107, // Stealth aura + SPELL_RAGNA_EMERGE = 20568, // Emerge from lava + SPELL_ELEMENTAL_FIRE_KILL = 19773, + SPELL_MIGHT_OF_RAGNAROS = 21154, + SPELL_INTENSE_HEAT = 21155, + + MAX_ADDS_IN_SUBMERGE = 8, + NPC_SON_OF_FLAME = 12143, + NPC_FLAME_OF_RAGNAROS = 13148, +}; + +struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI +{ + boss_ragnarosAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_molten_core*)pCreature->GetInstanceData(); + m_uiEnterCombatTimer = 0; + m_bHasAggroYelled = false; + Reset(); + } + + instance_molten_core* m_pInstance; + + uint32 m_uiEnterCombatTimer; + uint32 m_uiWrathOfRagnarosTimer; + uint32 m_uiHammerTimer; + uint32 m_uiMagmaBlastTimer; + uint32 m_uiElementalFireTimer; + uint32 m_uiSubmergeTimer; + uint32 m_uiAttackTimer; + uint32 m_uiAddCount; + + bool m_bHasAggroYelled; + bool m_bHasYelledMagmaBurst; + bool m_bHasSubmergedOnce; + bool m_bIsSubmerged; + + void Reset() + { + 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_uiAddCount = 0; + + m_bHasYelledMagmaBurst = false; + m_bHasSubmergedOnce = false; + m_bIsSubmerged = false; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 3)) + return; + + DoScriptText(SAY_KILL, m_creature); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_RAGNAROS, DONE); + } + + void Aggro(Unit* pWho) + { + 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() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_RAGNAROS, FAIL); + + // Reset flag if had been submerged + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + ScriptedAI::EnterEvadeMode(); + } + + void SummonedCreatureJustDied(Creature* pSummmoned) + { + // If all Sons of Flame are dead, trigger emerge + if (pSummmoned->GetEntry() == NPC_SON_OF_FLAME) + { + m_uiAddCount--; + + // If last add killed then emerge soonish + if (m_uiAddCount == 0) + m_uiAttackTimer = std::min(m_uiAttackTimer, (uint32)1000); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SON_OF_FLAME) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + ++m_uiAddCount; + } + else if (pSummoned->GetEntry() == NPC_FLAME_OF_RAGNAROS) + pSummoned->CastSpell(pSummoned, SPELL_INTENSE_HEAT, true, NULL, NULL, m_creature->GetObjectGuid()); + } + + 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) override + { + if (m_uiEnterCombatTimer) + { + if (m_uiEnterCombatTimer <= uiDiff) + { + if (!m_bHasAggroYelled) + { + m_uiEnterCombatTimer = 3000; + m_bHasAggroYelled = true; + DoScriptText(SAY_ARRIVAL5_RAG, m_creature); + } + else + { + m_uiEnterCombatTimer = 0; + // If we don't remove this passive flag, he will be unattackable after evading, this way he will enter combat + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + if (m_pInstance) + { + if (Player* pPlayer = m_pInstance->GetPlayerInMap(true, false)) + { + m_creature->AI()->AttackStart(pPlayer); + return; + } + } + } + } + else + m_uiEnterCombatTimer -= uiDiff; + } + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bIsSubmerged) + { + // Timer to check when Ragnaros should emerge (is set to soonish, when last add is killed) + if (m_uiAttackTimer < uiDiff) + { + // 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_uiMagmaBlastTimer = 3000; // Delay the magma blast after emerge + m_bIsSubmerged = false; + } + else + m_uiAttackTimer -= uiDiff; + + // Do nothing while submerged + return; + } + + // Wrath Of Ragnaros Timer + if (m_uiWrathOfRagnarosTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WRATH_OF_RAGNAROS) == CAST_OK) + { + DoScriptText(SAY_WRATH, m_creature); + m_uiWrathOfRagnarosTimer = 30000; + } + } + else + m_uiWrathOfRagnarosTimer -= uiDiff; + + // Elemental Fire Timer + if (m_uiElementalFireTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ELEMENTAL_FIRE) == CAST_OK) + m_uiElementalFireTimer = urand(10000, 14000); + } + else + m_uiElementalFireTimer -= uiDiff; + + // Hammer of Ragnaros + if (m_uiHammerTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MIGHT_OF_RAGNAROS, SELECT_FLAG_POWER_MANA)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MIGHT_OF_RAGNAROS) == CAST_OK) + { + DoScriptText(SAY_HAMMER, m_creature); + m_uiHammerTimer = 11000; + } + } + else + m_uiHammerTimer = 11000; + } + else + m_uiHammerTimer -= uiDiff; + + // Submerge Timer + if (m_uiSubmergeTimer < uiDiff) + { + // Submerge and attack again after 90 secs + DoCastSpellIfCan(m_creature, SPELL_RAGNA_SUBMERGE, CAST_INTERRUPT_PREVIOUS); + m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); + m_bIsSubmerged = true; + 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; + + // Summon 8 elementals at random points around the boss + float fX, fY, fZ; + 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_OOC_DESPAWN, 1000); + } + + return; + } + else + m_uiSubmergeTimer -= uiDiff; + + // TODO this actually should select _any_ enemy in melee range, not only the tank + // Range check for melee target, if nobody is found in range, then cast magma blast on random + // If we are within range melee the target + if (m_creature->IsNonMeleeSpellCasted(false) || !m_creature->getVictim()) + return; + + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + { + // Make sure our attack is ready + if (m_creature->isAttackReady()) + { + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + m_bHasYelledMagmaBurst = false; + } + } + else + { + // Magma Burst Timer + if (m_uiMagmaBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MAGMA_BLAST) == CAST_OK) + { + if (!m_bHasYelledMagmaBurst) + { + DoScriptText(SAY_MAGMABURST, m_creature); + m_bHasYelledMagmaBurst = true; + } + m_uiMagmaBlastTimer = 1000; // Spamm this! + } + } + } + else + m_uiMagmaBlastTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_ragnaros(Creature* pCreature) +{ + return new boss_ragnarosAI(pCreature); +} + +void AddSC_boss_ragnaros() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ragnaros"; + pNewScript->GetAI = &GetAI_boss_ragnaros; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_shazzrah.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_shazzrah.cpp new file mode 100644 index 0000000000..9695907d22 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_shazzrah.cpp @@ -0,0 +1,156 @@ +/* Copyright (C) 2006 - 2013 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_Shazzrah +SD%Complete: 75 +SDComment: Teleport NYI (need core support, remove hack here when implemented) +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + SPELL_ARCANE_EXPLOSION = 19712, + SPELL_SHAZZRAH_CURSE = 19713, + SPELL_MAGIC_GROUNDING = 19714, + SPELL_COUNTERSPELL = 19715, + SPELL_GATE_OF_SHAZZRAH = 23138 // effect spell: 23139 +}; + +struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI +{ + boss_shazzrahAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiArcaneExplosionTimer; + uint32 m_uiShazzrahCurseTimer; + uint32 m_uiMagicGroundingTimer; + uint32 m_uiCounterspellTimer; + uint32 m_uiBlinkTimer; + + void Reset() + { + m_uiArcaneExplosionTimer = 6000; + m_uiShazzrahCurseTimer = 10000; + m_uiMagicGroundingTimer = 24000; + m_uiCounterspellTimer = 15000; + m_uiBlinkTimer = 30000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SHAZZRAH, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SHAZZRAH, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SHAZZRAH, NOT_STARTED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Arcane Explosion Timer + if (m_uiArcaneExplosionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = urand(5000, 9000); + } + else + m_uiArcaneExplosionTimer -= uiDiff; + + // Shazzrah Curse Timer + if (m_uiShazzrahCurseTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHAZZRAH_CURSE) == CAST_OK) + m_uiShazzrahCurseTimer = 20000; + } + else + m_uiShazzrahCurseTimer -= uiDiff; + + // Magic Grounding Timer + if (m_uiMagicGroundingTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MAGIC_GROUNDING) == CAST_OK) + m_uiMagicGroundingTimer = 35000; + } + else + m_uiMagicGroundingTimer -= uiDiff; + + // Counterspell Timer + if (m_uiCounterspellTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_COUNTERSPELL) == CAST_OK) + m_uiCounterspellTimer = urand(16000, 20000); + } + else + m_uiCounterspellTimer -= uiDiff; + + // Blink Timer + if (m_uiBlinkTimer < uiDiff) + { + // Teleporting him to a random gamer and casting Arcane Explosion after that. + if (DoCastSpellIfCan(m_creature, SPELL_GATE_OF_SHAZZRAH) == CAST_OK) + { + // manual, until added effect of dummy properly -- TODO REMOVE HACK + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->NearTeleportTo(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_creature->GetOrientation()); + DoResetThreat(); + + DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION, CAST_TRIGGERED); + + m_uiBlinkTimer = 45000; + } + } + else + m_uiBlinkTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_shazzrah(Creature* pCreature) +{ + return new boss_shazzrahAI(pCreature); +} + +void AddSC_boss_shazzrah() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_shazzrah"; + pNewScript->GetAI = &GetAI_boss_shazzrah; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_sulfuron_harbinger.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_sulfuron_harbinger.cpp new file mode 100644 index 0000000000..2dcfb65b30 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/boss_sulfuron_harbinger.cpp @@ -0,0 +1,242 @@ +/* Copyright (C) 2006 - 2013 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_Sulfuron_Harbringer +SD%Complete: 80 +SDComment: Spells Dark strike and Flamespear need confirmation +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +enum +{ + SPELL_DARK_STRIKE = 19777, // Wowhead Linked to add - need confirmation! + SPELL_DEMORALIZING_SHOUT = 19778, + SPELL_INSPIRE = 19779, + SPELL_HAND_OF_RAGNAROS = 19780, + SPELL_FLAMESPEAR = 19781, + + // Adds Spells + SPELL_HEAL = 19775, + SPELL_SHADOWWORD_PAIN = 19776, + SPELL_IMMOLATE = 20294 +}; + +struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI +{ + boss_sulfuronAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiDarkstrikeTimer; + uint32 m_uiDemoralizingShoutTimer; + uint32 m_uiInspireTimer; + uint32 m_uiKnockdownTimer; + uint32 m_uiFlamespearTimer; + + void Reset() + { + m_uiDarkstrikeTimer = 10000; + m_uiDemoralizingShoutTimer = 15000; + m_uiInspireTimer = 3000; + m_uiKnockdownTimer = 6000; + m_uiFlamespearTimer = 2000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SULFURON, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SULFURON, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SULFURON, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Demoralizing Shout Timer + if (m_uiDemoralizingShoutTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEMORALIZING_SHOUT) == CAST_OK) + m_uiDemoralizingShoutTimer = urand(15000, 20000); + } + else + m_uiDemoralizingShoutTimer -= uiDiff; + + // Inspire Timer + if (m_uiInspireTimer < uiDiff) + { + Creature* pTarget = NULL; + std::list pList = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE); + if (!pList.empty()) + { + std::list::iterator i = pList.begin(); + advance(i, (rand() % pList.size())); + pTarget = (*i); + } + + if (!pTarget) + pTarget = m_creature; + + if (DoCastSpellIfCan(pTarget, SPELL_INSPIRE) == CAST_OK) + m_uiInspireTimer = 10000; + } + else + m_uiInspireTimer -= uiDiff; + + // Hand of Ragnaros Timer + if (m_uiKnockdownTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HAND_OF_RAGNAROS) == CAST_OK) + m_uiKnockdownTimer = urand(12000, 15000); + } + else + m_uiKnockdownTimer -= uiDiff; + + // Flamespear Timer + if (m_uiFlamespearTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FLAMESPEAR) == CAST_OK) + m_uiFlamespearTimer = urand(12000, 16000); + } + } + else + m_uiFlamespearTimer -= uiDiff; + + // Dark Strike Timer + if (m_uiDarkstrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_STRIKE) == CAST_OK) + m_uiDarkstrikeTimer = urand(15000, 18000); + } + else + m_uiDarkstrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL mob_flamewaker_priestAI : public ScriptedAI +{ + mob_flamewaker_priestAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + uint32 m_uiHealTimer; + uint32 m_uiShadowWordPainTimer; + uint32 m_uiImmolateTimer; + + ScriptedInstance* m_pInstance; + + void Reset() + { + m_uiHealTimer = urand(15000, 30000); + m_uiShadowWordPainTimer = 2000; + m_uiImmolateTimer = 8000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Casting Heal to Sulfuron or other Guards. + if (m_uiHealTimer < uiDiff) + { + if (Unit* pUnit = DoSelectLowestHpFriendly(60.0f, 1)) + { + if (DoCastSpellIfCan(pUnit, SPELL_HEAL) == CAST_OK) + m_uiHealTimer = urand(15000, 20000); + } + } + else + m_uiHealTimer -= uiDiff; + + // ShadowWord Pain Timer + if (m_uiShadowWordPainTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOWWORD_PAIN) == CAST_OK) + m_uiShadowWordPainTimer = urand(18000, 26000); + } + } + else + m_uiShadowWordPainTimer -= uiDiff; + + // Immolate Timer + if (m_uiImmolateTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_IMMOLATE) == CAST_OK) + m_uiImmolateTimer = urand(15000, 25000); + } + } + else + m_uiImmolateTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_sulfuron(Creature* pCreature) +{ + return new boss_sulfuronAI(pCreature); +} + +CreatureAI* GetAI_mob_flamewaker_priest(Creature* pCreature) +{ + return new mob_flamewaker_priestAI(pCreature); +} + +void AddSC_boss_sulfuron() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_sulfuron"; + pNewScript->GetAI = &GetAI_boss_sulfuron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_flamewaker_priest"; + pNewScript->GetAI = &GetAI_mob_flamewaker_priest; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/instance_molten_core.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/instance_molten_core.cpp new file mode 100644 index 0000000000..72f6f03bf1 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/instance_molten_core.cpp @@ -0,0 +1,253 @@ +/* Copyright (C) 2006 - 2013 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: Instance_Molten_Core +SD%Complete: 25 +SDComment: Majordomos and Ragnaros Event missing +SDCategory: Molten Core +EndScriptData */ + +#include "precompiled.h" +#include "molten_core.h" + +instance_molten_core::instance_molten_core(Map* pMap) : ScriptedInstance(pMap) +{ + Initialize(); +} + +void instance_molten_core::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +bool instance_molten_core::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + + return false; +} + +void instance_molten_core::OnPlayerEnter(Player* /*pPlayer*/) +{ + // Summon Majordomo if can + DoSpawnMajordomoIfCan(true); +} + +void instance_molten_core::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + // Bosses + case NPC_GARR: + case NPC_SULFURON: + case NPC_MAJORDOMO: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} + +void instance_molten_core::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + // Runes + case GO_RUNE_KRESS: + case GO_RUNE_MOHN: + case GO_RUNE_BLAZ: + case GO_RUNE_MAZJ: + case GO_RUNE_ZETH: + case GO_RUNE_THERI: + case GO_RUNE_KORO: + + // Majordomo event chest + case GO_CACHE_OF_THE_FIRE_LORD: + // Ragnaros GOs + case GO_LAVA_STEAM: + case GO_LAVA_SPLASH: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + } +} + +void instance_molten_core::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_LUCIFRON: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_MAGMADAR: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_KRESS); + break; + case TYPE_GEHENNAS: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_MOHN); + break; + case TYPE_GARR: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_BLAZ); + break; + case TYPE_SHAZZRAH: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_MAZJ); + break; + case TYPE_GEDDON: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_ZETH); + break; + case TYPE_GOLEMAGG: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_THERI); + break; + case TYPE_SULFURON: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_RUNE_KORO); + break; + case TYPE_MAJORDOMO: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoRespawnGameObject(GO_CACHE_OF_THE_FIRE_LORD, HOUR); + break; + case TYPE_RAGNAROS: + m_auiEncounter[uiType] = uiData; + break; + } + + // Check if Majordomo can be summoned + if (uiData == DONE) + DoSpawnMajordomoIfCan(false); + + 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_molten_core::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +// Handle Majordomo summon here +void instance_molten_core::DoSpawnMajordomoIfCan(bool bByPlayerEnter) +{ + // If both Majordomo and Ragnaros events are finished, return + if (m_auiEncounter[TYPE_MAJORDOMO] == DONE && m_auiEncounter[TYPE_RAGNAROS] == DONE) + return; + + // If already spawned return + if (GetSingleCreatureFromStorage(NPC_MAJORDOMO, true)) + return; + + // Check if all rune bosses are done + for (uint8 i = TYPE_MAGMADAR; i < TYPE_MAJORDOMO; ++i) + { + if (m_auiEncounter[i] != DONE) + return; + } + + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + // 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 (uiSummonPos) // Majordomo encounter already done, set faction + { + 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); + } + else // Else yell and summon adds + { + if (!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); + } + } +} + +void instance_molten_core::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] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9]; + + 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* GetInstance_instance_molten_core(Map* pMap) +{ + return new instance_molten_core(pMap); +} + +void AddSC_instance_molten_core() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_molten_core"; + pNewScript->GetInstanceData = &GetInstance_instance_molten_core; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/molten_core/molten_core.cpp b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/molten_core.cpp similarity index 91% rename from scripts/eastern_kingdoms/molten_core/molten_core.cpp rename to scripts/eastern_kingdoms/blackrock_mountain/molten_core/molten_core.cpp index 819f9b5e03..293595284f 100644 --- a/scripts/eastern_kingdoms/molten_core/molten_core.cpp +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/molten_core.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 diff --git a/scripts/eastern_kingdoms/blackrock_mountain/molten_core/molten_core.h b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/molten_core.h new file mode 100644 index 0000000000..667f946d49 --- /dev/null +++ b/scripts/eastern_kingdoms/blackrock_mountain/molten_core/molten_core.h @@ -0,0 +1,104 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MOLTEN_CORE_H +#define DEF_MOLTEN_CORE_H + +enum +{ + MAX_ENCOUNTER = 10, + + TYPE_LUCIFRON = 0, + TYPE_MAGMADAR = 1, + TYPE_GEHENNAS = 2, + TYPE_GARR = 3, + TYPE_SHAZZRAH = 4, + TYPE_GEDDON = 5, + TYPE_GOLEMAGG = 6, + TYPE_SULFURON = 7, + TYPE_MAJORDOMO = 8, + TYPE_RAGNAROS = 9, + + NPC_LUCIFRON = 12118, + NPC_MAGMADAR = 11982, + NPC_GEHENNAS = 12259, + NPC_GARR = 12057, + NPC_SHAZZRAH = 12264, + NPC_GEDDON = 12056, + NPC_GOLEMAGG = 11988, + NPC_SULFURON = 12098, + NPC_MAJORDOMO = 12018, + NPC_RAGNAROS = 11502, + + // Adds + // Used for respawn in case of wipe + NPC_FLAMEWAKER_PROTECTOR = 12119, // Lucifron + NPC_FLAMEWAKER = 11661, // Gehennas + NPC_FIRESWORN = 12099, // Garr + NPC_CORE_RAGER = 11672, // Golemagg + NPC_FLAMEWAKER_PRIEST = 11662, // Sulfuron + NPC_FLAMEWAKER_HEALER = 11663, // Majordomo + NPC_FLAMEWAKER_ELITE = 11664, // Majordomo + + GO_LAVA_STEAM = 178107, + GO_LAVA_SPLASH = 178108, + GO_CACHE_OF_THE_FIRE_LORD = 179703, + GO_RUNE_KRESS = 176956, // Magmadar + GO_RUNE_MOHN = 176957, // Gehennas + GO_RUNE_BLAZ = 176955, // Garr + GO_RUNE_MAZJ = 176953, // Shazzah + GO_RUNE_ZETH = 176952, // Geddon + GO_RUNE_THERI = 176954, // Golemagg + GO_RUNE_KORO = 176951, // Sulfuron + + MAX_MAJORDOMO_ADDS = 8, + FACTION_MAJORDOMO_FRIENDLY = 1080, + SAY_MAJORDOMO_SPAWN = -1409004, +}; + +static SPAWNLOCATION 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 SPAWNLOCATION 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) +}; + +class MANGOS_DLL_DECL instance_molten_core : public ScriptedInstance +{ + public: + instance_molten_core(Map* pMap); + ~instance_molten_core() {} + + void Initialize() override; + bool IsEncounterInProgress() const 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; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + protected: + void DoSpawnMajordomoIfCan(bool bByPlayerEnter); + + std::string m_strInstData; + uint32 m_auiEncounter[MAX_ENCOUNTER]; +}; + +#endif diff --git a/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h b/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h deleted file mode 100644 index d17773837b..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_BLACKROCK_SPIRE_H -#define DEF_BLACKROCK_SPIRE_H - -enum -{ - MAX_ENCOUNTER = 5, - MAX_ROOMS = 7, - - TYPE_ROOM_EVENT = 1, - TYPE_EMBERSEER = 2, - TYPE_FLAMEWREATH = 3, // Only summon once per instance - TYPE_GYTH = 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_BLACKHAND_INCANCERATOR = 10316, - NPC_LORD_VICTOR_NEFARIUS = 10162, - NPC_GYTH = 10339, - - // Doors - GO_EMBERSEER_IN = 175244, - GO_DOORS = 175705, - GO_EMBERSEER_OUT = 175153, - GO_GYTH_ENTRY_DOOR = 164726, - GO_GYTH_COMBAT_DOOR = 175185, // control in boss_script, because will auto-close after each wave - GO_GYTH_EXIT_DOOR = 175186, - - - GO_ROOM_7_RUNE = 175194, - GO_ROOM_3_RUNE = 175195, - GO_ROOM_6_RUNE = 175196, - GO_ROOM_1_RUNE = 175197, - GO_ROOM_5_RUNE = 175198, - GO_ROOM_2_RUNE = 175199, - GO_ROOM_4_RUNE = 175200, - - GO_ROOKERY_EGG = 175124, -}; - -class MANGOS_DLL_DECL instance_blackrock_spire : public ScriptedInstance -{ - public: - instance_blackrock_spire(Map* pMap); - ~instance_blackrock_spire() {} - - void Initialize(); - - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); - - void SetData(uint32 uiType, uint32 uiData); - void SetData64(uint32 uiType, uint64 uiData); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiType); - - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); - - void DoSortRoomEventMobs(); - void GetIncanceratorGUIDList(std::list &lList) { lList = m_lIncanceratorGUIDList; } - void GetRookeryEggGUIDList(std::list &lList) { lList = m_lRookeryEggGUIDList; } - - protected: - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiEmberseerGUID; - uint64 m_uiNefariusGUID; - uint64 m_uiGythGUID; - uint64 m_uiInfiltratorGUID; - - uint64 m_uiEmberseerInDoorGUID; - uint64 m_uiEmberseerCombatDoorGUID; - uint64 m_uiEmberseerOutDoorGUID; - uint64 m_uiGythEntryDoorGUID; - uint64 m_uiGythCombatDoorGUID; - uint64 m_uiGythExitDoorGUID; - - uint64 m_auiRoomRuneGUID[MAX_ROOMS]; - std::list m_alRoomEventMobGUIDSorted[MAX_ROOMS]; - std::list m_lRoomEventMobGUIDList; - std::list m_lIncanceratorGUIDList; - std::list m_lRookeryEggGUIDList; -}; - -#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 ba1c633765..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (C) 2006 - 2010 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()->GetGUID()); - 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* newscript; - newscript = new Script; - newscript->Name = "boss_drakkisath"; - newscript->GetAI = &GetAI_boss_drakkisath; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp deleted file mode 100644 index d5a32be712..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Gyth -SD%Complete: 100 -SDComment: Whole Event needs some rewrite -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" -#include "blackrock_spire.h" - -enum -{ - SPELL_CORROSIVEACID = 20667, - SPELL_FREEZE = 16350, // ID was wrong! - SPELL_FLAMEBREATH = 20712, - SPELL_ROOT_SELF = 33356, - - MODEL_ID_INVISIBLE = 11686, - MODEL_ID_GYTH_MOUNTED = 9723, - MODEL_ID_GYTH = 9806, - - NPC_FIRE_TONGUE = 10372, - NPC_CHROMATIC_WHELP = 10442, - NPC_CHROMATIC_DRAGON = 10447, - NPC_BLACKHAND_ELITE = 10317, - NPC_REND_BLACKHAND = 10429 -}; - -struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI -{ - boss_gythAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (instance_blackrock_spire*) pCreature->GetInstanceData(); - Reset(); - } - - instance_blackrock_spire* m_pInstance; - uint64 m_uiCombatDoorGUID; - uint32 uiAggroTimer; - uint32 uiDragonsTimer; - uint32 uiOrcTimer; - uint32 uiCorrosiveAcidTimer; - uint32 uiFreezeTimer; - uint32 uiFlamebreathTimer; - uint32 uiLine1Count; - uint32 uiLine2Count; - - bool m_bSummonedRend; - bool m_bAggro; - bool m_bRootSelf; - - void Reset() - { - uiDragonsTimer = 3000; - uiOrcTimer = 60000; - uiAggroTimer = 60000; - uiCorrosiveAcidTimer = 8000; - uiFreezeTimer = 11000; - uiFlamebreathTimer = 4000; - m_bSummonedRend = false; - m_bAggro = false; - m_bRootSelf = false; - - // how many times should the two lines of summoned creatures be spawned - // min 2 x 2, max 7 lines of attack in total - uiLine1Count = urand(2, 5); - uiLine2Count = urand(2, 7 - uiLine1Count); - - // Invisible for event start - m_creature->SetDisplayId(MODEL_ID_INVISIBLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void Aggro(Unit* pWho) - { - if (m_pInstance) - { - m_pInstance->SetData(TYPE_GYTH, IN_PROGRESS); - m_uiCombatDoorGUID = m_pInstance->GetData64(GO_GYTH_COMBAT_DOOR); - } - } - - void JustDied(Unit* pKiller) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_GYTH, DONE); - } - - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_GYTH, FAIL); - } - - void SummonCreatureWithRandomTarget(uint32 uiCreatureId) - { - float fX, fY, fZ; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 2*INTERACTION_DISTANCE, fX, fY, fZ); - fX = std::min(m_creature->GetPositionX(), fX); // Halfcircle - suits better the rectangular form - if (Creature* pSummoned = m_creature->SummonCreature(uiCreatureId, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 240000)) - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (!m_bRootSelf) - { - DoCastSpellIfCan(m_creature, SPELL_ROOT_SELF); - m_bRootSelf = true; - } - - if (!m_bAggro && uiLine1Count == 0 && uiLine2Count == 0) - { - if (uiAggroTimer < uiDiff) - { - m_bAggro = true; - // Visible now! - m_creature->SetDisplayId(MODEL_ID_GYTH_MOUNTED); - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveAurasDueToSpell(SPELL_ROOT_SELF); - if (m_pInstance) - m_pInstance->DoUseDoorOrButton(m_uiCombatDoorGUID); - - } - else - uiAggroTimer -= uiDiff; - } - - // Summon Dragon pack. 2 Dragons and 3 Whelps - if (!m_bAggro && !m_bSummonedRend && uiLine1Count > 0) - { - if (uiDragonsTimer < uiDiff) - { - SummonCreatureWithRandomTarget(NPC_FIRE_TONGUE); - SummonCreatureWithRandomTarget(NPC_FIRE_TONGUE); - SummonCreatureWithRandomTarget(NPC_CHROMATIC_WHELP); - SummonCreatureWithRandomTarget(NPC_CHROMATIC_WHELP); - SummonCreatureWithRandomTarget(NPC_CHROMATIC_WHELP); - --uiLine1Count; - if (m_pInstance) - m_pInstance->DoUseDoorOrButton(m_uiCombatDoorGUID); - uiDragonsTimer = 60000; - } - else - uiDragonsTimer -= uiDiff; - } - - //Summon Orc pack. 1 Orc Handler 1 Elite Dragonkin and 3 Whelps - if (!m_bAggro && !m_bSummonedRend && uiLine1Count == 0 && uiLine2Count > 0) - { - if (uiOrcTimer < uiDiff) - { - SummonCreatureWithRandomTarget(NPC_CHROMATIC_DRAGON); - SummonCreatureWithRandomTarget(NPC_BLACKHAND_ELITE); - SummonCreatureWithRandomTarget(NPC_CHROMATIC_WHELP); - SummonCreatureWithRandomTarget(NPC_CHROMATIC_WHELP); - SummonCreatureWithRandomTarget(NPC_CHROMATIC_WHELP); - if (m_pInstance) - m_pInstance->DoUseDoorOrButton(m_uiCombatDoorGUID); - --uiLine2Count; - uiOrcTimer = 60000; - } - else - uiOrcTimer -= uiDiff; - } - - // we take part in the fight - if (m_bAggro) - { - // CorrosiveAcid_Timer - if (uiCorrosiveAcidTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_CORROSIVEACID); - uiCorrosiveAcidTimer = 7000; - } - else - uiCorrosiveAcidTimer -= uiDiff; - - // Freeze_Timer - if (uiFreezeTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_FREEZE) == CAST_OK) - uiFreezeTimer = 16000; - } - else - uiFreezeTimer -= uiDiff; - - // Flamebreath_Timer - if (uiFlamebreathTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAMEBREATH); - uiFlamebreathTimer = 10500; - } - else - uiFlamebreathTimer -= uiDiff; - - //Summon Rend - if (!m_bSummonedRend && m_creature->GetHealthPercent() < 11.0f) - { - // summon Rend and Change model to normal Gyth - // Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - // Gyth model - m_creature->SetDisplayId(MODEL_ID_GYTH); - m_creature->SummonCreature(NPC_REND_BLACKHAND, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000); - m_bSummonedRend = true; - } - - DoMeleeAttackIfReady(); - } // end if Aggro - } -}; - -CreatureAI* GetAI_boss_gyth(Creature* pCreature) -{ - return new boss_gythAI(pCreature); -} - -void AddSC_boss_gyth() -{ - Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "boss_gyth"; - pNewScript->GetAI = &GetAI_boss_gyth; - pNewScript->RegisterSelf(); -} 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 bf6208f8b4..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_halycon"; - newscript->GetAI = &GetAI_boss_halycon; - newscript->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 3dff5dd2d2..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright (C) 2006 - 2010 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* newscript; - newscript = new Script; - newscript->Name = "boss_highlord_omokk"; - newscript->GetAI = &GetAI_boss_highlordomokk; - newscript->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 9501d026e5..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2006 - 2010 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* newscript; - newscript = new Script; - newscript->Name = "boss_mother_smolderweb"; - newscript->GetAI = &GetAI_boss_mothersmolderweb; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp deleted file mode 100644 index 57733d06f7..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Pyroguard_Emberseer -SD%Complete: 100 -SDComment: Event to activate Emberseer NYI - 'aggro'-text missing -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" -#include "blackrock_spire.h" - -enum -{ - SPELL_FIRENOVA = 23462, - SPELL_FLAMEBUFFET = 23341, - SPELL_PYROBLAST = 20228 // guesswork, but best fitting in spells-area, was 17274 (has mana cost) -}; - -struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI -{ - boss_pyroguard_emberseerAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (instance_blackrock_spire*) pCreature->GetInstanceData(); - Reset(); - } - - instance_blackrock_spire* m_pInstance; - uint32 m_uiFireNovaTimer; - uint32 m_uiFlameBuffetTimer; - uint32 m_uiPyroBlastTimer; - - void Reset() - { - m_uiFireNovaTimer = 6000; - m_uiFlameBuffetTimer = 3000; - m_uiPyroBlastTimer = 14000; - } - - void Aggro(Unit* pWho) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_EMBERSEER, IN_PROGRESS); - } - - void JustDied(Unit* pKiller) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_EMBERSEER, DONE); - } - - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_EMBERSEER, FAIL); - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // FireNova Timer - if (m_uiFireNovaTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FIRENOVA); - m_uiFireNovaTimer = 6000; - } - else - m_uiFireNovaTimer -= uiDiff; - - // FlameBuffet Timer - if (m_uiFlameBuffetTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAMEBUFFET); - m_uiFlameBuffetTimer = 14000; - } - else - m_uiFlameBuffetTimer -= uiDiff; - - // PyroBlast Timer - if (m_uiPyroBlastTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_PYROBLAST); - m_uiPyroBlastTimer = 15000; - } - else - m_uiPyroBlastTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_pyroguard_emberseer(Creature* pCreature) -{ - return new boss_pyroguard_emberseerAI(pCreature); -} - -void AddSC_boss_pyroguard_emberseer() -{ - Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "boss_pyroguard_emberseer"; - pNewScript->GetAI = &GetAI_boss_pyroguard_emberseer; - pNewScript->RegisterSelf(); -} 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 09e1d1f4a2..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2006 - 2010 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* newscript; - newscript = new Script; - newscript->Name = "quartermaster_zigris"; - newscript->GetAI = &GetAI_boss_quatermasterzigris; - newscript->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 daab7235bc..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (C) 2006 - 2010 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* newscript; - newscript = new Script; - newscript->Name = "boss_rend_blackhand"; - newscript->GetAI = &GetAI_boss_rend_blackhand; - newscript->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 168ccdee5e..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (C) 2006 - 2010 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* newscript; - newscript = new Script; - newscript->Name = "boss_shadow_hunter_voshgajin"; - newscript->GetAI = &GetAI_boss_shadowvosh; - newscript->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 54106ab31c..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 2006 - 2010 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* newscript; - newscript = new Script; - newscript->Name = "boss_the_beast"; - newscript->GetAI = &GetAI_boss_thebeast; - newscript->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 0864098ca7..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_warmaster_voone"; - newscript->GetAI = &GetAI_boss_warmastervoone; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp b/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp deleted file mode 100644 index ce0435d66a..0000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: instance_blackrock_spire -SD%Complete: 50 -SDComment: To really get this instance working, many encounters will need more love - and also the DB content is surely not yet perfect. -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" -#include "blackrock_spire.h" - -enum -{ - AREATRIGGER_ENTER_UBRS = 2046, - AREATRIGGER_STADIUM = 2026 -}; - -/* Areatrigger -1470 Instance Entry -1628 LBRS, between Spiders and Ogres -1946 LBRS, ubrs pre-quest giver (1) -1986 LBRS, ubrs pre-quest giver (2) -1987 LBRS, ubrs pre-quest giver (3) -2026 UBRS, stadium event trigger -2046 UBRS, way to upper -2066 UBRS, The Beast - Exit (to the dark chamber) -2067 UBRS, The Beast - Entry -2068 LBRS, fall out of map -3726 UBRS, entrance to BWL -*/ - -instance_blackrock_spire::instance_blackrock_spire(Map* pMap) : ScriptedInstance(pMap), - m_uiEmberseerGUID(0), - m_uiNefariusGUID(0), - m_uiGythGUID(0), - m_uiInfiltratorGUID(0), - - m_uiEmberseerInDoorGUID(0), - m_uiEmberseerCombatDoorGUID(0), - m_uiEmberseerOutDoorGUID(0), - - m_uiGythEntryDoorGUID(0), - m_uiGythCombatDoorGUID(0), - m_uiGythExitDoorGUID(0) -{ - Initialize(); -} - -void instance_blackrock_spire::Initialize() -{ - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_auiRoomRuneGUID, 0, sizeof(m_auiRoomRuneGUID)); -} - -void instance_blackrock_spire::OnObjectCreate(GameObject* pGo) -{ - switch(pGo->GetEntry()) - { - case GO_EMBERSEER_IN: - m_uiEmberseerInDoorGUID = pGo->GetGUID(); - if (GetData(TYPE_ROOM_EVENT) == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_DOORS: - m_uiEmberseerCombatDoorGUID = pGo->GetGUID(); - break; - case GO_EMBERSEER_OUT: - m_uiEmberseerOutDoorGUID = pGo->GetGUID(); - if (GetData(TYPE_EMBERSEER) == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_GYTH_ENTRY_DOOR: - m_uiGythEntryDoorGUID = pGo->GetGUID(); - break; - case GO_GYTH_COMBAT_DOOR: - m_uiGythCombatDoorGUID = pGo->GetGUID(); - break; - case GO_GYTH_EXIT_DOOR: - m_uiGythExitDoorGUID = pGo->GetGUID(); - if (GetData(TYPE_GYTH) == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - - case GO_ROOM_1_RUNE: m_auiRoomRuneGUID[0] = pGo->GetGUID(); break; - case GO_ROOM_2_RUNE: m_auiRoomRuneGUID[1] = pGo->GetGUID(); break; - case GO_ROOM_3_RUNE: m_auiRoomRuneGUID[2] = pGo->GetGUID(); break; - case GO_ROOM_4_RUNE: m_auiRoomRuneGUID[3] = pGo->GetGUID(); break; - case GO_ROOM_5_RUNE: m_auiRoomRuneGUID[4] = pGo->GetGUID(); break; - case GO_ROOM_6_RUNE: m_auiRoomRuneGUID[5] = pGo->GetGUID(); break; - case GO_ROOM_7_RUNE: m_auiRoomRuneGUID[6] = pGo->GetGUID(); break; - - case GO_ROOKERY_EGG: m_lRookeryEggGUIDList.push_back(pGo->GetGUID()); break; - } -} - -void instance_blackrock_spire::OnCreatureCreate(Creature* pCreature) -{ - switch(pCreature->GetEntry()) - { - case NPC_PYROGUARD_EMBERSEER: m_uiEmberseerGUID = pCreature->GetEntry(); break; - case NPC_LORD_VICTOR_NEFARIUS: m_uiNefariusGUID = pCreature->GetGUID(); break; - case NPC_GYTH: m_uiGythGUID = pCreature->GetGUID(); break; - case NPC_SCARSHIELD_INFILTRATOR: m_uiInfiltratorGUID = pCreature->GetGUID(); break; - - case NPC_BLACKHAND_SUMMONER: - case NPC_BLACKHAND_VETERAN: m_lRoomEventMobGUIDList.push_back(pCreature->GetGUID()); break; - case NPC_BLACKHAND_INCANCERATOR: m_lIncanceratorGUIDList.push_back(pCreature->GetGUID()); break; - } -} - -void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) -{ - switch(uiType) - { - case TYPE_ROOM_EVENT: - if (uiData == DONE) - DoUseDoorOrButton(m_uiEmberseerInDoorGUID); - m_auiEncounter[0] = uiData; - break; - case TYPE_EMBERSEER: - if (uiData == IN_PROGRESS || uiData == FAIL) - DoUseDoorOrButton(m_uiEmberseerCombatDoorGUID); - else if (uiData == DONE) - { - DoUseDoorOrButton(m_uiEmberseerCombatDoorGUID); - DoUseDoorOrButton(m_uiEmberseerOutDoorGUID); - } - m_auiEncounter[1] = uiData; - break; - case TYPE_FLAMEWREATH: - m_auiEncounter[2] = uiData; - break; - case TYPE_GYTH: - if (uiData == IN_PROGRESS || uiData == FAIL) - DoUseDoorOrButton(m_uiGythEntryDoorGUID); - else if (uiData == DONE) - { - DoUseDoorOrButton(m_uiGythEntryDoorGUID); - DoUseDoorOrButton(m_uiGythExitDoorGUID); - } - m_auiEncounter[3] = uiData; - break; - case TYPE_VALTHALAK: - m_auiEncounter[4] = 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]; - - strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } -} - -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_auiRoomRuneGUID[i]) // This check is used, to ensure which runes still need processing - { - m_alRoomEventMobGUIDSorted[i].remove(uiData); - if (m_alRoomEventMobGUIDSorted[i].empty()) - { - DoUseDoorOrButton(m_auiRoomRuneGUID[i]); - m_auiRoomRuneGUID[i] = 0; - } - else - uiNotEmptyRoomsCount++; // found an not empty room - } - } - if (!uiNotEmptyRoomsCount) - SetData(TYPE_ROOM_EVENT, DONE); - } -} - -void instance_blackrock_spire::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; -} - -uint32 instance_blackrock_spire::GetData(uint32 uiType) -{ - 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_GYTH: return m_auiEncounter[3]; - case TYPE_VALTHALAK: return m_auiEncounter[4]; - } - return 0; -} - -uint64 instance_blackrock_spire::GetData64(uint32 uiType) -{ - switch (uiType) - { - case NPC_PYROGUARD_EMBERSEER: return m_uiEmberseerGUID; - case NPC_LORD_VICTOR_NEFARIUS: return m_uiNefariusGUID; - case NPC_GYTH: return m_uiGythGUID; - case NPC_SCARSHIELD_INFILTRATOR: return m_uiInfiltratorGUID; - case GO_GYTH_COMBAT_DOOR: return m_uiGythCombatDoorGUID; - } - return 0; -} - -void instance_blackrock_spire::DoSortRoomEventMobs() -{ - if (GetData(TYPE_ROOM_EVENT) != NOT_STARTED) - return; - for (uint8 i = 0; i < MAX_ROOMS; i++) - if (GameObject* pRune = instance->GetGameObject(m_auiRoomRuneGUID[i])) - for (std::list::const_iterator itr = m_lRoomEventMobGUIDList.begin(); itr != m_lRoomEventMobGUIDList.end(); itr++) - if (Creature* pCreature = instance->GetCreature(*itr)) - if (pCreature->isAlive() && pCreature->GetDistance(pRune) < 10.0f) - m_alRoomEventMobGUIDSorted[i].push_back(*itr); - - SetData(TYPE_ROOM_EVENT, IN_PROGRESS); -} - -InstanceData* GetInstanceData_instance_blackrock_spire(Map* pMap) -{ - return new instance_blackrock_spire(pMap); -} - -bool AreaTrigger_at_blackrock_spire(Player* pPlayer, AreaTriggerEntry const* pAt) -{ - if (pPlayer->isDead()) - return false; - - switch (pAt->id) - { - case AREATRIGGER_ENTER_UBRS: - if (instance_blackrock_spire* pInstance = (instance_blackrock_spire*) pPlayer->GetInstanceData()) - pInstance->DoSortRoomEventMobs(); - break; - case AREATRIGGER_STADIUM: - if (instance_blackrock_spire* pInstance = (instance_blackrock_spire*) pPlayer->GetInstanceData()) - if (Creature* pGyth = pInstance->instance->GetCreature(pInstance->GetData64(NPC_GYTH))) - if (pGyth->isAlive() && !pGyth->isInCombat()) - pGyth->AI()->AttackStart(pPlayer); - break; - } - return false; -} - -void AddSC_instance_blackrock_spire() -{ - Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "instance_blackrock_spire"; - pNewScript->GetInstanceData = &GetInstanceData_instance_blackrock_spire; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_blackrock_spire"; - pNewScript->pAreaTrigger = &AreaTrigger_at_blackrock_spire; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp deleted file mode 100644 index 27635ab091..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Broodlord_Lashlayer -SD%Complete: 100 -SDComment: -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO -1469000 -#define SAY_LEASH -1469001 - -#define SPELL_CLEAVE 26350 -#define SPELL_BLASTWAVE 23331 -#define SPELL_MORTALSTRIKE 24573 -#define SPELL_KNOCKBACK 25778 - -struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI -{ - boss_broodlordAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Cleave_Timer; - uint32 BlastWave_Timer; - uint32 MortalStrike_Timer; - uint32 KnockBack_Timer; - - void Reset() - { - Cleave_Timer = 8000; //These times are probably wrong - BlastWave_Timer = 12000; - MortalStrike_Timer = 20000; - KnockBack_Timer = 30000; - } - - void Aggro(Unit* pWho) - { - DoScriptText(SAY_AGGRO, m_creature); - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - // BlastWave - if (BlastWave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BLASTWAVE); - BlastWave_Timer = urand(8000, 16000); - }else BlastWave_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = urand(25000, 35000); - }else MortalStrike_Timer -= diff; - - if (KnockBack_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKBACK); - //Drop 50% aggro - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); - - KnockBack_Timer = urand(15000, 30000); - }else KnockBack_Timer -= diff; - - DoMeleeAttackIfReady(); - - if (EnterEvadeIfOutOfCombatArea(diff)) - DoScriptText(SAY_LEASH, m_creature); - } -}; -CreatureAI* GetAI_boss_broodlord(Creature* pCreature) -{ - return new boss_broodlordAI(pCreature); -} - -void AddSC_boss_broodlord() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_broodlord"; - newscript->GetAI = &GetAI_boss_broodlord; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp deleted file mode 100644 index 003d135524..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Chromaggus -SD%Complete: 95 -SDComment: Chromatic Mutation disabled due to lack of core support -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -enum -{ - EMOTE_GENERIC_FRENZY_KILL = -1000001, - EMOTE_SHIMMER = -1469003, - - //These spells are actually called elemental shield - //What they do is decrease all damage by 75% then they increase - //One school of damage by 1100% - SPELL_FIRE_VURNALBILTY = 22277, - SPELL_FROST_VURNALBILTY = 22278, - SPELL_SHADOW_VURNALBILTY = 22279, - SPELL_NATURE_VURNALBILTY = 22280, - SPELL_ARCANE_VURNALBILTY = 22281, - - SPELL_INCINERATE = 23308, //Incinerate 23308,23309 - SPELL_TIMELAPSE = 23310, //Time lapse 23310, 23311(old threat mod that was removed in 2.01) - SPELL_CORROSIVEACID = 23313, //Corrosive Acid 23313, 23314 - SPELL_IGNITEFLESH = 23315, //Ignite Flesh 23315,23316 - SPELL_FROSTBURN = 23187, //Frost burn 23187, 23189 - - //Brood Affliction 23173 - Scripted Spell that cycles through all targets within 100 yards and has a chance to cast one of the afflictions on them - //Since Scripted spells arn't coded I'll just write a function that does the same thing - SPELL_BROODAF_BLUE = 23153, //Blue affliction 23153 - SPELL_BROODAF_BLACK = 23154, //Black affliction 23154 - SPELL_BROODAF_RED = 23155, //Red affliction 23155 (23168 on death) - SPELL_BROODAF_BRONZE = 23170, //Bronze Affliction 23170 - SPELL_BROODAF_GREEN = 23169, //Brood Affliction Green 23169 - - SPELL_CHROMATIC_MUT_1 = 23174, //Spell cast on player if they get all 5 debuffs - - SPELL_FRENZY = 28371, //The frenzy spell may be wrong - SPELL_ENRAGE = 28747 -}; - -struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI -{ - boss_chromaggusAI(Creature* pCreature) : ScriptedAI(pCreature) - { - //Select the 2 breaths that we are going to use until despawned - //5 possiblities for the first breath, 4 for the second, 20 total possiblites - //This way we don't end up casting 2 of the same breath - //TL TL would be stupid - srand(time(NULL)); - switch(urand(0, 19)) - { - //B1 - Incin - case 0: - Breath1_Spell = SPELL_INCINERATE; - Breath2_Spell = SPELL_TIMELAPSE; - break; - case 1: - Breath1_Spell = SPELL_INCINERATE; - Breath2_Spell = SPELL_CORROSIVEACID; - break; - case 2: - Breath1_Spell = SPELL_INCINERATE; - Breath2_Spell = SPELL_IGNITEFLESH; - break; - case 3: - Breath1_Spell = SPELL_INCINERATE; - Breath2_Spell = SPELL_FROSTBURN; - break; - - //B1 - TL - case 4: - Breath1_Spell = SPELL_TIMELAPSE; - Breath2_Spell = SPELL_INCINERATE; - break; - case 5: - Breath1_Spell = SPELL_TIMELAPSE; - Breath2_Spell = SPELL_CORROSIVEACID; - break; - case 6: - Breath1_Spell = SPELL_TIMELAPSE; - Breath2_Spell = SPELL_IGNITEFLESH; - break; - case 7: - Breath1_Spell = SPELL_TIMELAPSE; - Breath2_Spell = SPELL_FROSTBURN; - break; - - //B1 - Acid - case 8: - Breath1_Spell = SPELL_CORROSIVEACID; - Breath2_Spell = SPELL_INCINERATE; - break; - case 9: - Breath1_Spell = SPELL_CORROSIVEACID; - Breath2_Spell = SPELL_TIMELAPSE; - break; - case 10: - Breath1_Spell = SPELL_CORROSIVEACID; - Breath2_Spell = SPELL_IGNITEFLESH; - break; - case 11: - Breath1_Spell = SPELL_CORROSIVEACID; - Breath2_Spell = SPELL_FROSTBURN; - break; - - //B1 - Ignite - case 12: - Breath1_Spell = SPELL_IGNITEFLESH; - Breath2_Spell = SPELL_INCINERATE; - break; - case 13: - Breath1_Spell = SPELL_IGNITEFLESH; - Breath2_Spell = SPELL_CORROSIVEACID; - break; - case 14: - Breath1_Spell = SPELL_IGNITEFLESH; - Breath2_Spell = SPELL_TIMELAPSE; - break; - case 15: - Breath1_Spell = SPELL_IGNITEFLESH; - Breath2_Spell = SPELL_FROSTBURN; - break; - - //B1 - Frost - case 16: - Breath1_Spell = SPELL_FROSTBURN; - Breath2_Spell = SPELL_INCINERATE; - break; - case 17: - Breath1_Spell = SPELL_FROSTBURN; - Breath2_Spell = SPELL_TIMELAPSE; - break; - case 18: - Breath1_Spell = SPELL_FROSTBURN; - Breath2_Spell = SPELL_CORROSIVEACID; - break; - case 19: - Breath1_Spell = SPELL_FROSTBURN; - Breath2_Spell = SPELL_IGNITEFLESH; - break; - }; - - EnterEvadeMode(); - } - - uint32 Breath1_Spell; - uint32 Breath2_Spell; - uint32 CurrentVurln_Spell; - - uint32 Shimmer_Timer; - uint32 Breath1_Timer; - uint32 Breath2_Timer; - uint32 Affliction_Timer; - uint32 Frenzy_Timer; - bool Enraged; - - void Reset() - { - CurrentVurln_Spell = 0; //We use this to store our last vurlnability spell so we can remove it later - - Shimmer_Timer = 0; //Time till we change vurlnerabilites - Breath1_Timer = 30000; //First breath is 30 seconds - Breath2_Timer = 60000; //Second is 1 minute so that we can alternate - Affliction_Timer = 10000; //This is special - 5 seconds means that we cast this on 1 pPlayer every 5 sconds - Frenzy_Timer = 15000; - - Enraged = false; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Shimmer_Timer Timer - if (Shimmer_Timer < diff) - { - //Remove old vurlnability spell - if (CurrentVurln_Spell) - m_creature->RemoveAurasDueToSpell(CurrentVurln_Spell); - - //Cast new random vurlnabilty on self - uint32 spell; - switch(urand(0, 4)) - { - case 0: spell = SPELL_FIRE_VURNALBILTY; break; - case 1: spell = SPELL_FROST_VURNALBILTY; break; - case 2: spell = SPELL_SHADOW_VURNALBILTY; break; - case 3: spell = SPELL_NATURE_VURNALBILTY; break; - case 4: spell = SPELL_ARCANE_VURNALBILTY; break; - } - - if (DoCastSpellIfCan(m_creature, spell) == CAST_OK) - { - CurrentVurln_Spell = spell; - - DoScriptText(EMOTE_SHIMMER, m_creature); - Shimmer_Timer = 45000; - } - }else Shimmer_Timer -= diff; - - //Breath1_Timer - if (Breath1_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),Breath1_Spell); - Breath1_Timer = 60000; - }else Breath1_Timer -= diff; - - //Breath2_Timer - if (Breath2_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),Breath2_Spell); - Breath2_Timer = 60000; - }else Breath2_Timer -= diff; - - //Affliction_Timer - if (Affliction_Timer < diff) - { - uint32 SpellAfflict = 0; - - switch(urand(0, 4)) - { - case 0: SpellAfflict = SPELL_BROODAF_BLUE; break; - case 1: SpellAfflict = SPELL_BROODAF_BLACK; break; - case 2: SpellAfflict = SPELL_BROODAF_RED; break; - case 3: SpellAfflict = SPELL_BROODAF_BRONZE; break; - case 4: SpellAfflict = SPELL_BROODAF_GREEN; break; - } - - 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) - { - //Cast affliction - DoCastSpellIfCan(pUnit, SpellAfflict, CAST_TRIGGERED); - - //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)) - { - //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 - //So instead we instant kill our target - - //WORKAROUND - if (pUnit->GetTypeId() == TYPEID_PLAYER) - pUnit->CastSpell(pUnit, 5, false); - } - } - } - - Affliction_Timer = 10000; - }else Affliction_Timer -= diff; - - //Frenzy_Timer - if (Frenzy_Timer < diff) - { - if (DoCastSpellIfCan(m_creature,SPELL_FRENZY) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - Frenzy_Timer = urand(10000, 15000); - } - }else Frenzy_Timer -= diff; - - //Enrage if not already enraged and below 20% - if (!Enraged && m_creature->GetHealthPercent() < 20.0f) - { - DoCastSpellIfCan(m_creature,SPELL_ENRAGE); - Enraged = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_chromaggus(Creature* pCreature) -{ - return new boss_chromaggusAI(pCreature); -} - -void AddSC_boss_chromaggus() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_chromaggus"; - newscript->GetAI = &GetAI_boss_chromaggus; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp deleted file mode 100644 index 3395a7d928..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Ebonroc -SD%Complete: 50 -SDComment: Shadow of Ebonroc needs core support -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWFLAME 22539 -#define SPELL_WINGBUFFET 18500 -#define SPELL_SHADOWOFEBONROC 23340 -#define SPELL_HEAL 41386 //Thea Heal spell of his Shadow - -struct MANGOS_DLL_DECL boss_ebonrocAI : public ScriptedAI -{ - boss_ebonrocAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowFlame_Timer; - uint32 WingBuffet_Timer; - uint32 ShadowOfEbonroc_Timer; - uint32 Heal_Timer; - - void Reset() - { - ShadowFlame_Timer = 15000; //These times are probably wrong - WingBuffet_Timer = 30000; - ShadowOfEbonroc_Timer = 45000; - Heal_Timer = 1000; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Shadowflame Timer - if (ShadowFlame_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = urand(12000, 15000); - }else ShadowFlame_Timer -= diff; - - //Wing Buffet Timer - if (WingBuffet_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_WINGBUFFET); - WingBuffet_Timer = 25000; - }else WingBuffet_Timer -= diff; - - //Shadow of Ebonroc Timer - if (ShadowOfEbonroc_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWOFEBONROC); - ShadowOfEbonroc_Timer = urand(25000, 35000); - }else ShadowOfEbonroc_Timer -= diff; - - if (m_creature->getVictim()->HasAura(SPELL_SHADOWOFEBONROC, EFFECT_INDEX_0)) - { - if (Heal_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_HEAL); - Heal_Timer = urand(1000, 3000); - }else Heal_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ebonroc(Creature* pCreature) -{ - return new boss_ebonrocAI(pCreature); -} - -void AddSC_boss_ebonroc() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_ebonroc"; - newscript->GetAI = &GetAI_boss_ebonroc; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp deleted file mode 100644 index 312265f0a3..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Firemaw -SD%Complete: 100 -SDComment: -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWFLAME 22539 -#define SPELL_WINGBUFFET 23339 -#define SPELL_FLAMEBUFFET 23341 - -struct MANGOS_DLL_DECL boss_firemawAI : public ScriptedAI -{ - boss_firemawAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowFlame_Timer; - uint32 WingBuffet_Timer; - uint32 FlameBuffet_Timer; - - void Reset() - { - ShadowFlame_Timer = 30000; //These times are probably wrong - WingBuffet_Timer = 24000; - FlameBuffet_Timer = 5000; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowFlame_Timer - if (ShadowFlame_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = urand(15000, 18000); - }else ShadowFlame_Timer -= diff; - - //WingBuffet_Timer - if (WingBuffet_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_WINGBUFFET); - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-75); - - WingBuffet_Timer = 25000; - }else WingBuffet_Timer -= diff; - - //FlameBuffet_Timer - if (FlameBuffet_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FLAMEBUFFET); - FlameBuffet_Timer = 5000; - }else FlameBuffet_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_firemaw(Creature* pCreature) -{ - return new boss_firemawAI(pCreature); -} - -void AddSC_boss_firemaw() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_firemaw"; - newscript->GetAI = &GetAI_boss_firemaw; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp deleted file mode 100644 index 33b5d955bd..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Flamegor -SD%Complete: 100 -SDComment: -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -enum -{ - EMOTE_GENERIC_FRENZY = -1000002, - - SPELL_SHADOWFLAME = 22539, - SPELL_WINGBUFFET = 23339, - SPELL_FRENZY = 23342 //This spell periodically triggers fire nova -}; - -struct MANGOS_DLL_DECL boss_flamegorAI : public ScriptedAI -{ - boss_flamegorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowFlame_Timer; - uint32 WingBuffet_Timer; - uint32 Frenzy_Timer; - - void Reset() - { - ShadowFlame_Timer = 21000; //These times are probably wrong - WingBuffet_Timer = 35000; - Frenzy_Timer = 10000; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowFlame_Timer - if (ShadowFlame_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = urand(15000, 22000); - }else ShadowFlame_Timer -= diff; - - //WingBuffet_Timer - if (WingBuffet_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_WINGBUFFET); - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-75); - - WingBuffet_Timer = 25000; - }else WingBuffet_Timer -= diff; - - //Frenzy_Timer - if (Frenzy_Timer < diff) - { - if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); - Frenzy_Timer = urand(8000, 10000); - } - }else Frenzy_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_flamegor(Creature* pCreature) -{ - return new boss_flamegorAI(pCreature); -} - -void AddSC_boss_flamegor() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_flamegor"; - newscript->GetAI = &GetAI_boss_flamegor; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp deleted file mode 100644 index da5fb00a30..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Nefarian -SD%Complete: 80 -SDComment: Some issues with class calls effecting more than one class -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO -1469007 -#define SAY_XHEALTH -1469008 -#define SAY_SHADOWFLAME -1469009 -#define SAY_RAISE_SKELETONS -1469010 -#define SAY_SLAY -1469011 -#define SAY_DEATH -1469012 - -#define SAY_MAGE -1469013 -#define SAY_WARRIOR -1469014 -#define SAY_DRUID -1469015 -#define SAY_PRIEST -1469016 -#define SAY_PALADIN -1469017 -#define SAY_SHAMAN -1469018 -#define SAY_WARLOCK -1469019 -#define SAY_HUNTER -1469020 -#define SAY_ROGUE -1469021 - -#define SPELL_SHADOWFLAME_INITIAL 22972 -#define SPELL_SHADOWFLAME 22539 -#define SPELL_BELLOWINGROAR 22686 -#define SPELL_VEILOFSHADOW 7068 -#define SPELL_CLEAVE 20691 -#define SPELL_TAILLASH 23364 -#define SPELL_BONECONTRUST 23363 //23362, 23361 - -#define SPELL_MAGE 23410 //wild magic -#define SPELL_WARRIOR 23397 //beserk -#define SPELL_DRUID 23398 // cat form -#define SPELL_PRIEST 23401 // corrupted healing -#define SPELL_PALADIN 23418 //syphon blessing -#define SPELL_SHAMAN 23425 //totems -#define SPELL_WARLOCK 23427 //infernals -#define SPELL_HUNTER 23436 //bow broke -#define SPELL_ROGUE 23414 //Paralise - -struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI -{ - boss_nefarianAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowFlame_Timer; - uint32 BellowingRoar_Timer; - uint32 VeilOfShadow_Timer; - uint32 Cleave_Timer; - uint32 TailLash_Timer; - uint32 ClassCall_Timer; - bool Phase3; - - void Reset() - { - ShadowFlame_Timer = 12000; //These times are probably wrong - BellowingRoar_Timer = 30000; - VeilOfShadow_Timer = 15000; - Cleave_Timer = 7000; - TailLash_Timer = 10000; - ClassCall_Timer = 35000; //35-40 seconds - Phase3 = false; - } - - void KilledUnit(Unit* Victim) - { - if (urand(0, 4)) - return; - - DoScriptText(SAY_SLAY, m_creature, Victim); - } - - void JustDied(Unit* Killer) - { - DoScriptText(SAY_DEATH, m_creature); - } - - void Aggro(Unit* pWho) - { - switch(urand(0, 3)) - { - case 0: DoScriptText(SAY_XHEALTH, m_creature); break; - case 1: DoScriptText(SAY_AGGRO, m_creature); break; - case 2: DoScriptText(SAY_SHADOWFLAME, m_creature); break; - } - - DoCastSpellIfCan(pWho,SPELL_SHADOWFLAME_INITIAL); - - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowFlame_Timer - if (ShadowFlame_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWFLAME); - ShadowFlame_Timer = 12000; - }else ShadowFlame_Timer -= diff; - - //BellowingRoar_Timer - if (BellowingRoar_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BELLOWINGROAR); - BellowingRoar_Timer = 30000; - }else BellowingRoar_Timer -= diff; - - //VeilOfShadow_Timer - if (VeilOfShadow_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_VEILOFSHADOW); - VeilOfShadow_Timer = 15000; - }else VeilOfShadow_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - //TailLash_Timer - if (TailLash_Timer < diff) - { - //Cast NYI since we need a better check for behind target - //DoCastSpellIfCan(m_creature->getVictim(),SPELL_TAILLASH); - - TailLash_Timer = 10000; - }else TailLash_Timer -= diff; - - //ClassCall_Timer - if (ClassCall_Timer < diff) - { - //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)) - { - case 0: - DoScriptText(SAY_MAGE, m_creature); - DoCastSpellIfCan(m_creature,SPELL_MAGE); - break; - case 1: - DoScriptText(SAY_WARRIOR, m_creature); - DoCastSpellIfCan(m_creature,SPELL_WARRIOR); - break; - case 2: - DoScriptText(SAY_DRUID, m_creature); - DoCastSpellIfCan(m_creature,SPELL_DRUID); - break; - case 3: - DoScriptText(SAY_PRIEST, m_creature); - DoCastSpellIfCan(m_creature,SPELL_PRIEST); - break; - case 4: - DoScriptText(SAY_PALADIN, m_creature); - DoCastSpellIfCan(m_creature,SPELL_PALADIN); - break; - case 5: - DoScriptText(SAY_SHAMAN, m_creature); - DoCastSpellIfCan(m_creature,SPELL_SHAMAN); - break; - case 6: - DoScriptText(SAY_WARLOCK, m_creature); - DoCastSpellIfCan(m_creature,SPELL_WARLOCK); - break; - case 7: - DoScriptText(SAY_HUNTER, m_creature); - DoCastSpellIfCan(m_creature,SPELL_HUNTER); - break; - case 8: - DoScriptText(SAY_ROGUE, m_creature); - DoCastSpellIfCan(m_creature,SPELL_ROGUE); - break; - } - - ClassCall_Timer = urand(35000, 40000); - }else ClassCall_Timer -= diff; - - //Phase3 begins when we are below X health - if (!Phase3 && m_creature->GetHealthPercent() < 20.0f) - { - Phase3 = true; - DoScriptText(SAY_RAISE_SKELETONS, m_creature); - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_nefarian(Creature* pCreature) -{ - return new boss_nefarianAI(pCreature); -} - -void AddSC_boss_nefarian() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_nefarian"; - newscript->GetAI = &GetAI_boss_nefarian; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp deleted file mode 100644 index 41e6645af1..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Razorgore -SD%Complete: 50 -SDComment: Needs additional review. Phase 1 NYI (Grethok the Controller) -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -//Razorgore Phase 2 Script -enum -{ - SAY_EGGS_BROKEN1 = -1469022, - SAY_EGGS_BROKEN2 = -1469023, - SAY_EGGS_BROKEN3 = -1469024, - SAY_DEATH = -1469025, - - SPELL_CLEAVE = 19632, - SPELL_WARSTOMP = 24375, - SPELL_FIREBALLVOLLEY = 22425, - SPELL_CONFLAGRATION = 23023 -}; - -struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI -{ - boss_razorgoreAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiCleaveTimer; - uint32 m_uiWarStompTimer; - uint32 m_uiFireballVolleyTimer; - uint32 m_uiConflagrationTimer; - - void Reset() - { - m_uiCleaveTimer = 15000; //These times are probably wrong - m_uiWarStompTimer = 35000; - m_uiConflagrationTimer = 12000; - m_uiFireballVolleyTimer = 7000; - - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void JustDied(Unit* pKiller) - { - DoScriptText(SAY_DEATH, m_creature); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Cleave - if (m_uiCleaveTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = urand(7000, 10000); - } - else - m_uiCleaveTimer -= uiDiff; - - // WarStomp - if (m_uiWarStompTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_WARSTOMP); - m_uiWarStompTimer = urand(15000, 25000); - } - else - m_uiWarStompTimer -= uiDiff; - - // Fireball Volley - if (m_uiFireballVolleyTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALLVOLLEY); - m_uiFireballVolleyTimer = urand(12000, 15000); - } - else - m_uiFireballVolleyTimer -= uiDiff; - - // Conflagration - if (m_uiConflagrationTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONFLAGRATION); - //We will remove this threat reduction and add an aura check. - - //if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - //m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); - - m_uiConflagrationTimer = 12000; - } - else - m_uiConflagrationTimer -= uiDiff; - - // Aura Check. If the gamer is affected by confliguration we attack a random gamer. - if (m_creature->getVictim()->HasAura(SPELL_CONFLAGRATION, EFFECT_INDEX_0)) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - m_creature->TauntApply(pTarget); - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_razorgore(Creature* pCreature) -{ - return new boss_razorgoreAI(pCreature); -} - -void AddSC_boss_razorgore() -{ - Script* newscript; - - newscript = new Script; - newscript->Name = "boss_razorgore"; - newscript->GetAI = &GetAI_boss_razorgore; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp deleted file mode 100644 index 4da3066494..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Vaelastrasz -SD%Complete: 75 -SDComment: Burning Adrenaline not correctly implemented in core -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SAY_LINE1 -1469026 -#define SAY_LINE2 -1469027 -#define SAY_LINE3 -1469028 -#define SAY_HALFLIFE -1469029 -#define SAY_KILLTARGET -1469030 - -#define GOSSIP_ITEM "Start Event " - -#define SPELL_ESSENCEOFTHERED 23513 -#define SPELL_FLAMEBREATH 23461 -#define SPELL_FIRENOVA 23462 -#define SPELL_TAILSWIPE 15847 -#define SPELL_BURNINGADRENALINE 23620 -#define SPELL_CLEAVE 20684 //Chain cleave is most likely named something different and contains a dummy effect - -struct MANGOS_DLL_DECL boss_vaelAI : public ScriptedAI -{ - boss_vaelAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pCreature->setFaction(35); - pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Reset(); - } - - uint64 PlayerGUID; - uint32 SpeachTimer; - uint32 SpeachNum; - uint32 Cleave_Timer; - uint32 FlameBreath_Timer; - uint32 FireNova_Timer; - uint32 BurningAdrenalineCaster_Timer; - uint32 BurningAdrenalineTank_Timer; - uint32 TailSwipe_Timer; - bool HasYelled; - bool DoingSpeach; - - void Reset() - { - PlayerGUID = 0; - SpeachTimer = 0; - SpeachNum = 0; - Cleave_Timer = 8000; //These times are probably wrong - FlameBreath_Timer = 11000; - BurningAdrenalineCaster_Timer = 15000; - BurningAdrenalineTank_Timer = 45000; - FireNova_Timer = 5000; - TailSwipe_Timer = 20000; - HasYelled = false; - DoingSpeach = false; - } - - void BeginSpeach(Unit* target) - { - //Stand up and begin speach - PlayerGUID = target->GetGUID(); - - //10 seconds - DoScriptText(SAY_LINE1, m_creature); - - SpeachTimer = 10000; - SpeachNum = 0; - DoingSpeach = true; - } - - void KilledUnit(Unit *victim) - { - if (urand(0, 4)) - return; - - DoScriptText(SAY_KILLTARGET, m_creature, victim); - } - - void Aggro(Unit* pWho) - { - DoCastSpellIfCan(m_creature,SPELL_ESSENCEOFTHERED); - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - //Speach - if (DoingSpeach) - { - if (SpeachTimer < diff) - { - switch (SpeachNum) - { - case 0: - //16 seconds till next line - DoScriptText(SAY_LINE2, m_creature); - SpeachTimer = 16000; - ++SpeachNum; - break; - case 1: - //This one is actually 16 seconds but we only go to 10 seconds because he starts attacking after he says "I must fight this!" - DoScriptText(SAY_LINE3, m_creature); - SpeachTimer = 10000; - ++SpeachNum; - break; - case 2: - m_creature->setFaction(103); - m_creature->SetHealth(int(m_creature->GetMaxHealth()*.3)); - - if (PlayerGUID) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(PlayerGUID)) - AttackStart(pPlayer); - - DoCastSpellIfCan(m_creature, SPELL_ESSENCEOFTHERED); - } - SpeachTimer = 0; - DoingSpeach = false; - break; - } - }else SpeachTimer -= diff; - } - - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Yell if hp lower than 15% - if (m_creature->GetHealthPercent() < 15.0f && !HasYelled) - { - DoScriptText(SAY_HALFLIFE, m_creature); - HasYelled = true; - } - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 15000; - }else Cleave_Timer -= diff; - - //FlameBreath_Timer - if (FlameBreath_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FLAMEBREATH); - FlameBreath_Timer = urand(4000, 8000); - }else FlameBreath_Timer -= diff; - - //BurningAdrenalineCaster_Timer - if (BurningAdrenalineCaster_Timer < diff) - { - Unit* target = NULL; - - int i = 0 ; - while (i < 3) // max 3 tries to get a random target with power_mana - { - ++i; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1);//not aggro leader - if (target) - if (target->getPowerType() == POWER_MANA) - i=3; - } - if (target) // cast on self (see below) - target->CastSpell(target,SPELL_BURNINGADRENALINE,1); - - BurningAdrenalineCaster_Timer = 15000; - }else BurningAdrenalineCaster_Timer -= diff; - - //BurningAdrenalineTank_Timer - if (BurningAdrenalineTank_Timer < diff) - { - // have the victim cast the spell on himself otherwise the third effect aura will be applied - // to Vael instead of the player - m_creature->getVictim()->CastSpell(m_creature->getVictim(),SPELL_BURNINGADRENALINE,1); - - BurningAdrenalineTank_Timer = 45000; - }else BurningAdrenalineTank_Timer -= diff; - - //FireNova_Timer - if (FireNova_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FIRENOVA); - FireNova_Timer = 5000; - }else FireNova_Timer -= diff; - - //TailSwipe_Timer - if (TailSwipe_Timer < diff) - { - //Only cast if we are behind - /*if (!m_creature->HasInArc(M_PI, m_creature->getVictim())) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_TAILSWIPE); - }*/ - - TailSwipe_Timer = 20000; - }else TailSwipe_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -bool GossipSelect_boss_vael(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) //Fight time - { - pPlayer->CLOSE_GOSSIP_MENU(); - - if (boss_vaelAI* pVaelAI = dynamic_cast(pCreature->AI())) - pVaelAI->BeginSpeach((Unit*)pPlayer); - } - - return true; -} - -bool GossipHello_boss_vael(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(907, pCreature->GetGUID()); - - return true; -} - -CreatureAI* GetAI_boss_vael(Creature* pCreature) -{ - return new boss_vaelAI(pCreature); -} - -void AddSC_boss_vael() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_vaelastrasz"; - newscript->GetAI = &GetAI_boss_vael; - newscript->pGossipHello = &GossipHello_boss_vael; - newscript->pGossipSelect = &GossipSelect_boss_vael; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp deleted file mode 100644 index 1fab906292..0000000000 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Victor_Nefarius -SD%Complete: 75 -SDComment: Missing some text, Vael beginning event, and spawns Nef in wrong place -SDCategory: Blackwing Lair -EndScriptData */ - -#include "precompiled.h" - -#define SAY_GAMESBEGIN_1 -1469004 -#define SAY_GAMESBEGIN_2 -1469005 -#define SAY_VAEL_INTRO -1469006 //when he corrupts Vaelastrasz - -#define GOSSIP_ITEM_1 "I've made no mistakes." -#define GOSSIP_ITEM_2 "You have lost your mind, Nefarius. You speak in riddles." -#define GOSSIP_ITEM_3 "Please do." - -#define CREATURE_BRONZE_DRAKANOID 14263 -#define CREATURE_BLUE_DRAKANOID 14261 -#define CREATURE_RED_DRAKANOID 14264 -#define CREATURE_GREEN_DRAKANOID 14262 -#define CREATURE_BLACK_DRAKANOID 14265 - -#define CREATURE_CHROMATIC_DRAKANOID 14302 -#define CREATURE_NEFARIAN 11583 - -#define ADD_X1 -7591.151855f -#define ADD_X2 -7514.598633f -#define ADD_Y1 -1204.051880f -#define ADD_Y2 -1150.448853f -#define ADD_Z1 476.800476f -#define ADD_Z2 476.796570f - -#define NEF_X -7445.0f -#define NEF_Y -1332.0f -#define NEF_Z 536.0f - -#define HIDE_X -7592.0f -#define HIDE_Y -1264.0f -#define HIDE_Z 481.0f - -#define SPELL_SHADOWBOLT 21077 -#define SPELL_FEAR 26070 - -//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 into hiding and stop attacking -//If Nefarian despawns because he killed the players then this guy will EnterEvadeMode -//and allow players to start the event over -//If nefarian dies then he will kill himself then he will kill himself in his hiding place -//To prevent players from doing the event twice - -struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI -{ - boss_victor_nefariusAI(Creature* pCreature) : ScriptedAI(pCreature) - { - NefarianGUID = 0; - Reset(); - srand(time(NULL)); - switch(urand(0, 19)) - { - case 0: - DrakType1 = CREATURE_BRONZE_DRAKANOID; - DrakType2 = CREATURE_BLUE_DRAKANOID; - break; - case 1: - DrakType1 = CREATURE_BRONZE_DRAKANOID; - DrakType2 = CREATURE_RED_DRAKANOID; - break; - case 2: - DrakType1 = CREATURE_BRONZE_DRAKANOID; - DrakType2 = CREATURE_GREEN_DRAKANOID; - break; - case 3: - DrakType1 = CREATURE_BRONZE_DRAKANOID; - DrakType2 = CREATURE_BLACK_DRAKANOID; - break; - case 4: - DrakType1 = CREATURE_BLUE_DRAKANOID; - DrakType2 = CREATURE_BRONZE_DRAKANOID; - break; - case 5: - DrakType1 = CREATURE_BLUE_DRAKANOID; - DrakType2 = CREATURE_RED_DRAKANOID; - break; - case 6: - DrakType1 = CREATURE_BLUE_DRAKANOID; - DrakType2 = CREATURE_GREEN_DRAKANOID; - break; - case 7: - DrakType1 = CREATURE_BLUE_DRAKANOID; - DrakType2 = CREATURE_BLACK_DRAKANOID; - break; - case 8: - DrakType1 = CREATURE_RED_DRAKANOID; - DrakType2 = CREATURE_BRONZE_DRAKANOID; - break; - case 9: - DrakType1 = CREATURE_RED_DRAKANOID; - DrakType2 = CREATURE_BLUE_DRAKANOID; - break; - case 10: - DrakType1 = CREATURE_RED_DRAKANOID; - DrakType2 = CREATURE_GREEN_DRAKANOID; - break; - case 11: - DrakType1 = CREATURE_RED_DRAKANOID; - DrakType2 = CREATURE_BLACK_DRAKANOID; - break; - case 12: - DrakType1 = CREATURE_GREEN_DRAKANOID; - DrakType2 = CREATURE_BRONZE_DRAKANOID; - break; - case 13: - DrakType1 = CREATURE_GREEN_DRAKANOID; - DrakType2 = CREATURE_BLUE_DRAKANOID; - break; - case 14: - DrakType1 = CREATURE_GREEN_DRAKANOID; - DrakType2 = CREATURE_RED_DRAKANOID; - break; - case 15: - DrakType1 = CREATURE_GREEN_DRAKANOID; - DrakType2 = CREATURE_BLACK_DRAKANOID; - break; - case 16: - DrakType1 = CREATURE_BLACK_DRAKANOID; - DrakType2 = CREATURE_BRONZE_DRAKANOID; - break; - case 17: - DrakType1 = CREATURE_BLACK_DRAKANOID; - DrakType2 = CREATURE_BLUE_DRAKANOID; - break; - case 18: - DrakType1 = CREATURE_BLACK_DRAKANOID; - DrakType2 = CREATURE_GREEN_DRAKANOID; - break; - case 19: - DrakType1 = CREATURE_BLACK_DRAKANOID; - DrakType2 = CREATURE_RED_DRAKANOID; - break; - } - } - - uint32 SpawnedAdds; - uint32 AddSpawnTimer; - uint32 ShadowBoltTimer; - uint32 FearTimer; - uint32 MindControlTimer; - uint32 ResetTimer; - uint32 DrakType1; - uint32 DrakType2; - uint64 NefarianGUID; - uint32 NefCheckTime; - - void Reset() - { - SpawnedAdds = 0; - AddSpawnTimer = 10000; - ShadowBoltTimer = 5000; - FearTimer = 8000; - ResetTimer = 900000; //On official it takes him 15 minutes(900 seconds) to reset. We are only doing 1 minute to make testing easier - NefarianGUID = 0; - NefCheckTime = 2000; - - m_creature->SetUInt32Value(UNIT_NPC_FLAGS,1); - m_creature->setFaction(35); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void BeginEvent(Player* target) - { - DoScriptText(SAY_GAMESBEGIN_2, m_creature); - - //MaNGOS::Singleton::Instance().GetMap(m_creature->GetMapId(), m_creature)->GetPlayers().begin(); - /* - list ::iterator i = MapManager::Instance().GetMap(m_creature->GetMapId(), m_creature)->GetPlayers().begin(); - - for (i = MapManager::Instance().GetMap(m_creature->GetMapId(), m_creature)->GetPlayers().begin(); i != MapManager::Instance().GetMap(m_creature->GetMapId(), m_creature)->GetPlayers().end(); ++i) - { - AttackStart((*i)); - } - */ - m_creature->SetUInt32Value(UNIT_NPC_FLAGS,0); - m_creature->setFaction(103); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - AttackStart(target); - } - - void MoveInLineOfSight(Unit *who) - { - //We simply use this function to find players until we can use Map->GetPlayers() - - if (who && who->GetTypeId() == TYPEID_PLAYER && m_creature->IsHostileTo(who)) - { - //Add them to our threat list - m_creature->AddThreat(who); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Only do this if we haven't spawned nef yet - if (SpawnedAdds < 42) - { - //ShadowBoltTimer - if (ShadowBoltTimer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - DoCastSpellIfCan(target,SPELL_SHADOWBOLT); - - ShadowBoltTimer = urand(3000, 10000); - }else ShadowBoltTimer -= diff; - - //FearTimer - if (FearTimer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - DoCastSpellIfCan(target,SPELL_FEAR); - - FearTimer = urand(10000, 20000); - }else FearTimer -= diff; - - //Add spawning mechanism - if (AddSpawnTimer < diff) - { - //Spawn 2 random types of creatures at the 2 locations - uint32 CreatureID; - Creature* Spawned = NULL; - Unit* target = NULL; - - //1 in 3 chance it will be a chromatic - if (!urand(0, 2)) - CreatureID = CREATURE_CHROMATIC_DRAKANOID; - else CreatureID = DrakType1; - - ++SpawnedAdds; - - //Spawn creature and force it to start attacking a random target - Spawned = m_creature->SummonCreature(CreatureID,ADD_X1,ADD_Y1,ADD_Z1,5.000f,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target && Spawned) - { - Spawned->AI()->AttackStart(target); - Spawned->setFaction(103); - } - - //1 in 3 chance it will be a chromatic - if (!urand(0, 2)) - CreatureID = CREATURE_CHROMATIC_DRAKANOID; - else CreatureID = DrakType2; - - ++SpawnedAdds; - - target = NULL; - Spawned = NULL; - Spawned = m_creature->SummonCreature(CreatureID,ADD_X2,ADD_Y2,ADD_Z2,5.000,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target && Spawned) - { - Spawned->AI()->AttackStart(target); - Spawned->setFaction(103); - } - - //Begin phase 2 by spawning Nefarian and what not - if (SpawnedAdds >= 42) - { - //Teleport Victor Nefarius way out of the map - //MapManager::Instance().GetMap(m_creature->GetMapId(), m_creature)->CreatureRelocation(m_creature,0,0,-5000,0); - - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - - //Root self - DoCastSpellIfCan(m_creature,33356); - - //Make super invis - DoCastSpellIfCan(m_creature,8149); - - //Teleport self to a hiding spot - m_creature->NearTeleportTo(HIDE_X, HIDE_Y, HIDE_Z, 0.0f); - - //Spawn nef and have him attack a random target - Creature* Nefarian = m_creature->SummonCreature(CREATURE_NEFARIAN,NEF_X,NEF_Y,NEF_Z,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,120000); - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - - if (target && Nefarian) - { - Nefarian->AI()->AttackStart(target); - Nefarian->setFaction(103); - NefarianGUID = Nefarian->GetGUID(); - } - else error_log("SD2: Blackwing Lair: Unable to spawn nefarian properly."); - } - - AddSpawnTimer = 4000; - }else AddSpawnTimer -= diff; - } - else if (NefarianGUID) - { - if (NefCheckTime < diff) - { - Creature* pNefarian = m_creature->GetMap()->GetCreature(NefarianGUID); - - //If nef is dead then we die to so the players get out of combat - //and cannot repeat the event - if (!pNefarian || !pNefarian->isAlive()) - { - NefarianGUID = 0; - m_creature->ForcedDespawn(); - } - - NefCheckTime = 2000; - }else NefCheckTime -= diff; - } - } -}; - -CreatureAI* GetAI_boss_victor_nefarius(Creature* pCreature) -{ - return new boss_victor_nefariusAI(pCreature); -} - -bool GossipHello_boss_victor_nefarius(Player* pPlayer, Creature* pCreature) -{ - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1 , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(7134, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_boss_victor_nefarius(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_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(7198, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(7199, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->CLOSE_GOSSIP_MENU(); - DoScriptText(SAY_GAMESBEGIN_1, pCreature); - if (boss_victor_nefariusAI* pNefAI = dynamic_cast(pCreature->AI())) - pNefAI->BeginEvent(pPlayer); - break; - } - return true; -} - -void AddSC_boss_victor_nefarius() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_victor_nefarius"; - newscript->GetAI = &GetAI_boss_victor_nefarius; - newscript->pGossipHello = &GossipHello_boss_victor_nefarius; - newscript->pGossipSelect = &GossipSelect_boss_victor_nefarius; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blasted_lands.cpp b/scripts/eastern_kingdoms/blasted_lands.cpp index c641d2d228..710b9e3fba 100644 --- a/scripts/eastern_kingdoms/blasted_lands.cpp +++ b/scripts/eastern_kingdoms/blasted_lands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,48 +17,16 @@ /* ScriptData SDName: Blasted_Lands SD%Complete: 90 -SDComment: Quest support: 2784, 2801, 3628. Missing some texts for Fallen Hero. Teleporter to Rise of the Defiler missing group support. +SDComment: Quest support: 2784, 2801. Missing some texts for Fallen Hero. Teleporter to Rise of the Defiler missing group support. SDCategory: Blasted Lands EndScriptData */ /* ContentData -npc_deathly_usher npc_fallen_hero_of_horde EndContentData */ #include "precompiled.h" -/*###### -## npc_deathly_usher -######*/ - -#define GOSSIP_ITEM_USHER "I wish to to visit the Rise of the Defiler." - -#define SPELL_TELEPORT_SINGLE 12885 -#define SPELL_TELEPORT_SINGLE_IN_GROUP 13142 -#define SPELL_TELEPORT_GROUP 27686 - -bool GossipHello_npc_deathly_usher(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(3628) == QUEST_STATUS_INCOMPLETE && pPlayer->HasItemCount(10757, 1)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_USHER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_deathly_usher(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, SPELL_TELEPORT_SINGLE, true); - } - - return true; -} - /*###### ## npc_fallen_hero_of_horde ######*/ @@ -74,64 +42,64 @@ bool GossipSelect_npc_deathly_usher(Player* pPlayer, Creature* pCreature, uint32 bool GossipHello_npc_fallen_hero_of_horde(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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->GetGUID()); + 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); - pPlayer->SEND_GOSSIP_MENU(1392, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1392, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+11: - pPlayer->SEND_GOSSIP_MENU(1411, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1411, pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(2784) == QUEST_STATUS_INCOMPLETE) pPlayer->AreaExploredOrEventHappens(2784); if (pPlayer->GetTeam() == ALLIANCE) { pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(1411, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1411, pCreature->GetObjectGuid()); } break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); - pPlayer->SEND_GOSSIP_MENU(1451, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1451, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+21: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - pPlayer->SEND_GOSSIP_MENU(1452, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1452, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+22: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); - pPlayer->SEND_GOSSIP_MENU(1453, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1453, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+23: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); - pPlayer->SEND_GOSSIP_MENU(1454, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1454, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+24: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); - pPlayer->SEND_GOSSIP_MENU(1455, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1455, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+25: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 26); - pPlayer->SEND_GOSSIP_MENU(1456, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1456, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+26: pPlayer->CLOSE_GOSSIP_MENU(); @@ -143,17 +111,11 @@ bool GossipSelect_npc_fallen_hero_of_horde(Player* pPlayer, Creature* pCreature, void AddSC_blasted_lands() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_deathly_usher"; - newscript->pGossipHello = &GossipHello_npc_deathly_usher; - newscript->pGossipSelect = &GossipSelect_npc_deathly_usher; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_fallen_hero_of_horde"; - newscript->pGossipHello = &GossipHello_npc_fallen_hero_of_horde; - newscript->pGossipSelect = &GossipSelect_npc_fallen_hero_of_horde; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_fallen_hero_of_horde"; + pNewScript->pGossipHello = &GossipHello_npc_fallen_hero_of_horde; + pNewScript->pGossipSelect = &GossipSelect_npc_fallen_hero_of_horde; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/boss_kruul.cpp b/scripts/eastern_kingdoms/boss_kruul.cpp deleted file mode 100644 index 1c1c9a973c..0000000000 --- a/scripts/eastern_kingdoms/boss_kruul.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright (C) 2006 - 2010 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() - { - // 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 *newscript; - newscript = new Script; - newscript->Name = "boss_kruul"; - newscript->GetAI = &GetAI_boss_kruul; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/burning_steppes.cpp b/scripts/eastern_kingdoms/burning_steppes.cpp index 02d73c7eda..9ab9aeb192 100644 --- a/scripts/eastern_kingdoms/burning_steppes.cpp +++ b/scripts/eastern_kingdoms/burning_steppes.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,15 +17,17 @@ /* 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 @@ -37,13 +39,13 @@ struct MANGOS_DLL_DECL npc_ragged_johnAI : public ScriptedAI void Reset() {} - 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); } } @@ -71,62 +73,62 @@ CreatureAI* GetAI_npc_ragged_john(Creature* pCreature) bool GossipHello_npc_ragged_john(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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 he last time you saw him.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(2713, pCreature->GetGUID()); + 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); - pPlayer->SEND_GOSSIP_MENU(2714, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2714, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+1: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Start making sense, dwarf. I don't want to have anything to do with your cracker, your pappy, or any sort of 'discreditin'.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(2715, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2715, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ironfoe?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(2716, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(2717, pCreature->GetGUID()); + 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: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "So that's how Windsor died...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(2718, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2718, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+5: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "So how did he die?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(2719, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(2720, pCreature->GetGUID()); + 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: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "WHY is he in Blackrock Depths?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - pPlayer->SEND_GOSSIP_MENU(2721, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2721, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+8: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "300? So the Dark Irons killed him and dragged him into the Depths?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - pPlayer->SEND_GOSSIP_MENU(2722, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(2723, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(2725, pCreature->GetGUID()); + 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: pPlayer->CLOSE_GOSSIP_MENU(); @@ -136,14 +138,330 @@ 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 MANGOS_DLL_DECL 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() + { + 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 *newscript; - - newscript = new Script; - newscript->Name = "npc_ragged_john"; - newscript->GetAI = &GetAI_npc_ragged_john; - newscript->pGossipHello = &GossipHello_npc_ragged_john; - newscript->pGossipSelect = &GossipSelect_npc_ragged_john; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_ragged_john"; + pNewScript->GetAI = &GetAI_npc_ragged_john; + 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/cata_zulaman/cata_boss_akilzon.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_akilzon.cpp new file mode 100644 index 0000000000..ef38817881 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_akilzon.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_akilzon +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_akilzon() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_boss_daakara.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_daakara.cpp new file mode 100644 index 0000000000..05657f5074 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_daakara.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_daakara +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_daakara() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_boss_halazzi.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_halazzi.cpp new file mode 100644 index 0000000000..44d4b51583 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_halazzi.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_halazzi +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_halazzi() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_boss_hex_lord_malacrass.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_hex_lord_malacrass.cpp new file mode 100644 index 0000000000..eab0260683 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_hex_lord_malacrass.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_hex_lord_malacrass +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_hex_lord_malacrass() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_boss_jan_alai.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_jan_alai.cpp new file mode 100644 index 0000000000..f88d663499 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_jan_alai.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_jan_alai +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_jan_alai() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_boss_nalorakk.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_nalorakk.cpp new file mode 100644 index 0000000000..24d8a07b7a --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_boss_nalorakk.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_nalorakk +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_nalorakk() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_instance_zulaman.cpp b/scripts/eastern_kingdoms/cata_zulaman/cata_instance_zulaman.cpp new file mode 100644 index 0000000000..2936b70443 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_instance_zulaman.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_instance_zulaman +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Aman (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_instance_zulaman() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulaman/cata_zulaman.h b/scripts/eastern_kingdoms/cata_zulaman/cata_zulaman.h new file mode 100644 index 0000000000..92c7abdea2 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulaman/cata_zulaman.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_CATAZULAMAN_H +#define DEF_CATAZULAMAN_H + +#endif diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_bloodlord_mandokir.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_bloodlord_mandokir.cpp new file mode 100644 index 0000000000..c5da1aa6d1 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_bloodlord_mandokir.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_bloodlord_mandokir +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_bloodlord_mandokir() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_edge_of_madness.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_edge_of_madness.cpp new file mode 100644 index 0000000000..93391da805 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_edge_of_madness.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_edge_of_madness +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_edge_of_madness() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_high_priest_veroxis.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_high_priest_veroxis.cpp new file mode 100644 index 0000000000..5c7d424b33 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_high_priest_veroxis.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_high_priest_veroxis +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_high_priest_veroxis() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_high_priestess_kilnara.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_high_priestess_kilnara.cpp new file mode 100644 index 0000000000..44b3915330 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_high_priestess_kilnara.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_high_priestess_kilnara +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_high_priestess_kilnara() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_jin_do_the_godbreaker.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_jin_do_the_godbreaker.cpp new file mode 100644 index 0000000000..6f898c333c --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_jin_do_the_godbreaker.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_jin_do_the_godbreaker +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_jin_do_the_godbreaker() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_zabzil.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_zabzil.cpp new file mode 100644 index 0000000000..14e96e0c09 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_boss_zabzil.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_boss_zabzil +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_boss_zabzil() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_instance_zulgurub.cpp b/scripts/eastern_kingdoms/cata_zulgurub/cata_instance_zulgurub.cpp new file mode 100644 index 0000000000..60787044d4 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_instance_zulgurub.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: cata_instance_zulgurub +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Zul'Gurub (Cata) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_cata_instance_zulgurub() +{ +} diff --git a/scripts/eastern_kingdoms/cata_zulgurub/cata_zulgurub.h b/scripts/eastern_kingdoms/cata_zulgurub/cata_zulgurub.h new file mode 100644 index 0000000000..fedc446678 --- /dev/null +++ b/scripts/eastern_kingdoms/cata_zulgurub/cata_zulgurub.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_CATAZULGURUB_H +#define DEF_CATAZULGURUB_H + +#endif diff --git a/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp b/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp new file mode 100644 index 0000000000..3cd0aaae23 --- /dev/null +++ b/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp @@ -0,0 +1,270 @@ +/* Copyright (C) 2006 - 2013 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_Mr_Smite +SD%Complete: 100 +SDComment: +SDCategory: Deadmines +EndScriptData */ + +#include "precompiled.h" +#include "deadmines.h" + +enum +{ + SAY_PHASE_2 = -1036002, + SAY_PHASE_3 = -1036003, + + // EQUIP_ID_SWORD = 2179, // default equipment, not used in code + EQUIP_ID_AXE = 2183, + EQUIP_ID_HAMMER = 10756, + + SPELL_NIBLE_REFLEXES = 6433, // removed after phase 1 + SPELL_SMITE_SLAM = 6435, // only casted in phase 3 + SPELL_SMITE_STOMP = 6432, + 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, + PHASE_3 = 3, + PHASE_EQUIP_NULL = 4, + PHASE_EQUIP_START = 5, + PHASE_EQUIP_PROCESS = 6, + PHASE_EQUIP_END = 7, +}; + +struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI +{ + boss_mr_smiteAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiPhase; + uint32 m_uiEquipTimer; + uint32 m_uiSlamTimer; + + void Reset() + { + m_uiPhase = PHASE_1; + m_uiEquipTimer = 0; + m_uiSlamTimer = 9000; + + DoCastSpellIfCan(m_creature, SPELL_NIBLE_REFLEXES, CAST_TRIGGERED); + + // must assume database has the default equipment set + SetEquipmentSlots(true); + } + + void AttackedBy(Unit* pAttacker) override + { + if (m_creature->getVictim()) + return; + + if (m_uiPhase > PHASE_3) + return; + + AttackStart(pAttacker); + } + + void AttackStart(Unit* pWho) override + { + if (m_uiPhase > PHASE_3) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void MovementInform(uint32 uiMotionType, uint32 /*uiPointId*/) override + { + if (uiMotionType != POINT_MOTION_TYPE) + return; + + m_creature->SetSheath(SHEATH_STATE_UNARMED); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + + m_uiEquipTimer = 3000; + m_uiPhase = PHASE_EQUIP_PROCESS; + } + + void PhaseEquipStart() + { + ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); + + if (!pInstance) + return; + + GameObject* pChest = pInstance->GetSingleGameObjectFromStorage(GO_SMITE_CHEST); + + if (!pChest) + return; + + m_uiPhase = PHASE_EQUIP_NULL; + + float fX, fY, fZ; + pChest->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); + + m_creature->GetMotionMaster()->Clear(); + m_creature->SetFacingToObject(pChest); + m_creature->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + + void PhaseEquipProcess() + { + if (m_creature->GetHealthPercent() < 33.0f) + { + // It's Hammer, go Hammer! + SetEquipmentSlots(false, EQUIP_ID_HAMMER, EQUIP_UNEQUIP); + DoCastSpellIfCan(m_creature, SPELL_SMITE_HAMMER); + } + else + SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE); + + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiPhase = PHASE_EQUIP_END; + m_uiEquipTimer = 1000; + } + + void PhaseEquipEnd() + { + // We don't have getVictim, so select from threat list + Unit* pVictim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0); + + if (!pVictim) + { + EnterEvadeMode(); + return; + } + + m_creature->SetSheath(SHEATH_STATE_MELEE); + + m_uiPhase = m_creature->GetHealthPercent() < 33.0f ? PHASE_3 : PHASE_2; + + if (m_uiPhase == PHASE_2) + DoCastSpellIfCan(m_creature, SPELL_THRASH, CAST_TRIGGERED); + + AttackStart(pVictim); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + if (m_uiEquipTimer) + { + // decrease the cooldown in between equipment change phases + if (m_uiEquipTimer > uiDiff) + { + m_uiEquipTimer -= uiDiff; + return; + } + else + m_uiEquipTimer = 0; + } + + switch (m_uiPhase) + { + case PHASE_EQUIP_START: + PhaseEquipStart(); + break; + case PHASE_EQUIP_PROCESS: + PhaseEquipProcess(); + break; + case PHASE_EQUIP_END: + PhaseEquipEnd(); + break; + } + + return; + } + + // the normal combat phases + switch (m_uiPhase) + { + case PHASE_1: + { + if (m_creature->GetHealthPercent() < 66.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_SMITE_STOMP) == CAST_OK) + { + DoScriptText(m_creature->GetHealthPercent() < 33.0f ? SAY_PHASE_3 : SAY_PHASE_2, m_creature); + m_uiPhase = PHASE_EQUIP_START; + m_uiEquipTimer = 2500; + + // will clear getVictim (m_attacking) + m_creature->AttackStop(true); + m_creature->RemoveAurasDueToSpell(SPELL_NIBLE_REFLEXES); + } + return; + } + break; + } + case PHASE_2: + { + if (m_creature->GetHealthPercent() < 33.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_SMITE_STOMP) == CAST_OK) + { + DoScriptText(SAY_PHASE_3, m_creature); + m_uiPhase = PHASE_EQUIP_START; + m_uiEquipTimer = 2500; + + // will clear getVictim (m_attacking) + m_creature->AttackStop(true); + m_creature->RemoveAurasDueToSpell(SPELL_THRASH); + } + return; + } + break; + } + case PHASE_3: + { + if (m_uiSlamTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SMITE_SLAM) == CAST_OK) + m_uiSlamTimer = 11000; + } + else + m_uiSlamTimer -= uiDiff; + + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_mr_smite(Creature* pCreature) +{ + return new boss_mr_smiteAI(pCreature); +} + +void AddSC_boss_mr_smite() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_mr_smite"; + pNewScript->GetAI = &GetAI_boss_mr_smite; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/deadmines/deadmines.cpp b/scripts/eastern_kingdoms/deadmines/deadmines.cpp index 0cb977fb30..30bfe3c106 100644 --- a/scripts/eastern_kingdoms/deadmines/deadmines.cpp +++ b/scripts/eastern_kingdoms/deadmines/deadmines.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,54 +16,34 @@ /* ScriptData SDName: Deadmines -SD%Complete: 90 -SDComment: Contains GO for event at end door +SD%Complete: 100 +SDComment: Contains GO for Iron Clad door event SDCategory: Deadmines EndScriptData */ #include "precompiled.h" #include "deadmines.h" -bool GOHello_go_door_lever_dm(Player* pPlayer, GameObject* pGo) +bool GOUse_go_defias_cannon(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); if (!pInstance) return false; - GameObject* pGoDoor = pInstance->instance->GetGameObject(pInstance->GetData64(DATA_DEFIAS_DOOR)); - - if (pGoDoor && pGoDoor->GetGoState() == 1) - return false; - - return true; -} - -bool GOHello_go_defias_cannon(Player* pPlayer, GameObject* pGo) -{ - ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); - - if (!pInstance) + if (pInstance->GetData(TYPE_IRON_CLAD_DOOR) == DONE) return false; - if (pInstance->GetData(TYPE_DEFIAS_ENDDOOR) == DONE || pInstance->GetData(TYPE_DEFIAS_ENDDOOR) == IN_PROGRESS) - return false; - - pInstance->SetData(TYPE_DEFIAS_ENDDOOR, IN_PROGRESS); + pInstance->SetData(TYPE_IRON_CLAD_DOOR, DONE); return false; } void AddSC_deadmines() { - Script *newscript; - - newscript = new Script; - newscript->Name = "go_door_lever_dm"; - newscript->pGOHello = &GOHello_go_door_lever_dm; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "go_defias_cannon"; - newscript->pGOHello = &GOHello_go_defias_cannon; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_defias_cannon"; + pNewScript->pGOUse = &GOUse_go_defias_cannon; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/deadmines/deadmines.h b/scripts/eastern_kingdoms/deadmines/deadmines.h index df5b91d197..ba1458f9ff 100644 --- a/scripts/eastern_kingdoms/deadmines/deadmines.h +++ b/scripts/eastern_kingdoms/deadmines/deadmines.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,19 +7,64 @@ enum { - MAX_ENCOUNTER = 1, + MAX_ENCOUNTER = 4, - TYPE_DEFIAS_ENDDOOR = 1, - DATA_DEFIAS_DOOR = 2, + TYPE_RHAHKZOR = 0, + TYPE_SNEED = 1, + TYPE_GILNID = 2, + TYPE_IRON_CLAD_DOOR = 3, INST_SAY_ALARM1 = -1036000, INST_SAY_ALARM2 = -1036001, - GO_DOOR_LEVER = 101833, - GO_IRON_CLAD = 16397, + GO_FACTORY_DOOR = 13965, // rhahk'zor + GO_MAST_ROOM_DOOR = 16400, // sneed + GO_FOUNDRY_DOOR = 16399, // gilnid + GO_HEAVY_DOOR_1 = 17153, // to sneed + GO_HEAVY_DOOR_2 = 17154, // to gilnid + GO_IRON_CLAD_DOOR = 16397, GO_DEFIAS_CANNON = 16398, + GO_SMITE_CHEST = 144111, // use to get correct location of mr.smites equipment changes + GO_MYSTERIOUS_CHEST = 180024, // used for quest 7938; spawns in the instance only if one of the players has the quest + + NPC_RHAHKZOR = 644, + NPC_SNEED = 643, + NPC_GILNID = 1763, NPC_MR_SMITE = 646, - NPC_PIRATE = 657 + NPC_PIRATE = 657, + NPC_SQUALLSHAPER = 1732, + + QUEST_FORTUNE_AWAITS = 7938, +}; + +class MANGOS_DLL_DECL instance_deadmines : public ScriptedInstance +{ + public: + instance_deadmines(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 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 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 4683b457c4..536ab772a8 100644 --- a/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp +++ b/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,117 +24,207 @@ EndScriptData */ #include "precompiled.h" #include "deadmines.h" -struct MANGOS_DLL_DECL instance_deadmines : public ScriptedInstance +instance_deadmines::instance_deadmines(Map* pMap) : ScriptedInstance(pMap), + m_uiIronDoorTimer(0), + m_uiDoorStep(0) { - instance_deadmines(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; +void instance_deadmines::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - uint64 m_uiIronCladGUID; - uint64 m_uiCannonGUID; - uint64 m_uiSmiteGUID; +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)) + DoRespawnGameObject(GO_MYSTERIOUS_CHEST, HOUR); +} - uint32 m_uiIronDoor_Timer; - uint32 m_uiDoor_Step; +void instance_deadmines::OnCreatureCreate(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_MR_SMITE) + m_mNpcEntryGuidStore[NPC_MR_SMITE] = pCreature->GetObjectGuid(); +} - void Initialize() +void instance_deadmines::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiIronCladGUID = 0; - m_uiCannonGUID = 0; - m_uiSmiteGUID = 0; - - m_uiIronDoor_Timer = 0; - m_uiDoor_Step = 0; + case GO_FACTORY_DOOR: + if (m_auiEncounter[TYPE_RHAHKZOR] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + + break; + case GO_MAST_ROOM_DOOR: + if (m_auiEncounter[TYPE_SNEED] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + + break; + case GO_FOUNDRY_DOOR: + if (m_auiEncounter[TYPE_GILNID] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + + break; + case GO_IRON_CLAD_DOOR: + if (m_auiEncounter[TYPE_IRON_CLAD_DOOR] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + + break; + case GO_DEFIAS_CANNON: + case GO_SMITE_CHEST: + case GO_MYSTERIOUS_CHEST: + break; + + default: + return; } - void OnCreatureCreate(Creature* pCreature) + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_deadmines::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - if (pCreature->GetEntry() == NPC_MR_SMITE) - m_uiSmiteGUID = pCreature->GetGUID(); + case NPC_RHAHKZOR: SetData(TYPE_RHAHKZOR, DONE); break; + case NPC_SNEED: SetData(TYPE_SNEED, DONE); break; + case NPC_GILNID: SetData(TYPE_GILNID, DONE); break; } +} - void OnObjectCreate(GameObject* pGo) +void instance_deadmines::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - if (pGo->GetEntry() == GO_IRON_CLAD) - m_uiIronCladGUID = pGo->GetGUID(); + case TYPE_RHAHKZOR: + { + if (uiData == DONE) + DoUseDoorOrButton(GO_FACTORY_DOOR); - if (pGo->GetEntry() == GO_DEFIAS_CANNON) - m_uiCannonGUID = pGo->GetGUID(); - } + m_auiEncounter[uiType] = uiData; + break; + } + case TYPE_SNEED: + { + if (uiData == DONE) + DoUseDoorOrButton(GO_MAST_ROOM_DOOR); - void SetData(uint32 uiType, uint32 uiData) - { - if (uiType == TYPE_DEFIAS_ENDDOOR) + m_auiEncounter[uiType] = uiData; + break; + } + case TYPE_GILNID: { - if (uiData == IN_PROGRESS) - { - if (GameObject* pGo = instance->GetGameObject(m_uiIronCladGUID)) - { - pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - m_uiIronDoor_Timer = 3000; - } - } - m_auiEncounter[0] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_FOUNDRY_DOOR); + + m_auiEncounter[uiType] = uiData; + break; + } + case TYPE_IRON_CLAD_DOOR: + { + // delayed door animation to sync with Defias Cannon animation + if (uiData == DONE) + m_uiIronDoorTimer = 500; + + m_auiEncounter[uiType] = uiData; + break; } } - uint32 GetData(uint32 uiType) + if (uiData == DONE) { - if (uiType == TYPE_DEFIAS_ENDDOOR) - return m_auiEncounter[0]; + OUT_SAVE_INST_DATA; - return 0; + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint64 GetData64(uint32 uiData) +uint32 instance_deadmines::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_deadmines::Load(const char* chrIn) +{ + if (!chrIn) { - if (uiData == DATA_DEFIAS_DOOR) - return m_uiIronCladGUID; + OUT_LOAD_INST_DATA_FAIL; + return; + } - return 0; + 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; } - void Update(uint32 uiDiff) + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_deadmines::Update(uint32 uiDiff) +{ + if (m_uiIronDoorTimer) { - if (m_uiIronDoor_Timer) + if (m_uiIronDoorTimer <= uiDiff) { - if (m_uiIronDoor_Timer <= uiDiff) + switch (m_uiDoorStep) { - if (Creature* pMrSmite = instance->GetCreature(m_uiSmiteGUID)) - { - switch(m_uiDoor_Step) + 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)) { - case 0: - DoScriptText(INST_SAY_ALARM1,pMrSmite); - m_uiIronDoor_Timer = 2000; - ++m_uiDoor_Step; - break; - case 1: - if (Creature* pi1 = pMrSmite->SummonCreature(NPC_PIRATE, 93.68f, -678.63f, 7.71f, 2.09f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 1800000)) - pi1->GetMotionMaster()->MovePoint(0, 100.11f, -670.65f, 7.42f); - if (Creature* pi2 = pMrSmite->SummonCreature(NPC_PIRATE, 102.63f, -685.07f, 7.42f, 1.28f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 1800000)) - pi2->GetMotionMaster()->MovePoint(0, 100.11f, -670.65f, 7.42f); - ++m_uiDoor_Step; - m_uiIronDoor_Timer = 10000; - break; - case 2: - DoScriptText(INST_SAY_ALARM2,pMrSmite); - m_uiDoor_Step = 0; - m_uiIronDoor_Timer = 0; - debug_log("SD2: Instance Deadmines: Iron door event reached end."); - break; + // 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()); + } } - } - else - m_uiIronDoor_Timer = 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_uiIronDoor_Timer -= uiDiff; } + else + m_uiIronDoorTimer -= uiDiff; } -}; +} InstanceData* GetInstanceData_instance_deadmines(Map* pMap) { @@ -143,9 +233,10 @@ InstanceData* GetInstanceData_instance_deadmines(Map* pMap) void AddSC_instance_deadmines() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_deadmines"; - newscript->GetInstanceData = &GetInstanceData_instance_deadmines; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_deadmines"; + pNewScript->GetInstanceData = &GetInstanceData_instance_deadmines; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/dun_morogh.cpp b/scripts/eastern_kingdoms/dun_morogh.cpp index ac2f7c64ba..7ed599272e 100644 --- a/scripts/eastern_kingdoms/dun_morogh.cpp +++ b/scripts/eastern_kingdoms/dun_morogh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 *newscript; - - newscript = new Script; - newscript->Name = "npc_narm_faulk"; - newscript->GetAI = &GetAI_npc_narm_faulk; - newscript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/eastern_plaguelands.cpp b/scripts/eastern_kingdoms/eastern_plaguelands.cpp index 5902066454..e8ad934b09 100644 --- a/scripts/eastern_kingdoms/eastern_plaguelands.cpp +++ b/scripts/eastern_kingdoms/eastern_plaguelands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,160 +17,353 @@ /* ScriptData SDName: Eastern_Plaguelands SD%Complete: 100 -SDComment: Quest support: 5211, 5742. Special vendor Augustus the Touched +SDComment: Quest support: 5742, 7622 SDCategory: Eastern Plaguelands EndScriptData */ /* ContentData -mobs_ghoul_flayer -npc_augustus_the_touched -npc_darrowshire_spirit npc_tirion_fordring +npc_eris_havenfire EndContentData */ #include "precompiled.h" -//id8530 - cannibal ghoul -//id8531 - gibbering ghoul -//id8532 - diseased flayer +/*###### +## npc_tirion_fordring +######*/ -struct MANGOS_DLL_DECL mobs_ghoul_flayerAI : public ScriptedAI +bool GossipHello_npc_tirion_fordring(Player* pPlayer, Creature* pCreature) { - mobs_ghoul_flayerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - void Reset() { } + 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); - 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); - } + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); -}; + return true; +} -CreatureAI* GetAI_mobs_ghoul_flayer(Creature* pCreature) +bool GossipSelect_npc_tirion_fordring(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) { - return new mobs_ghoul_flayerAI(pCreature); + switch(uiAction) + { + 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; + } + + return true; } -/*###### -## npc_augustus_the_touched +/*##### +## npc_eris_havenfire ######*/ -bool GossipHello_npc_augustus_the_touched(Player* pPlayer, Creature* pCreature) +enum { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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, - if (pCreature->isVendor() && pPlayer->GetQuestRewardStatus(6164)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + // 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, - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + 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 -bool GossipSelect_npc_augustus_the_touched(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) + QUEST_BALANCE_OF_LIGHT_AND_SHADOW = 7622, + + MAX_PEASANTS = 12, + MAX_ARCHERS = 8, +}; + +static const float aArcherSpawn[8][4] = { - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - return true; -} + {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 MANGOS_DLL_DECL npc_eris_havenfireAI : public ScriptedAI { - npc_darrowshire_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_eris_havenfireAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiEventTimer; + uint32 m_uiSadEndTimer; + uint8 m_uiPhase; + uint8 m_uiCurrentWave; + uint8 m_uiKillCounter; + uint8 m_uiSaveCounter; - void Reset() + 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->GetGUID()); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); - 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->GetGUID()); + if (uiPointId) + { + ++m_uiSaveCounter; + pSummoned->GetMotionMaster()->Clear(); - 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); + pSummoned->RemoveAllAuras(); + pSummoned->CastSpell(pSummoned, SPELL_ENTER_THE_LIGHT_DND, false); + pSummoned->ForcedDespawn(10000); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // Event ended + if (m_uiSaveCounter >= 50 && m_uiCurrentWave == 5) + DoBalanceEventEnd(); + // Phase ended + else if (m_uiSaveCounter + m_uiKillCounter == m_uiCurrentWave * MAX_PEASANTS) + DoHandlePhaseEnd(); + } + } - return true; + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_INJURED_PEASANT || pSummoned->GetEntry() == NPC_PLAGUED_PEASANT) + { + ++m_uiKillCounter; + + // 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); + + 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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; } void AddSC_eastern_plaguelands() { - Script *newscript; - - newscript = new Script; - newscript->Name = "mobs_ghoul_flayer"; - newscript->GetAI = &GetAI_mobs_ghoul_flayer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_augustus_the_touched"; - newscript->pGossipHello = &GossipHello_npc_augustus_the_touched; - newscript->pGossipSelect = &GossipSelect_npc_augustus_the_touched; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_darrowshire_spirit"; - newscript->GetAI = &GetAI_npc_darrowshire_spirit; - newscript->pGossipHello = &GossipHello_npc_darrowshire_spirit; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tirion_fordring"; - newscript->pGossipHello = &GossipHello_npc_tirion_fordring; - newscript->pGossipSelect = &GossipSelect_npc_tirion_fordring; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_tirion_fordring"; + pNewScript->pGossipHello = &GossipHello_npc_tirion_fordring; + pNewScript->pGossipSelect = &GossipSelect_npc_tirion_fordring; + + pNewScript = new Script; + 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 e4ffb29a27..7792479832 100644 --- a/scripts/eastern_kingdoms/elwynn_forest.cpp +++ b/scripts/eastern_kingdoms/elwynn_forest.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,76 +16,207 @@ /* ScriptData SDName: Elwynn_Forest -SD%Complete: 50 -SDComment: Quest support: 1786 +SD%Complete: 100 +SDComment: Hogger event SDCategory: Elwynn Forest EndScriptData */ /* ContentData -npc_henze_faulk +npc_hogger EndContentData */ #include "precompiled.h" /*###### -## npc_henze_faulk +## npc_hogger ######*/ -#define SAY_HEAL -1000187 +enum +{ + SAY_CALL_HELP = -1004000, + WHISPER_EATING = -1004001, // note: this type may need to be updated in the future + SAY_HOGGER_BEATEN = -1004002, + + SPELL_EATING = 87351, + SPELL_SUMMON_MINIONS = 87366, + SPELL_VICIOUS_SLICE = 87337, + SPELL_BLOODY_STRIKE = 87359, + + NPC_MINION_OF_HOOGER = 46932, + NPC_GENERAL_BUNNY = 45979, +}; -struct MANGOS_DLL_DECL npc_henze_faulkAI : public ScriptedAI +struct MANGOS_DLL_DECL npc_hoggerAI : public ScriptedAI { - uint32 lifeTimer; - bool spellHit; + npc_hoggerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiViciousSliceTimer; + uint32 m_uiEatingEndTimer; + uint32 m_uiBloodyStrikeTimer; + bool m_bHasSpawnedMinions; + bool m_bEncounterFinished; + + ObjectGuid m_bunnyGuid; + + void Reset() override + { + m_uiViciousSliceTimer = urand(15000, 20000); + m_uiEatingEndTimer = 0; + m_uiBloodyStrikeTimer = 1000; + m_bHasSpawnedMinions = false; + m_bEncounterFinished = false; + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + // start epilogue event + if (m_bEncounterFinished) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->GetMotionMaster()->MoveWaypoint(); + } + else + { + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + Reset(); + } + + m_creature->SetLootRecipient(NULL); + } + + void AttackStart(Unit* pWho) override + { + // special case for epilogue + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // special case for epilogue + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; - npc_henze_faulkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + ScriptedAI::MoveInLineOfSight(pWho); + } - void Reset() + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); // lay down - spellHit = false; + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + DoCastSpellIfCan(m_creature, SPELL_EATING); + m_uiEatingEndTimer = 12000; } - void MoveInLineOfSight(Unit *who) { } + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_MINION_OF_HOOGER) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } - void UpdateAI(const uint32 diff) + void DamageTaken(Unit* pDealer, uint32& uiDamage) override { - if (m_creature->IsStandState()) + // evade and start epilogue when near death + if (uiDamage >= m_creature->GetHealth()) { - if (lifeTimer < diff) + uiDamage = 0; + + if (!m_bEncounterFinished) + { + m_bEncounterFinished = true; m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; + DoScriptText(SAY_HOGGER_BEATEN, m_creature); + + if (pDealer->GetTypeId() == TYPEID_PLAYER) + ((Player*)pDealer)->KilledMonsterCredit(m_creature->GetEntry()); + } + } + + // start eating at 50% hp + if (!m_bHasSpawnedMinions && !m_bEncounterFinished && m_creature->GetHealthPercent() < 50.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_MINIONS) == CAST_OK) + { + DoScriptText(SAY_CALL_HELP, m_creature); + DoScriptText(WHISPER_EATING, m_creature, pDealer); + + SetCombatMovement(false); + if (Creature* pBunny = GetClosestCreatureWithEntry(m_creature, NPC_GENERAL_BUNNY, 25.0f)) + { + float fX, fY, fZ; + pBunny->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_bunnyGuid = pBunny->GetObjectGuid(); + } + + m_bHasSpawnedMinions = true; + } } } - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) + void UpdateAI(const uint32 uiDiff) override { - if (Spellkind->Id == 8593 && !spellHit) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // resume combat after eat + if (m_uiEatingEndTimer) + { + if (m_uiEatingEndTimer <= uiDiff) + { + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_uiEatingEndTimer = 0; + } + else + m_uiEatingEndTimer -= uiDiff; + + if (m_uiBloodyStrikeTimer < uiDiff) + { + if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_bunnyGuid)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BLOODY_STRIKE) == CAST_OK) + m_uiBloodyStrikeTimer = 2000; + } + } + else + m_uiBloodyStrikeTimer -= uiDiff; + + return; + } + + if (m_uiViciousSliceTimer < uiDiff) { - 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; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_VICIOUS_SLICE) == CAST_OK) + m_uiViciousSliceTimer = urand(15000, 20000); } - } + else + m_uiViciousSliceTimer -= uiDiff; + DoMeleeAttackIfReady(); + } }; -CreatureAI* GetAI_npc_henze_faulk(Creature* pCreature) + +CreatureAI* GetAI_npc_hogger(Creature* pCreature) { - return new npc_henze_faulkAI(pCreature); + return new npc_hoggerAI(pCreature); } void AddSC_elwynn_forest() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_henze_faulk"; - newscript->GetAI = &GetAI_npc_henze_faulk; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_hogger"; + pNewScript->GetAI = &GetAI_npc_hogger; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/eversong_woods.cpp b/scripts/eastern_kingdoms/eversong_woods.cpp index 0f56491ec9..0731b83fab 100644 --- a/scripts/eastern_kingdoms/eversong_woods.cpp +++ b/scripts/eastern_kingdoms/eversong_woods.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Eversong_Woods SD%Complete: 100 -SDComment: Quest support: 8483, 8488, 9686 +SDComment: Quest support: 8483, 8488, 8490, 9686 SDCategory: Eversong Woods EndScriptData */ @@ -26,10 +26,12 @@ npc_kelerun_bloodmourn go_harbinger_second_trial npc_prospector_anvilward npc_apprentice_mirveda +npc_infused_crystal EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "TemporarySummon.h" /*###### ## npc_kelerun_bloodmourn @@ -58,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}, @@ -75,8 +77,8 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI } uint32 m_uiNpcFlags; - uint64 m_uiPlayerGUID; - uint64 uiChallengerGUID[MAX_CHALLENGER]; + ObjectGuid m_playerGuid; + ObjectGuid m_aChallengerGuids[MAX_CHALLENGER]; uint8 m_uiChallengerCount; @@ -90,9 +92,7 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI { m_creature->SetUInt32Value(UNIT_NPC_FLAGS, m_uiNpcFlags); - m_uiPlayerGUID = 0; - - memset(&uiChallengerGUID, 0, sizeof(uiChallengerGUID)); + m_playerGuid.Clear(); m_uiChallengerCount = 0; @@ -101,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() @@ -109,11 +115,11 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI m_bIsEventInProgress = true; } - bool CanProgressEvent(uint64 uiPlayer) + bool CanProgressEvent(Player* pPlayer) { if (m_bIsEventInProgress) { - m_uiPlayerGUID = uiPlayer; + m_playerGuid = pPlayer->GetObjectGuid(); DoSpawnChallengers(); m_uiEngageTimer = 15000; @@ -125,89 +131,90 @@ 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)) { - uiChallengerGUID[i] = pCreature->GetGUID(); + m_aChallengerGuids[i] = pCreature->GetObjectGuid(); pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } } } - 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_uiPlayerGUID) + 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(uiChallengerGUID[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_uiPlayerGUID); - - 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_uiPlayerGUID); - - if (pPlayer && pPlayer->isAlive()) + if (m_uiEngageTimer <= uiDiff) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(uiChallengerGUID[m_uiChallengerCount])) + 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; } } }; @@ -217,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) { @@ -229,15 +236,14 @@ bool QuestAccept_npc_kelerun_bloodmourn(Player* pPlayer, Creature* pCreature, co return true; } -bool GOHello_go_harbinger_second_trial(Player* pPlayer, GameObject* pGO) +bool GOUse_go_harbinger_second_trial(Player* pPlayer, GameObject* pGO) { if (pGO->GetGoType() == GAMEOBJECT_TYPE_GOOBER) { if (Creature* pCreature = GetClosestCreatureWithEntry(pGO, NPC_KELERUN, 30.0f)) { - npc_kelerun_bloodmournAI* pKelrunAI = dynamic_cast(pCreature->AI()); - if (pKelrunAI && pKelrunAI->CanProgressEvent(pPlayer->GetGUID())) - return false; + if (npc_kelerun_bloodmournAI* pKelrunAI = dynamic_cast(pCreature->AI())) + pKelrunAI->CanProgressEvent(pPlayer); } } @@ -252,7 +258,12 @@ 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 @@ -263,8 +274,10 @@ struct MANGOS_DLL_DECL npc_prospector_anvilwardAI : public npc_escortAI // CreatureAI functions npc_prospector_anvilwardAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} + void Reset() { } + // Pure Virtual Functions - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); @@ -280,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) @@ -303,31 +305,28 @@ 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->GetGUID()); + 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->GetGUID()); + 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(); if (npc_prospector_anvilwardAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID()); + pEscortAI->Start(false, pPlayer); break; } @@ -350,62 +349,62 @@ enum struct MANGOS_DLL_DECL npc_apprentice_mirvedaAI : public ScriptedAI { - npc_apprentice_mirvedaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_apprentice_mirvedaAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint8 m_uiMobCount; uint32 m_uiFireballTimer; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; void Reset() { m_uiMobCount = 0; - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_uiFireballTimer = 0; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (pPlayer && pPlayer->GetQuestStatus(QUEST_UNEXPECTED_RESULT) == QUEST_STATUS_INCOMPLETE) 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; if (m_uiMobCount) return; - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (pPlayer && pPlayer->GetQuestStatus(QUEST_UNEXPECTED_RESULT) == QUEST_STATUS_INCOMPLETE) pPlayer->GroupEventHappens(QUEST_UNEXPECTED_RESULT, m_creature); - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } - void StartEvent(uint64 uiPlayerGUID) + void StartEvent(Player* pPlayer) { m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - m_uiPlayerGUID = uiPlayerGUID; + m_playerGuid = pPlayer->GetObjectGuid(); m_creature->SummonCreature(NPC_GHARSUL, 8745.0f, -7134.32f, 35.22f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 4000); m_creature->SummonCreature(NPC_ANGERSHADE, 8745.0f, -7134.32f, 35.22f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 4000); 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; @@ -425,13 +424,113 @@ bool QuestAccept_unexpected_results(Player* pPlayer, Creature* pCreature, const { if (pQuest->GetQuestId() == QUEST_UNEXPECTED_RESULT) if (npc_apprentice_mirvedaAI* pMirvedaAI = dynamic_cast(pCreature->AI())) - pMirvedaAI->StartEvent(pPlayer->GetGUID()); + pMirvedaAI->StartEvent(pPlayer); return true; } CreatureAI* GetAI_npc_apprentice_mirvedaAI(Creature* pCreature) { - return new npc_apprentice_mirvedaAI (pCreature); + return new npc_apprentice_mirvedaAI(pCreature); +} + +/*###### +## npc_infused_crystal +######*/ + +enum +{ + QUEST_POWERING_OUR_DEFENSES = 8490, + SAY_DEFENSE_FINISH = -1000668, + NPC_ENRAGED_WRAITH = 17086, +}; + +float fEnragedWrathPosition[3][4] = +{ + {8259.375977f, -7202.288574f, 139.287430f, 5.0f}, + {8255.425781f, -7222.026367f, 139.607162f, 5.0f}, + {8267.902344f, -7193.510742f, 139.430374f, 5.0f} +}; + +struct MANGOS_DLL_DECL npc_infused_crystalAI : public ScriptedAI +{ + npc_infused_crystalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + Reset(); + } + + uint32 m_uiQuestTimer; + uint32 m_uiSpawnTimer; + ObjectGuid m_uiPlayerGUID; + + bool bCompleted; + + void Reset() + { + m_uiQuestTimer = 60000; + m_uiSpawnTimer = 1000; + m_uiPlayerGUID.Clear(); + bCompleted = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (pWho->GetTypeId() != TYPEID_PLAYER) + return; + Player* pPlayer = (Player*)pWho; + + if (pPlayer->GetQuestStatus(QUEST_POWERING_OUR_DEFENSES) != QUEST_STATUS_INCOMPLETE) + return; + + m_uiPlayerGUID = pPlayer->GetObjectGuid(); + } + + void Aggro(Unit* pWho){} + + void JustDied(Unit* pWho) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (pPlayer->GetQuestStatus(QUEST_POWERING_OUR_DEFENSES) == QUEST_STATUS_INCOMPLETE) + pPlayer->FailQuest(QUEST_POWERING_OUR_DEFENSES); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (bCompleted) + return; + + if (m_uiSpawnTimer < uiDiff) + { + for (uint8 i = 0; i < 3; ++i) + { + if (Creature* pEnragedWrath = m_creature->SummonCreature(NPC_ENRAGED_WRAITH, fEnragedWrathPosition[i][0], fEnragedWrathPosition[i][1], fEnragedWrathPosition[i][2], fEnragedWrathPosition[i][3], TEMPSUMMON_TIMED_OOC_DESPAWN, 5000)) + { + pEnragedWrath->AI()->AttackStart(m_creature); + } + } + m_uiSpawnTimer = 40000; + } + else + m_uiSpawnTimer -= uiDiff; + + if (m_uiQuestTimer < uiDiff) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + { + pPlayer->KilledMonsterCredit(m_creature->GetEntry()); + DoScriptText(SAY_DEFENSE_FINISH, m_creature); + m_creature->ForcedDespawn(5000); + } + bCompleted = true; + } + else + m_uiQuestTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_infused_crystalAI(Creature* pCreature) +{ + return new npc_infused_crystalAI(pCreature); } void AddSC_eversong_woods() @@ -441,12 +540,12 @@ void AddSC_eversong_woods() pNewScript = new Script; pNewScript->Name = "npc_kelerun_bloodmourn"; pNewScript->GetAI = &GetAI_npc_kelerun_bloodmourn; - pNewScript->pQuestAccept = &QuestAccept_npc_kelerun_bloodmourn; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kelerun_bloodmourn; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "go_harbinger_second_trial"; - pNewScript->pGOHello = &GOHello_go_harbinger_second_trial; + pNewScript->pGOUse = &GOUse_go_harbinger_second_trial; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -458,7 +557,12 @@ void AddSC_eversong_woods() pNewScript = new Script; pNewScript->Name = "npc_apprentice_mirveda"; - pNewScript->GetAI = GetAI_npc_apprentice_mirvedaAI; - pNewScript->pQuestAccept = &QuestAccept_unexpected_results; + pNewScript->GetAI = &GetAI_npc_apprentice_mirvedaAI; + pNewScript->pQuestAcceptNPC = &QuestAccept_unexpected_results; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_infused_crystal"; + pNewScript->GetAI = &GetAI_npc_infused_crystalAI; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/ghostlands.cpp b/scripts/eastern_kingdoms/ghostlands.cpp index 5731842834..d600f0f49e 100644 --- a/scripts/eastern_kingdoms/ghostlands.cpp +++ b/scripts/eastern_kingdoms/ghostlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,76 +17,17 @@ /* ScriptData SDName: Ghostlands SD%Complete: 100 -SDComment: Quest support: 9212, 9692. Obtain Budd's Guise of Zul'aman. Vendor Rathis Tomber +SDComment: Quest support: 9212. SDCategory: Ghostlands EndScriptData */ /* ContentData -npc_blood_knight_dawnstar -npc_budd_nedreck npc_ranger_lilatha -npc_rathis_tomber EndContentData */ #include "precompiled.h" #include "escort_ai.h" -/*###### -## npc_blood_knight_dawnstar -######*/ - -#define GOSSIP_ITEM_INSIGNIA "Take Blood Knight Insignia" - -bool GossipHello_npc_blood_knight_dawnstar(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(9692) == QUEST_STATUS_INCOMPLETE && !pPlayer->HasItemCount(24226,1,true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,GOSSIP_ITEM_INSIGNIA,GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_blood_knight_dawnstar(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(24226, 1)) - pPlayer->SendNewItem(pItem, 1, true, false); - - pPlayer->CLOSE_GOSSIP_MENU(); - } - return true; -} - -/*###### -## npc_budd_nedreck -######*/ - -#define GOSSIP_ITEM_DISGUISE "You gave the crew disguises?" - -bool GossipHello_npc_budd_nedreck(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(11166) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,GOSSIP_ITEM_DISGUISE,GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_budd_nedreck(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction==GOSSIP_ACTION_INFO_DEF) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, 42540, false); - } - return true; -} - /*###### ## npc_ranger_lilatha ######*/ @@ -109,43 +50,38 @@ enum struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI { - npc_ranger_lilathaAI(Creature* pCreature) : npc_escortAI(pCreature) - { - m_uiGoCageGUID = 0; - m_uiHeliosGUID = 0; - Reset(); - } + npc_ranger_lilathaAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - uint64 m_uiGoCageGUID; - uint64 m_uiHeliosGUID; + ObjectGuid m_goCageGuid; + ObjectGuid m_heliosGuid; - void MoveInLineOfSight(Unit* pUnit) + void MoveInLineOfSight(Unit* pUnit) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { - if (!m_uiHeliosGUID && pUnit->GetEntry() == NPC_CAPTAIN_HELIOS) + if (!m_heliosGuid && pUnit->GetEntry() == NPC_CAPTAIN_HELIOS) { if (m_creature->IsWithinDistInMap(pUnit, 30.0f)) - m_uiHeliosGUID = pUnit->GetGUID(); + m_heliosGuid = pUnit->GetObjectGuid(); } } 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)) { - m_uiGoCageGUID = pGoTemp->GetGUID(); + m_goCageGuid = pGoTemp->GetObjectGuid(); pGoTemp->SetGoState(GO_STATE_ACTIVE); } @@ -154,7 +90,7 @@ struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI DoScriptText(SAY_START, m_creature, pPlayer); break; case 1: - if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_uiGoCageGUID)) + if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_goCageGuid)) pGo->SetGoState(GO_STATE_READY); break; case 5: @@ -184,7 +120,7 @@ struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI break; case 33: DoScriptText(SAY_END2, m_creature, pPlayer); - if (Creature* pHelios = m_creature->GetMap()->GetCreature(m_uiHeliosGUID)) + if (Creature* pHelios = m_creature->GetMap()->GetCreature(m_heliosGuid)) DoScriptText(CAPTAIN_ANSWER, pHelios, m_creature); break; } @@ -194,8 +130,8 @@ struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { - m_uiGoCageGUID = 0; - m_uiHeliosGUID = 0; + m_goCageGuid.Clear(); + m_heliosGuid.Clear(); } } }; @@ -209,66 +145,21 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } -/*###### -## npc_rathis_tomber -######*/ - -bool GossipHello_npc_rathis_tomber(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pCreature->isVendor() && pPlayer->GetQuestRewardStatus(9152)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(8432, pCreature->GetGUID()); - }else - pPlayer->SEND_GOSSIP_MENU(8431, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_rathis_tomber(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - - return true; -} - void AddSC_ghostlands() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_blood_knight_dawnstar"; - newscript->pGossipHello = &GossipHello_npc_blood_knight_dawnstar; - newscript->pGossipSelect = &GossipSelect_npc_blood_knight_dawnstar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_budd_nedreck"; - newscript->pGossipHello = &GossipHello_npc_budd_nedreck; - newscript->pGossipSelect = &GossipSelect_npc_budd_nedreck; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_ranger_lilatha"; - newscript->GetAI = &GetAI_npc_ranger_lilathaAI; - newscript->pQuestAccept = &QuestAccept_npc_ranger_lilatha; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_rathis_tomber"; - newscript->pGossipHello = &GossipHello_npc_rathis_tomber; - newscript->pGossipSelect = &GossipSelect_npc_rathis_tomber; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_ranger_lilatha"; + pNewScript->GetAI = &GetAI_npc_ranger_lilathaAI; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_ranger_lilatha; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/gilneas.cpp b/scripts/eastern_kingdoms/gilneas.cpp new file mode 100644 index 0000000000..c364581272 --- /dev/null +++ b/scripts/eastern_kingdoms/gilneas.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Gilneas +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gilneas +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_gilneas() +{ +} diff --git a/scripts/eastern_kingdoms/gilneas_city.cpp b/scripts/eastern_kingdoms/gilneas_city.cpp new file mode 100644 index 0000000000..f4e8c9821e --- /dev/null +++ b/scripts/eastern_kingdoms/gilneas_city.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Gilneas City +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gilneas City +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_gilneas_city() +{ +} diff --git a/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp b/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp index ef785322f8..7fe1476bac 100644 --- a/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp +++ b/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -59,8 +59,8 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI sBombFace* m_asBombFaces; float m_afSpawnPos[3]; - std::list m_lSummonedBombGUIDs; - std::list m_lLandedBombGUIDs; + GuidList m_lSummonedBombGUIDs; + GuidList m_lLandedBombGUIDs; void Reset() { @@ -73,12 +73,23 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI m_lLandedBombGUIDs.clear(); } - void KilledUnit(Unit* pVictim) + void GetAIInformation(ChatHandler& reader) override + { + reader.PSendSysMessage("Thermaplugg, currently phase %s", m_bIsPhaseTwo ? "two" : "one"); + + if (m_asBombFaces) + { + for (uint8 i = 0; i < MAX_GNOME_FACES; ++i) + reader.PSendSysMessage("Bomb face %u is %s ", (uint32)i, m_asBombFaces[i].m_bActivated ? "activated" : "not activated"); + } + } + + 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); @@ -86,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); @@ -101,45 +112,49 @@ 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); + if (!m_pInstance || m_pInstance->GetData(TYPE_THERMAPLUGG) == FAIL) + return; + + m_pInstance->SetData(TYPE_THERMAPLUGG,FAIL); + // Remove remaining bombs - for (std::list::const_iterator itr = m_lSummonedBombGUIDs.begin(); itr != m_lSummonedBombGUIDs.end(); itr++) + while (!m_lSummonedBombGUIDs.empty()) { - if (Creature* pBomb = m_creature->GetMap()->GetCreature(*itr)) + ObjectGuid guid = m_lSummonedBombGUIDs.back(); + m_lSummonedBombGUIDs.pop_back(); + if (Creature* pBomb = m_creature->GetMap()->GetCreature(guid)) pBomb->ForcedDespawn(); } - m_lSummonedBombGUIDs.clear(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_WALKING_BOMB) { - m_lSummonedBombGUIDs.push_back(pSummoned->GetGUID()); + 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->GetGUID()); + m_lLandedBombGUIDs.push_back(pSummoned->GetObjectGuid()); } - void SummonedCreatureDespawn(Creature* pSummoned) + void SummonedCreatureDespawn(Creature* pSummoned) override { - m_lSummonedBombGUIDs.remove(pSummoned->GetGUID()); + m_lSummonedBombGUIDs.remove(pSummoned->GetObjectGuid()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -147,7 +162,7 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI // Movement of Summoned mobs if (!m_lLandedBombGUIDs.empty()) { - for (std::list::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); @@ -181,7 +196,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); } @@ -192,7 +207,7 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI // Spawn bombs if (m_asBombFaces) { - for (uint8 i = 0; i < MAX_GNOME_FACES; i++) + for (uint8 i = 0; i < MAX_GNOME_FACES; ++i) { if (m_asBombFaces[i].m_bActivated) { @@ -200,10 +215,10 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI { // Calculate the spawning position as 90% between face and thermaplugg spawn-pos, and hight hardcoded float fX = 0.0f, fY = 0.0f; - if (GameObject* pFace = m_creature->GetMap()->GetGameObject(m_asBombFaces[i].m_uiGnomeFaceGUID)) + 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 @@ -223,7 +238,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; @@ -235,7 +250,7 @@ bool EffectDummyCreature_spell_boss_thermaplugg(Unit* pCaster, uint32 uiSpellId, return true; } -bool GOHello_go_gnomeface_button(Player* pPlayer, GameObject* pGo) +bool GOUse_go_gnomeface_button(Player* pPlayer, GameObject* pGo) { instance_gnomeregan* pInstance = (instance_gnomeregan*)pPlayer->GetInstanceData(); if (!pInstance) @@ -262,11 +277,11 @@ void AddSC_boss_thermaplugg() pNewScript = new Script; pNewScript->Name = "boss_thermaplugg"; pNewScript->GetAI = &GetAI_boss_thermaplugg; - pNewScript->pEffectDummyCreature = &EffectDummyCreature_spell_boss_thermaplugg; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_boss_thermaplugg; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "go_gnomeface_button"; - pNewScript->pGOHello = &GOHello_go_gnomeface_button; + pNewScript->pGOUse = &GOUse_go_gnomeface_button; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp index 981678bb93..6f7fb49666 100644 --- a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp +++ b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,18 +16,20 @@ /* ScriptData SDName: gnomeregan -SD%Complete: 80 -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 @@ -42,7 +44,7 @@ enum SAY_INTRO_4 = -1090004, SAY_LOOK_1 = -1090005, SAY_HEAR_1 = -1090006, - SAY_AGGRO = -1090007, + SAY_AGGRO_1 = -1090007, SAY_CHARGE_1 = -1090008, SAY_CHARGE_2 = -1090009, SAY_BLOW_1_10 = -1090010, @@ -59,6 +61,8 @@ enum SAY_BLOW_2 = -1090021, SAY_FINISH_2 = -1090022, + SAY_AGGRO_2 = -1090028, + SAY_GRUBBIS_SPAWN = -1090023, GOSSIP_ITEM_START = -3090000, @@ -75,6 +79,644 @@ enum NPC_CAVERNDEEP_AMBUSHER = 6207 }; +struct sSummonInformation +{ + uint32 uiPosition, uiEntry; + float fX, fY, fZ, fO; +}; + +static const sSummonInformation asSummonInfo[MAX_SUMMON_POSITIONS] = +{ + // Entries must be sorted by pack + // First Cave-In + {1, NPC_CAVERNDEEP_AMBUSHER, -566.8114f, -111.7036f, -151.1891f, 5.986479f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -568.5875f, -113.7559f, -151.1869f, 0.06981317f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -570.2333f, -116.8126f, -151.2272f, 0.296706f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -550.6331f, -108.7592f, -153.965f, 0.8901179f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -558.9717f, -115.0669f, -151.8799f, 0.5235988f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -556.6719f, -112.0526f, -152.8255f, 0.4886922f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -552.6419f, -113.4385f, -153.0727f, 0.8028514f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -549.1248f, -112.1469f, -153.7987f, 0.7504916f}, + {1, NPC_CAVERNDEEP_AMBUSHER, -546.7435f, -112.3051f, -154.2225f, 0.9250245f}, + {2, NPC_CAVERNDEEP_AMBUSHER, -571.4071f, -108.7721f, -150.6547f, 5.480334f}, + {2, NPC_CAVERNDEEP_AMBUSHER, -573.797f, -106.5265f, -150.4106f, 5.550147f}, + {2, NPC_CAVERNDEEP_AMBUSHER, -576.3784f, -108.0483f, -150.4227f, 5.585053f}, + {2, NPC_CAVERNDEEP_AMBUSHER, -576.697f, -111.7413f, -150.6484f, 5.759586f}, + {3, NPC_CAVERNDEEP_AMBUSHER, -571.3161f, -114.4412f, -151.0931f, 6.021386f}, + {3, NPC_CAVERNDEEP_AMBUSHER, -570.3127f, -111.7964f, -151.04f, 2.042035f}, + + // Second Cave-In + {4, NPC_CAVERNDEEP_AMBUSHER, -474.5954f, -104.074f, -146.0483f, 2.338741f}, + {4, NPC_CAVERNDEEP_AMBUSHER, -477.9396f, -108.6563f, -145.7394f, 1.553343f}, + {4, NPC_CAVERNDEEP_AMBUSHER, -475.6625f, -97.12168f, -146.5959f, 1.291544f}, + {4, NPC_CAVERNDEEP_AMBUSHER, -480.5233f, -88.40702f, -146.3772f, 3.001966f}, + {5, NPC_CAVERNDEEP_AMBUSHER, -474.2943f, -105.2212f, -145.9747f, 2.251475f}, + {5, NPC_CAVERNDEEP_AMBUSHER, -481.1831f, -101.4225f, -146.377f, 2.146755f}, + {5, NPC_CAVERNDEEP_BURROWER, -475.0871f, -100.016f, -146.4382f, 2.303835f}, + {5, NPC_CAVERNDEEP_AMBUSHER, -478.8562f, -106.9321f, -145.8533f, 1.658063f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -473.8762f, -107.4022f, -145.838f, 2.024582f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -490.5134f, -92.72843f, -148.0954f, 3.054326f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -491.401f, -88.25341f, -148.0358f, 3.560472f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -479.1431f, -106.227f, -145.9097f, 1.727876f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -475.3185f, -101.4804f, -146.2717f, 2.234021f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -485.1559f, -89.57419f, -146.9299f, 3.071779f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -482.2516f, -96.80614f, -146.6596f, 2.303835f}, + {6, NPC_CAVERNDEEP_AMBUSHER, -477.9874f, -92.82047f, -146.6944f, 3.124139f}, + + // Grubbis and add + {7, NPC_GRUBBIS, -476.3761f, -108.1901f, -145.7763f, 1.919862f}, + {7, NPC_CHOMPER, -473.1326f, -103.0901f, -146.1155f, 2.042035f} +}; + +struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI +{ + npc_blastmaster_emi_shortfuseAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (instance_gnomeregan*)pCreature->GetInstanceData(); + // Remove Gossip-Menu in reload case for DONE enounter + if (m_pInstance && m_pInstance->GetData(TYPE_GRUBBIS) == DONE) + pCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + Reset(); + } + + instance_gnomeregan* m_pInstance; + + uint8 m_uiPhase; + uint32 m_uiPhaseTimer; + ObjectGuid m_playerGuid; + bool m_bDidAggroText, m_bSouthernCaveInOpened, m_bNorthernCaveInOpened; + GuidList m_luiSummonedMobGUIDs; + + void Reset() + { + m_bDidAggroText = false; // Used for 'defend' text, is triggered when the npc is attacked + + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiPhase = 0; + m_uiPhaseTimer = 0; + m_bSouthernCaveInOpened = m_bNorthernCaveInOpened = false; + m_luiSummonedMobGUIDs.clear(); + } + } + + void DoSummonPack(uint8 uiIndex) + { + for (uint8 i = 0; i < MAX_SUMMON_POSITIONS; ++i) + { + // This requires order of the array + if (asSummonInfo[i].uiPosition > uiIndex) + break; + if (asSummonInfo[i].uiPosition == uiIndex) + m_creature->SummonCreature(asSummonInfo[i].uiEntry, asSummonInfo[i].fX, asSummonInfo[i].fY, asSummonInfo[i].fZ, asSummonInfo[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_CAVERNDEEP_BURROWER: + case NPC_CAVERNDEEP_AMBUSHER: + { + 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)); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + break; + } + case NPC_GRUBBIS: + // Movement of Grubbis and Add to be handled by DB waypoints + DoScriptText(SAY_GRUBBIS_SPAWN, pSummoned); + break; + } + m_luiSummonedMobGUIDs.push_back(pSummoned->GetObjectGuid()); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_GRUBBIS) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GRUBBIS, DONE); + m_uiPhaseTimer = 1000; + } + m_luiSummonedMobGUIDs.remove(pSummoned->GetObjectGuid()); + } + + bool IsPreparingExplosiveCharge() + { + return m_uiPhase == 11 || m_uiPhase == 13 || m_uiPhase == 26 || m_uiPhase == 28; + } + + void MoveInLineOfSight(Unit* pWho) override + { + // In case we are preparing the explosive charges, we won't start attacking mobs + if (IsPreparingExplosiveCharge()) + return; + + npc_escortAI::MoveInLineOfSight(pWho); + } + + void AttackStart(Unit* pWho) override + { + // In case we are preparing the explosive charges, we won't start attacking mobs + if (IsPreparingExplosiveCharge()) + return; + + npc_escortAI::AttackStart(pWho); + } + + void AttackedBy(Unit* pAttacker) override + { + // Possibility for Aggro-Text only once per combat + if (m_bDidAggroText) + return; + + m_bDidAggroText = true; + + if (!urand(0, 2)) + DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature, pAttacker); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_GRUBBIS, FAIL); + + if (m_bSouthernCaveInOpened) // close southern cave-in door + m_pInstance->DoUseDoorOrButton(GO_CAVE_IN_SOUTH); + 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) + { + if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) + pSummoned->ForcedDespawn(); + } + } + + void StartEvent(Player* pPlayer) + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_GRUBBIS, IN_PROGRESS); + + m_uiPhase = 1; + m_uiPhaseTimer = 1000; + m_playerGuid = pPlayer->GetObjectGuid(); + } + + void WaypointStart(uint32 uiPointId) override + { + switch (uiPointId) + { + case 10: + // Open Southern Cave-In + if (m_pInstance && !m_bSouthernCaveInOpened) + m_pInstance->DoUseDoorOrButton(GO_CAVE_IN_SOUTH); + m_bSouthernCaveInOpened = true; + break; + case 12: + DoScriptText(SAY_CHARGE_1, m_creature); + break; + case 16: + DoScriptText(SAY_CHARGE_3, m_creature); + // Open Northern Cave-In + if (m_pInstance && !m_bNorthernCaveInOpened) + m_pInstance->DoUseDoorOrButton(GO_CAVE_IN_NORTH); + m_bNorthernCaveInOpened = true; + break; + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 4: + m_uiPhaseTimer = 1000; + break; + case 9: + m_uiPhaseTimer = 2000; + break; + case 11: + m_creature->HandleEmote(EMOTE_STATE_USESTANDING); + m_uiPhaseTimer = 15000; + break; + case 13: + m_creature->HandleEmote(EMOTE_STATE_USESTANDING); + m_uiPhaseTimer = 10000; + break; + case 15: + SetEscortPaused(true); + if (m_pInstance) + { + if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_CAVE_IN_SOUTH)) + m_creature->SetFacingToObject(pDoor); + } + DoScriptText(SAY_BLOW_1_10, m_creature); + m_uiPhaseTimer = 5000; + break; + case 16: + m_creature->HandleEmote(EMOTE_STATE_USESTANDING); + m_uiPhaseTimer = 15000; + break; + case 17: + m_creature->HandleEmote(EMOTE_STATE_USESTANDING); + m_uiPhaseTimer = 10000; + break; + case 19: + m_uiPhaseTimer = 2000; + SetEscortPaused(true); // And keep paused from now on! + break; + } + } + + void UpdateEscortAI(uint32 const uiDiff) override + { + // the phases are handled OOC (keeps them in sync with the waypoints) + if (m_uiPhaseTimer && !m_creature->getVictim()) + { + if (m_uiPhaseTimer <= uiDiff) + { + switch (m_uiPhase) + { + case 1: + DoScriptText(SAY_START, m_creature); + 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; + break; + case 2: + DoScriptText(SAY_INTRO_1, m_creature); + m_uiPhaseTimer = 3500; // 6s delay, but 2500ms for escortstarting + break; + case 3: + Start(false, m_creature->GetMap()->GetPlayer(m_playerGuid), NULL, false, false); + m_uiPhaseTimer = 0; + break; + + case 4: // Shortly after reached WP 4 + DoScriptText(SAY_INTRO_2, m_creature); + m_uiPhaseTimer = 0; + break; + + case 5: // Shortly after reached WP 9 + DoScriptText(SAY_INTRO_3, m_creature); + m_uiPhaseTimer = 6000; + break; + case 6: + DoScriptText(SAY_INTRO_4, m_creature); + m_uiPhaseTimer = 9000; + break; + case 7: + if (m_pInstance) + { + if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_CAVE_IN_SOUTH)) + m_creature->SetFacingToObject(pDoor); + } + m_uiPhaseTimer = 2000; + break; + case 8: + DoScriptText(SAY_LOOK_1, m_creature); + m_uiPhaseTimer = 5000; + break; + case 9: + DoScriptText(SAY_HEAR_1, m_creature); + m_uiPhaseTimer = 2000; + break; + case 10: // Shortly shortly before starting WP 11 + DoSummonPack(1); + m_uiPhaseTimer = 0; + break; + + case 11: // 15s after reached WP 11 + DoSummonPack(2); + + // Summon first explosive charge + if (m_pInstance) + m_pInstance->SetData(TYPE_EXPLOSIVE_CHARGE, DATA_EXPLOSIVE_CHARGE_1); + // Remove EMOTE_STATE_USESTANDING state-emote + m_creature->HandleEmote(EMOTE_ONESHOT_NONE); + + m_uiPhaseTimer = 1; + break; + case 12: // Empty Phase, used to store information about set charge + m_uiPhaseTimer = 0; + break; + + case 13: // 10s after reached WP 13 + DoSummonPack(3); + + // Summon second explosive charge + if (m_pInstance) + m_pInstance->SetData(TYPE_EXPLOSIVE_CHARGE, DATA_EXPLOSIVE_CHARGE_2); + // Remove EMOTE_STATE_USESTANDING state-emote + m_creature->HandleEmote(EMOTE_ONESHOT_NONE); + + m_uiPhaseTimer = 11000; + break; + case 14: // Empty Phase, used to store information about set charge + m_uiPhaseTimer = 1; + break; + case 15: // shortly before starting WP 14 + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + m_creature->SetFacingToObject(pPlayer); + DoScriptText(SAY_CHARGE_2, m_creature); + m_uiPhaseTimer = 0; + break; + + case 16: // 5s after reaching WP 15 + DoScriptText(SAY_BLOW_1_5, m_creature); + m_uiPhaseTimer = 5000; + break; + case 17: + DoScriptText(SAY_BLOW_1, m_creature); + m_uiPhaseTimer = 1000; + break; + case 18: + DoCastSpellIfCan(m_creature, SPELL_EXPLOSION_SOUTH); + m_uiPhaseTimer = 500; + break; + case 19: + // Close southern cave-in and let charges explode + if (m_pInstance) + { + m_pInstance->DoUseDoorOrButton(GO_CAVE_IN_SOUTH); + m_bSouthernCaveInOpened = false; + m_pInstance->SetData(TYPE_EXPLOSIVE_CHARGE, DATA_EXPLOSIVE_CHARGE_USE); + } + m_uiPhaseTimer = 5000; + break; + case 20: + m_creature->HandleEmote(EMOTE_ONESHOT_CHEER); + m_uiPhaseTimer = 6000; + break; + case 21: + DoScriptText(SAY_FINISH_1, m_creature); + m_uiPhaseTimer = 6000; + break; + case 22: + DoScriptText(SAY_LOOK_2, m_creature); + m_uiPhaseTimer = 3000; + break; + case 23: + if (m_pInstance) + { + if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_CAVE_IN_NORTH)) + m_creature->SetFacingToObject(pDoor); + } + m_uiPhaseTimer = 3000; + break; + case 24: + DoScriptText(SAY_HEAR_2, m_creature); + m_uiPhaseTimer = 8000; + break; + case 25: // shortly before starting WP 16 + SetEscortPaused(false); + DoSummonPack(4); + m_uiPhaseTimer = 0; + break; + + case 26: // 15s after reaching WP 16 + DoSummonPack(5); + + // Summon third explosive charge + if (m_pInstance) + m_pInstance->SetData(TYPE_EXPLOSIVE_CHARGE, DATA_EXPLOSIVE_CHARGE_3); + // Remove EMOTE_STATE_USESTANDING state-emote + m_creature->HandleEmote(EMOTE_ONESHOT_NONE); + + m_uiPhaseTimer = 1; + break; + case 27: // Empty Phase, used to store information about set charge + m_uiPhaseTimer = 0; + break; + + case 28: // 10s after reaching WP 17 + DoSummonPack(6); + + // Summon forth explosive charge + if (m_pInstance) + m_pInstance->SetData(TYPE_EXPLOSIVE_CHARGE, DATA_EXPLOSIVE_CHARGE_4); + // Remove EMOTE_STATE_USESTANDING state-emote + m_creature->HandleEmote(EMOTE_ONESHOT_NONE); + + m_uiPhaseTimer = 10000; + break; + case 29: // Empty Phase, used to store information about set charge + m_uiPhaseTimer = 1; + break; + case 30: // shortly before starting WP 18 + DoScriptText(SAY_CHARGE_4, m_creature); + m_uiPhaseTimer = 0; + break; + + case 31: // shortly after reaching WP 19 + if (m_pInstance) + { + if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_CAVE_IN_NORTH)) + m_creature->SetFacingToObject(pDoor); + } + DoScriptText(SAY_BLOW_2_10, m_creature); + m_uiPhaseTimer = 5000; + break; + case 32: + DoScriptText(SAY_BLOW_2_5, m_creature); + m_uiPhaseTimer = 1000; + break; + case 33: + DoSummonPack(7); // Summon Grubbis and add + m_uiPhaseTimer = 0; + break; + + case 34: // 1 sek after Death of Grubbis + if (m_pInstance) + { + if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_CAVE_IN_NORTH)) + m_creature->SetFacingToObject(pDoor); + } + m_creature->HandleEmote(EMOTE_ONESHOT_CHEER); + m_uiPhaseTimer = 5000; + break; + case 35: + DoScriptText(SAY_BLOW_SOON, m_creature); + m_uiPhaseTimer = 5000; + break; + case 36: + DoScriptText(SAY_BLOW_2, m_creature); + m_uiPhaseTimer = 2000; + break; + case 37: + m_creature->HandleEmote(EMOTE_ONESHOT_POINT); + m_uiPhaseTimer = 1000; + break; + case 38: + DoCastSpellIfCan(m_creature, SPELL_EXPLOSION_NORTH); + m_uiPhaseTimer = 500; + break; + case 39: + // Close northern cave-in and let charges explode + if (m_pInstance) + { + m_pInstance->DoUseDoorOrButton(GO_CAVE_IN_NORTH); + m_bNorthernCaveInOpened = false; + m_pInstance->SetData(TYPE_EXPLOSIVE_CHARGE, DATA_EXPLOSIVE_CHARGE_USE); + } + m_uiPhaseTimer = 8000; + break; + case 40: + DoCastSpellIfCan(m_creature, SPELL_FIREWORKS_RED); + DoScriptText(SAY_FINISH_2, m_creature); + m_uiPhaseTimer = 0; + break; + } + ++m_uiPhase; + } + else + m_uiPhaseTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_blastmaster_emi_shortfuse(Creature* pCreature) +{ + return new npc_blastmaster_emi_shortfuseAI(pCreature); +} + +bool GossipHello_npc_blastmaster_emi_shortfuse(Player* pPlayer, Creature* pCreature) +{ + if (instance_gnomeregan* pInstance = (instance_gnomeregan*)pCreature->GetInstanceData()) + { + 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->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + } + } + return true; +} + +bool GossipSelect_npc_blastmaster_emi_shortfuse(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + if (instance_gnomeregan* pInstance = (instance_gnomeregan*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_GRUBBIS) == NOT_STARTED || pInstance->GetData(TYPE_GRUBBIS) == FAIL) + { + if (npc_blastmaster_emi_shortfuseAI* pEmiAI = dynamic_cast(pCreature->AI())) + pEmiAI->StartEvent(pPlayer); + } + } + } + pPlayer->CLOSE_GOSSIP_MENU(); + + 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 MANGOS_DLL_DECL 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; + + pNewScript = new Script; + pNewScript->Name = "npc_blastmaster_emi_shortfuse"; + pNewScript->GetAI = &GetAI_npc_blastmaster_emi_shortfuse; + 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 4491dae73b..b2a13b45e0 100644 --- a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h +++ b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -46,7 +46,7 @@ enum struct sBombFace { - uint64 m_uiGnomeFaceGUID; + ObjectGuid m_gnomeFaceGuid; bool m_bActivated; uint32 m_uiBombTimer; }; @@ -57,37 +57,31 @@ class MANGOS_DLL_DECL instance_gnomeregan : public ScriptedInstance 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); - uint64 GetData64(uint32 uiData); + 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 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]; - std::string strInstData; + std::string m_strInstData; sBombFace m_asBombFaces[MAX_GNOME_FACES]; - uint64 m_auiExplosiveSortedGUIDs[2][MAX_EXPLOSIVES_PER_SIDE]; + ObjectGuid m_aExplosiveSortedGuids[2][MAX_EXPLOSIVES_PER_SIDE]; - uint64 m_uiBlastmasterShortfuseGUID; - uint64 m_uiCaveInNorthGUID; - uint64 m_uiCaveInSouthGUID; - uint64 m_uiDoorFinalChamberGUID; - - std::list m_luiExplosiveChargeGUIDs; - std::list m_luiSpawnedExplosiveChargeGUIDs; - std::list 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 4d90d08c57..701e11d766 100644 --- a/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp +++ b/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,11 +24,7 @@ EndScriptData */ #include "precompiled.h" #include "gnomeregan.h" -instance_gnomeregan::instance_gnomeregan(Map* pMap) : ScriptedInstance(pMap), - m_uiBlastmasterShortfuseGUID(0), - m_uiCaveInNorthGUID(0), - m_uiCaveInSouthGUID(0), - m_uiDoorFinalChamberGUID(0) +instance_gnomeregan::instance_gnomeregan(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } @@ -36,34 +32,39 @@ instance_gnomeregan::instance_gnomeregan(Map* pMap) : ScriptedInstance(pMap), void instance_gnomeregan::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_asBombFaces, 0, sizeof(m_asBombFaces)); - memset(&m_auiExplosiveSortedGUIDs, 0, sizeof(m_auiExplosiveSortedGUIDs)); + + for (uint8 i = 0; i < MAX_GNOME_FACES; ++i) + { + m_asBombFaces[i].m_bActivated = false; + m_asBombFaces[i].m_uiBombTimer = 0; + } } void instance_gnomeregan::OnCreatureCreate(Creature* pCreature) { - switch (pCreature->GetEntry()) - { - case NPC_BLASTMASTER_SHORTFUSE: m_uiBlastmasterShortfuseGUID = pCreature->GetGUID(); break; - } + if (pCreature->GetEntry() == NPC_BLASTMASTER_SHORTFUSE) + m_mNpcEntryGuidStore[NPC_BLASTMASTER_SHORTFUSE] = pCreature->GetObjectGuid(); } void instance_gnomeregan::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - case GO_RED_ROCKET: m_lRedRocketGUIDs.push_back(pGo->GetGUID()); break; - case GO_CAVE_IN_NORTH: m_uiCaveInNorthGUID = pGo->GetGUID(); break; - case GO_CAVE_IN_SOUTH: m_uiCaveInSouthGUID = pGo->GetGUID(); break; - case GO_EXPLOSIVE_CHARGE: m_luiExplosiveChargeGUIDs.push_back(pGo->GetGUID()); break; - case GO_THE_FINAL_CHAMBER: m_uiDoorFinalChamberGUID = pGo->GetGUID(); break; - - case GO_GNOME_FACE_1: m_asBombFaces[0].m_uiGnomeFaceGUID = pGo->GetGUID(); break; - case GO_GNOME_FACE_2: m_asBombFaces[1].m_uiGnomeFaceGUID = pGo->GetGUID(); break; - case GO_GNOME_FACE_3: m_asBombFaces[2].m_uiGnomeFaceGUID = pGo->GetGUID(); break; - case GO_GNOME_FACE_4: m_asBombFaces[3].m_uiGnomeFaceGUID = pGo->GetGUID(); break; - case GO_GNOME_FACE_5: m_asBombFaces[4].m_uiGnomeFaceGUID = pGo->GetGUID(); break; - case GO_GNOME_FACE_6: m_asBombFaces[5].m_uiGnomeFaceGUID = pGo->GetGUID(); break; + case GO_CAVE_IN_NORTH: + case GO_CAVE_IN_SOUTH: + case GO_THE_FINAL_CHAMBER: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + + case GO_RED_ROCKET: m_lRedRocketGUIDs.push_back(pGo->GetObjectGuid()); return; + case GO_EXPLOSIVE_CHARGE: m_luiExplosiveChargeGUIDs.push_back(pGo->GetObjectGuid()); return; + + case GO_GNOME_FACE_1: m_asBombFaces[0].m_gnomeFaceGuid = pGo->GetObjectGuid(); return; + case GO_GNOME_FACE_2: m_asBombFaces[1].m_gnomeFaceGuid = pGo->GetObjectGuid(); return; + case GO_GNOME_FACE_3: m_asBombFaces[2].m_gnomeFaceGuid = pGo->GetObjectGuid(); return; + case GO_GNOME_FACE_4: m_asBombFaces[3].m_gnomeFaceGuid = pGo->GetObjectGuid(); return; + case GO_GNOME_FACE_5: m_asBombFaces[4].m_gnomeFaceGuid = pGo->GetObjectGuid(); return; + case GO_GNOME_FACE_6: m_asBombFaces[5].m_gnomeFaceGuid = pGo->GetObjectGuid(); return; } } @@ -74,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; @@ -84,7 +85,7 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) if (!m_luiExplosiveChargeGUIDs.empty()) { std::list lExplosiveCharges; - for (std::list::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); @@ -97,21 +98,21 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) // Sort to south and north uint8 uiCounterSouth = 0; uint8 uiCounterNorth = 0; - GameObject* pCaveInSouth = instance->GetGameObject(m_uiCaveInSouthGUID); - GameObject* pCaveInNorth = instance->GetGameObject(m_uiCaveInNorthGUID); + GameObject* pCaveInSouth = GetSingleGameObjectFromStorage(GO_CAVE_IN_SOUTH); + GameObject* pCaveInNorth = GetSingleGameObjectFromStorage(GO_CAVE_IN_NORTH); if (pCaveInSouth && pCaveInNorth) { - for (std::list::iterator itr = lExplosiveCharges.begin(); itr != lExplosiveCharges.end(); itr++) + for (std::list::iterator itr = lExplosiveCharges.begin(); itr != lExplosiveCharges.end(); ++itr) { if ((*itr)->GetDistanceOrder(pCaveInSouth, pCaveInNorth) && uiCounterSouth < MAX_EXPLOSIVES_PER_SIDE) { - m_auiExplosiveSortedGUIDs[0][uiCounterSouth] = (*itr)->GetGUID(); - uiCounterSouth++; + m_aExplosiveSortedGuids[0][uiCounterSouth] = (*itr)->GetObjectGuid(); + ++uiCounterSouth; } else if (uiCounterNorth < MAX_EXPLOSIVES_PER_SIDE) { - m_auiExplosiveSortedGUIDs[1][uiCounterNorth] = (*itr)->GetGUID(); - uiCounterNorth++; + m_aExplosiveSortedGuids[1][uiCounterNorth] = (*itr)->GetObjectGuid(); + ++uiCounterNorth; } } } @@ -124,7 +125,7 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) } if (uiData == DONE) { - for (std::list::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; @@ -132,26 +133,26 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) switch (uiData) { case DATA_EXPLOSIVE_CHARGE_1: - DoRespawnGameObject(m_auiExplosiveSortedGUIDs[0][0], HOUR); - m_luiSpawnedExplosiveChargeGUIDs.push_back(m_auiExplosiveSortedGUIDs[0][0]); + DoRespawnGameObject(m_aExplosiveSortedGuids[0][0], HOUR); + m_luiSpawnedExplosiveChargeGUIDs.push_back(m_aExplosiveSortedGuids[0][0]); break; case DATA_EXPLOSIVE_CHARGE_2: - DoRespawnGameObject(m_auiExplosiveSortedGUIDs[0][1], HOUR); - m_luiSpawnedExplosiveChargeGUIDs.push_back(m_auiExplosiveSortedGUIDs[0][1]); + DoRespawnGameObject(m_aExplosiveSortedGuids[0][1], HOUR); + m_luiSpawnedExplosiveChargeGUIDs.push_back(m_aExplosiveSortedGuids[0][1]); break; case DATA_EXPLOSIVE_CHARGE_3: - DoRespawnGameObject(m_auiExplosiveSortedGUIDs[1][0], HOUR); - m_luiSpawnedExplosiveChargeGUIDs.push_back(m_auiExplosiveSortedGUIDs[1][0]); + DoRespawnGameObject(m_aExplosiveSortedGuids[1][0], HOUR); + m_luiSpawnedExplosiveChargeGUIDs.push_back(m_aExplosiveSortedGuids[1][0]); break; case DATA_EXPLOSIVE_CHARGE_4: - DoRespawnGameObject(m_auiExplosiveSortedGUIDs[1][1], HOUR); - m_luiSpawnedExplosiveChargeGUIDs.push_back(m_auiExplosiveSortedGUIDs[1][1]); + DoRespawnGameObject(m_aExplosiveSortedGuids[1][1], HOUR); + m_luiSpawnedExplosiveChargeGUIDs.push_back(m_aExplosiveSortedGuids[1][1]); break; case DATA_EXPLOSIVE_CHARGE_USE: - Creature* pBlastmaster = instance->GetCreature(m_uiBlastmasterShortfuseGUID); + Creature* pBlastmaster = GetSingleCreatureFromStorage(NPC_BLASTMASTER_SHORTFUSE); if (!pBlastmaster) break; - for (std::list::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); @@ -165,13 +166,11 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) if (uiData == IN_PROGRESS) { // Make Door locked - if (GameObject* pDoor = instance->GetGameObject(m_uiDoorFinalChamberGUID)) + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_THE_FINAL_CHAMBER)) { + pDoor->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); if (pDoor->getLootState() == GO_ACTIVATED) pDoor->ResetDoorOrButton(); - - // Doesn't work here, because the flags are to be reseted on next tick in GO::Update - pDoor->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); } // Always directly activates this bomb-face @@ -180,15 +179,15 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) else if (uiData == DONE || uiData == FAIL) { // Make Door unlocked again - if (GameObject* pDoor = instance->GetGameObject(m_uiDoorFinalChamberGUID)) + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_THE_FINAL_CHAMBER)) { + pDoor->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); if (pDoor->getLootState() == GO_READY) pDoor->UseDoorOrButton(); - pDoor->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); } // Deactivate all remaining BombFaces - for (uint8 i = 0; i < MAX_GNOME_FACES; i++) + for (uint8 i = 0; i < MAX_GNOME_FACES; ++i) DoDeactivateBombFace(i); } break; @@ -201,7 +200,7 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -221,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; @@ -230,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]; @@ -241,17 +240,6 @@ uint32 instance_gnomeregan::GetData(uint32 uiType) } } -uint64 instance_gnomeregan::GetData64(uint32 uiData) -{ - switch(uiData) - { - case GO_CAVE_IN_NORTH: return m_uiCaveInNorthGUID; - case GO_CAVE_IN_SOUTH: return m_uiCaveInSouthGUID; - default: - return 0; - } -} - sBombFace* instance_gnomeregan::GetBombFaces() { return m_asBombFaces; @@ -264,7 +252,7 @@ void instance_gnomeregan::DoActivateBombFace(uint8 uiIndex) if (!m_asBombFaces[uiIndex].m_bActivated) { - DoUseDoorOrButton(m_asBombFaces[uiIndex].m_uiGnomeFaceGUID); + DoUseDoorOrButton(m_asBombFaces[uiIndex].m_gnomeFaceGuid); m_asBombFaces[uiIndex].m_bActivated = true; m_asBombFaces[uiIndex].m_uiBombTimer = 3000; } @@ -277,7 +265,7 @@ void instance_gnomeregan::DoDeactivateBombFace(uint8 uiIndex) if (m_asBombFaces[uiIndex].m_bActivated) { - DoUseDoorOrButton(m_asBombFaces[uiIndex].m_uiGnomeFaceGUID); + DoUseDoorOrButton(m_asBombFaces[uiIndex].m_gnomeFaceGuid); m_asBombFaces[uiIndex].m_bActivated = false; m_asBombFaces[uiIndex].m_uiBombTimer = 0; } diff --git a/scripts/eastern_kingdoms/grim_batol/boss_drahga_shadowburner.cpp b/scripts/eastern_kingdoms/grim_batol/boss_drahga_shadowburner.cpp new file mode 100644 index 0000000000..48229e5caa --- /dev/null +++ b/scripts/eastern_kingdoms/grim_batol/boss_drahga_shadowburner.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_drahga_shadowburner +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Grim Batol +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_drahga_shadowburner() +{ +} diff --git a/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp b/scripts/eastern_kingdoms/grim_batol/boss_erudax.cpp similarity index 82% rename from scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp rename to scripts/eastern_kingdoms/grim_batol/boss_erudax.cpp index cdea07be0d..769b0f056e 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp +++ b/scripts/eastern_kingdoms/grim_batol/boss_erudax.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,10 +15,14 @@ */ /* ScriptData -SDName: Instance_Blackwing_Lair +SDName: boss_erudax SD%Complete: 0 -SDComment: -SDCategory: Blackwing Lair +SDComment: Placeholder +SDCategory: Grim Batol EndScriptData */ #include "precompiled.h" + +void AddSC_boss_erudax() +{ +} diff --git a/scripts/eastern_kingdoms/grim_batol/boss_forgemaster_throngus.cpp b/scripts/eastern_kingdoms/grim_batol/boss_forgemaster_throngus.cpp new file mode 100644 index 0000000000..6318aae18a --- /dev/null +++ b/scripts/eastern_kingdoms/grim_batol/boss_forgemaster_throngus.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_forgemaster_throngus +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Grim Batol +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_forgemaster_throngus() +{ +} diff --git a/scripts/eastern_kingdoms/grim_batol/boss_general_umbriss.cpp b/scripts/eastern_kingdoms/grim_batol/boss_general_umbriss.cpp new file mode 100644 index 0000000000..be47a0be41 --- /dev/null +++ b/scripts/eastern_kingdoms/grim_batol/boss_general_umbriss.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_general_umbriss +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Grim Batol +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_general_umbriss() +{ +} diff --git a/scripts/eastern_kingdoms/grim_batol/grim_batol.h b/scripts/eastern_kingdoms/grim_batol/grim_batol.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/eastern_kingdoms/grim_batol/grim_batol.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/eastern_kingdoms/grim_batol/instance_grim_batol.cpp b/scripts/eastern_kingdoms/grim_batol/instance_grim_batol.cpp new file mode 100644 index 0000000000..a710099203 --- /dev/null +++ b/scripts/eastern_kingdoms/grim_batol/instance_grim_batol.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_grim_batol +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Grim Batol +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_grim_batol() +{ +} diff --git a/scripts/eastern_kingdoms/hinterlands.cpp b/scripts/eastern_kingdoms/hinterlands.cpp index 6a44f15c0d..7f49de079f 100644 --- a/scripts/eastern_kingdoms/hinterlands.cpp +++ b/scripts/eastern_kingdoms/hinterlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,7 +29,7 @@ EndContentData */ #include "precompiled.h" #include "escort_ai.h" - /*###### +/*###### ## npc_00x09hl ######*/ @@ -53,9 +53,9 @@ struct MANGOS_DLL_DECL npc_00x09hlAI : public npc_escortAI void Reset() { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 26: DoScriptText(SAY_OOX_AMBUSH, m_creature); @@ -71,12 +71,12 @@ 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) + 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); @@ -85,7 +85,7 @@ struct MANGOS_DLL_DECL npc_00x09hlAI : public npc_escortAI } break; case 44: - for(uint8 i = 0; i < 3; ++i) + 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); @@ -96,7 +96,7 @@ struct MANGOS_DLL_DECL npc_00x09hlAI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->GetEntry() == NPC_MARAUDING_OWL || pWho->GetEntry() == NPC_VILE_AMBUSHER) return; @@ -104,7 +104,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,12 +115,12 @@ 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); if (npc_00x09hlAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -150,18 +150,13 @@ enum GO_RINJI_CAGE = 142036 }; -struct Location -{ - float m_fX, m_fY, m_fZ; -}; - -Location m_afAmbushSpawn[] = +static LOCATION m_afAmbushSpawn[] = { {191.29620f, -2839.329346f, 107.388f}, {70.972466f, -2848.674805f, 109.459f} }; -Location m_afAmbushMoveTo[] = +static LOCATION m_afAmbushMoveTo[] = { {166.63038f, -2824.780273f, 108.153f}, {70.886589f, -2874.335449f, 116.675f} @@ -187,7 +182,7 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI m_uiPostEventTimer = 3000; } - void JustRespawned() + void JustRespawned() override { m_bIsByOutrunner = false; m_iSpawnId = 0; @@ -195,7 +190,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 +203,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 +214,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].x, m_afAmbushSpawn[m_iSpawnId].y, m_afAmbushSpawn[m_iSpawnId].z, 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].x, m_afAmbushSpawn[m_iSpawnId].y, m_afAmbushSpawn[m_iSpawnId].z, 0.0f, + TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 60000); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - pSummoned->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - pSummoned->GetMotionMaster()->MovePoint(0, m_afAmbushMoveTo[m_iSpawnId].m_fX, m_afAmbushMoveTo[m_iSpawnId].m_fY, m_afAmbushMoveTo[m_iSpawnId].m_fZ); + m_creature->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, m_afAmbushMoveTo[m_iSpawnId].x, m_afAmbushMoveTo[m_iSpawnId].y, m_afAmbushMoveTo[m_iSpawnId].z); } - 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 +258,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 +271,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); @@ -313,7 +308,7 @@ bool QuestAccept_npc_rinji(Player* pPlayer, Creature* pCreature, const Quest* pQ pGo->UseDoorOrButton(); if (npc_rinjiAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -330,12 +325,12 @@ void AddSC_hinterlands() pNewScript = new Script; pNewScript->Name = "npc_00x09hl"; pNewScript->GetAI = &GetAI_npc_00x09hl; - pNewScript->pQuestAccept = &QuestAccept_npc_00x09hl; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_00x09hl; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_rinji"; pNewScript->GetAI = &GetAI_npc_rinji; - pNewScript->pQuestAccept = &QuestAccept_npc_rinji; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_rinji; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/ironforge.cpp b/scripts/eastern_kingdoms/ironforge.cpp index 4c54ccd171..17449e1061 100644 --- a/scripts/eastern_kingdoms/ironforge.cpp +++ b/scripts/eastern_kingdoms/ironforge.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,6 +23,8 @@ EndScriptData */ /* ContentData npc_royal_historian_archesonus +King Magni Bronzebeard +High Tinker Mekkatorque EndContentData */ #include "precompiled.h" @@ -40,15 +42,15 @@ EndContentData */ bool GossipHello_npc_royal_historian_archesonus(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2235, pCreature->GetObjectGuid()); } else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } @@ -59,19 +61,19 @@ bool GossipSelect_npc_royal_historian_archesonus(Player* pPlayer, Creature* pCre { 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->GetGUID()); + 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->GetGUID()); + 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->GetGUID()); + 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->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2239, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+4: pPlayer->CLOSE_GOSSIP_MENU(); @@ -81,13 +83,172 @@ bool GossipSelect_npc_royal_historian_archesonus(Player* pPlayer, Creature* pCre return true; } +/*###### +## King Magni Bronzebeard +######*/ + +enum +{ + SPELL_AVATAR = 19135, + SPELL_KNOCK_AWAY = 20686, + SPELL_STORM_BOLT = 20685, + //SPELL_MOTRAL_STRIKE = 13737, + //SPELL_STRONG_CLEAVE = 8255, + //SPELL_RAMPAGE = 8285, + //SPELL_CONCUSSION_BLOW = 12809 +}; + +struct MANGOS_DLL_DECL boss_king_magni_bronzebreardAI : public ScriptedAI +{ + boss_king_magni_bronzebreardAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiAvatarTimer; + uint32 m_uiKnockAwayTimer; + uint32 m_uiStormboltTimer; + + void Reset() + { + m_uiAvatarTimer = 15000; + m_uiKnockAwayTimer = 8000; + m_uiStormboltTimer = 10000; + } + + void Aggro(Unit *who) + { + m_creature->CallForHelp(100); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiAvatarTimer < uiDiff) + { + DoCast(m_creature, SPELL_AVATAR); + m_uiAvatarTimer = urand(15000, 12000); + } + else + m_uiAvatarTimer -= uiDiff; + + if (m_uiKnockAwayTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_KNOCK_AWAY); + m_uiKnockAwayTimer = urand(8000, 12000); + } + else + m_uiKnockAwayTimer -= uiDiff; + + if (m_uiStormboltTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_STORM_BOLT); + m_uiStormboltTimer = 10000; + } + else + m_uiStormboltTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_king_magni_bronzebreard(Creature* pCreature) +{ + return new boss_king_magni_bronzebreardAI(pCreature); +} + +/*###### +## High Tinker Mekkatorque +######*/ + +enum +{ + SPELL_BOMB = 9143, + SPELL_GOBLIN_DRAGON_GUN = 22739, + SPELL_SUPER_SHRINK_RAY = 22742, + + //SPELL_IRON_GRENADE = 4068, + //SPELL_HI_EXP_BOMB = 12543, + //SPELL_MITHRIL_FRAG_BOMB = 12421, + //SPELL_BIG_IRON_BOMB = 4069 +}; + +struct MANGOS_DLL_DECL boss_high_tinker_mekkatorqueAI : public ScriptedAI +{ + boss_high_tinker_mekkatorqueAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiBombTimer; + uint32 m_uiGoblinDragonGunTimer; + uint32 m_uiSuperShrinkRayTimer; + + void Reset() + { + m_uiBombTimer = 10000; + m_uiGoblinDragonGunTimer = 15000; + m_uiSuperShrinkRayTimer = 15000; + } + + void Aggro(Unit *who) + { + m_creature->CallForHelp(100); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBombTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_BOMB); + m_uiBombTimer = urand(8000, 15000); + } + else + m_uiBombTimer -= uiDiff; + + if (m_uiGoblinDragonGunTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_GOBLIN_DRAGON_GUN); + m_uiGoblinDragonGunTimer = urand(15000, 20000); + } + else + m_uiGoblinDragonGunTimer -= uiDiff; + + if (m_uiSuperShrinkRayTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SUPER_SHRINK_RAY); + m_uiSuperShrinkRayTimer = urand(15000, 20000); + } + else + m_uiSuperShrinkRayTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_high_tinker_mekkatorque(Creature* pCreature) +{ + return new boss_high_tinker_mekkatorqueAI(pCreature); +} + void AddSC_ironforge() { - Script *newscript; + 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(); + + pNewScript = new Script; + pNewScript->Name = "boss_king_magni_bronzebreard"; + pNewScript->GetAI = &GetAI_boss_king_magni_bronzebreard; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_royal_historian_archesonus"; - newscript->pGossipHello = &GossipHello_npc_royal_historian_archesonus; - newscript->pGossipSelect = &GossipSelect_npc_royal_historian_archesonus; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_high_tinker_mekkatorque"; + pNewScript->GetAI = &GetAI_boss_high_tinker_mekkatorque; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/isle_of_queldanas.cpp b/scripts/eastern_kingdoms/isle_of_queldanas.cpp index b8f35e38b6..feea514d23 100644 --- a/scripts/eastern_kingdoms/isle_of_queldanas.cpp +++ b/scripts/eastern_kingdoms/isle_of_queldanas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,14 +17,12 @@ /* ScriptData SDName: Isle_of_Queldanas SD%Complete: 100 -SDComment: Quest support: 11524, 11525, 11533, 11543 +SDComment: Quest support: 11524, 11525 SDCategory: Isle Of Quel'Danas EndScriptData */ /* ContentData -npc_ayren_cloudbreaker npc_converted_sentry -npc_unrestrained_dragonhawk EndContentData */ #include "precompiled.h" @@ -33,48 +31,46 @@ EndContentData */ ## npc_converted_sentry ######*/ -#define SAY_CONVERTED_1 -1000188 -#define SAY_CONVERTED_2 -1000189 +enum +{ + SAY_CONVERTED_1 = -1000188, + SAY_CONVERTED_2 = -1000189, -#define SPELL_CONVERT_CREDIT 45009 + SPELL_CONVERT_CREDIT = 45009, + TIME_PET_DURATION = 7500 +}; struct MANGOS_DLL_DECL npc_converted_sentryAI : public ScriptedAI { npc_converted_sentryAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool Credit; - uint32 Timer; + uint32 m_uiCreditTimer; void Reset() { - Credit = false; - Timer = 2500; + m_uiCreditTimer = 2500; } - void MoveInLineOfSight(Unit *who) - { - return; - } + void MoveInLineOfSight(Unit* /*pWho*/) override {} - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!Credit) + if (m_uiCreditTimer) { - if (Timer <= diff) + if (m_uiCreditTimer <= uiDiff) { - uint32 i = urand(1,2); - if (i==1) - DoScriptText(SAY_CONVERTED_1, m_creature); - else - DoScriptText(SAY_CONVERTED_2, m_creature); + DoScriptText(urand(0, 1) ? SAY_CONVERTED_1 : SAY_CONVERTED_2, m_creature); - DoCastSpellIfCan(m_creature,SPELL_CONVERT_CREDIT); - ((Pet*)m_creature)->SetDuration(7500); - Credit = true; - }else Timer -= diff; + DoCastSpellIfCan(m_creature, SPELL_CONVERT_CREDIT); + ((Pet*)m_creature)->SetDuration(TIME_PET_DURATION); + m_uiCreditTimer = 0; + } + else + m_uiCreditTimer -= uiDiff; } } }; + CreatureAI* GetAI_npc_converted_sentry(Creature* pCreature) { return new npc_converted_sentryAI(pCreature); @@ -82,10 +78,10 @@ CreatureAI* GetAI_npc_converted_sentry(Creature* pCreature) void AddSC_isle_of_queldanas() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_converted_sentry"; - newscript->GetAI = &GetAI_npc_converted_sentry; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_converted_sentry"; + pNewScript->GetAI = &GetAI_npc_converted_sentry; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_curator.cpp b/scripts/eastern_kingdoms/karazhan/boss_curator.cpp index 0991a8c25f..daa6883c25 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_curator.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_curator.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 { - 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() { - 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 JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CURATOR, FAIL); } - void JustSummoned(Creature* pSummoned) + 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; @@ -203,9 +219,10 @@ CreatureAI* GetAI_boss_curator(Creature* pCreature) void AddSC_boss_curator() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_curator"; - newscript->GetAI = &GetAI_boss_curator; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_curator"; + pNewScript->GetAI = &GetAI_boss_curator; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp b/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp index 4285021174..961ddfd740 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,6 +22,7 @@ SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" enum { @@ -41,24 +42,30 @@ enum struct MANGOS_DLL_DECL 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(); + } + + ScriptedInstance* m_pInstance; - uint32 m_uiRepentance_Timer; - uint32 m_uiHolyfire_Timer; - uint32 m_uiHolywrath_Timer; - uint32 m_uiHolyground_Timer; + uint32 m_uiRepentanceTimer; + uint32 m_uiHolyfireTimer; + uint32 m_uiHolywrathTimer; + uint32 m_uiHolygroundTimer; void Reset() { - 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 UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MAIDEN, FAIL); + } + + 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(); } @@ -151,9 +151,10 @@ CreatureAI* GetAI_boss_maiden_of_virtue(Creature* pCreature) void AddSC_boss_maiden_of_virtue() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_maiden_of_virtue"; - newscript->GetAI = &GetAI_boss_maiden_of_virtue; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_maiden_of_virtue"; + pNewScript->GetAI = &GetAI_boss_maiden_of_virtue; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp b/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp index caabba3313..9b238aec17 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,138 +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 { - boss_midnightAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_midnightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + Reset(); + } + + instance_karazhan* m_pInstance; - uint64 m_uiAttumenGUID; - uint8 m_uiPhase; - uint32 m_uiMount_Timer; + uint8 m_uiPhase; + uint32 m_uiKnockDown; void Reset() { - m_uiPhase = 1; - m_uiAttumenGUID = 0; - 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_uiAttumenGUID)) + 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 *, uint64); //Below .. + // Wrapper to prepare phase 3 + void DoPrepareMount(Creature* pTarget) + { + if (pTarget) + { + m_uiPhase = 2; - void UpdateAI(const uint32 uiDiff) + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(1, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + } + } + + 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_uiAttumenGUID = pAttumen->GetGUID(); - pAttumen->AI()->AttackStart(m_creature->getVictim()); - SetMidnight(pAttumen, m_creature->GetGUID()); - - 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_uiAttumenGUID)) - 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_uiAttumenGUID)) - { - pAttumen->SetDisplayId(MOUNTED_DISPLAYID); - pAttumen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (pAttumen->getVictim()) - { - pAttumen->GetMotionMaster()->MoveChase(pAttumen->getVictim()); - pAttumen->SetUInt64Value(UNIT_FIELD_TARGET, pAttumen->getVictim()->GetGUID()); - } - 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; + } + + // 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; - if (m_uiPhase != 3) - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(); } }; @@ -181,89 +194,76 @@ struct MANGOS_DLL_DECL 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; } - uint64 m_uiMidnightGUID; - 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 + + bool m_bHasSummonRider; void Reset() { - 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) + if (pSpell->GetMechanic() == 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_uiMidnightGUID)) - 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_uiMidnightGUID)) - { - pMidnight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pMidnight->SetVisibility(VISIBILITY_ON); - } - m_uiMidnightGUID = 0; + 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; @@ -276,47 +276,38 @@ 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) { - Unit *target = NULL; - std::vector target_list; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BERSERKER_CHARGE, SELECT_FLAG_NOT_IN_MELEE_RANGE | SELECT_FLAG_IN_LOS)) { - target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (target && !target->IsWithinDist(m_creature, ATTACK_DISTANCE, false)) - target_list.push_back(target); - - target = NULL; - } - - if (target_list.size()) - { - if (target = *(target_list.begin()+rand()%target_list.size())) - DoCastSpellIfCan(target, SPELL_BERSERKER_CHARGE); + if (DoCastSpellIfCan(pTarget, SPELL_BERSERKER_CHARGE) == CAST_OK) + m_uiChargeTimer = 20000; } - - m_uiChargeTimer = 20000; + else + m_uiChargeTimer = 2000; } 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_uiMidnightGUID)) - { - 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; } } @@ -324,28 +315,43 @@ struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI } }; -void boss_midnightAI::SetMidnight(Creature* pAttumen, uint64 uiValue) -{ - if (boss_attumenAI* pAttumenAI = dynamic_cast(pAttumen->AI())) - pAttumenAI->m_uiMidnightGUID = uiValue; -} - CreatureAI* GetAI_boss_attumen(Creature* pCreature) { return new boss_attumenAI(pCreature); } -void AddSC_boss_attumen() +bool EffectDummyCreature_spell_mount_attumen(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - Script* newscript; + // 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); + } - newscript = new Script; - newscript->Name = "boss_attumen"; - newscript->GetAI = &GetAI_boss_attumen; - newscript->RegisterSelf(); + // always return true when we are handling this spell and effect + return true; + } + + return false; +} - newscript = new Script; - newscript->Name = "boss_midnight"; - newscript->GetAI = &GetAI_boss_midnight; - newscript->RegisterSelf(); +void AddSC_boss_attumen() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_attumen"; + pNewScript->GetAI = &GetAI_boss_attumen; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_mount_attumen; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_midnight"; + pNewScript->GetAI = &GetAI_boss_midnight; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp b/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp index 19bdb243a6..8e8c0aba53 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Moroes SD%Complete: 95 -SDComment: +SDComment: Timers. SDCategory: Karazhan EndScriptData */ @@ -26,6 +26,9 @@ EndScriptData */ enum { + MAX_ACTIVE_GUESTS = 4, + MAX_GUESTS = 6, + SAY_AGGRO = -1532011, SAY_SPECIAL_1 = -1532012, SAY_SPECIAL_2 = -1532013, @@ -41,85 +44,66 @@ enum SPELL_FRENZY = 37023 }; -const float afLocations[4][4]= +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} }; -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 { boss_moroesAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_bFirstTime = true; m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } ScriptedInstance* m_pInstance; - uint64 m_auiAddGUID[4]; - uint32 m_auiAddId[4]; + 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() { - 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; @@ -127,717 +111,174 @@ 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() > 4) - 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_auiAddGUID[i] = pCreature->GetGUID(); - 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 < 4; ++i) + if (!m_pInstance) + return; + + for (uint8 i = 0; i < MAX_ACTIVE_GUESTS; ++i) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_auiAddGUID[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_auiAddGUID[i] = pCreature->GetGUID(); - } + // 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 < 4; ++i) + // remove aura from spell Garrote when Moroes dies + Map* pMap = m_creature->GetMap(); + if (pMap->IsDungeon()) { - if (m_auiAddGUID[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_auiAddGUID[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 < 4; ++i) + if (m_uiWaitTimer <= uiDiff) { - if (m_auiAddGUID[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_auiAddGUID[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) { - Unit* pTarget = NULL; - - ThreatList const& vThreatList = m_creature->getThreatManager().getThreatList(); - if (vThreatList.empty()) - return; - - std::vector vTargetList; - - for (ThreatList::const_iterator itr = vThreatList.begin();itr != vThreatList.end(); ++itr) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BLIND, SELECT_FLAG_PLAYER)) { - pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (pTarget && pTarget->IsWithinDist(m_creature, ATTACK_DISTANCE, false)) - vTargetList.push_back(pTarget); + if (DoCastSpellIfCan(pTarget, SPELL_BLIND) == CAST_OK) + m_uiBlindTimer = 40000; } - - if (!vTargetList.empty()) - pTarget = *(vTargetList.begin()+rand()%vTargetList.size()); - - if (pTarget) - DoCastSpellIfCan(pTarget, SPELL_BLIND); - - m_uiBlind_Timer = 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; - - uint64 m_auiGuestGUID[4]; - - boss_moroes_guestAI(Creature* pCreature) : ScriptedAI(pCreature) - { - memset(&m_auiGuestGUID, 0, sizeof(m_auiGuestGUID)); - - 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; - - m_auiGuestGUID[0] = m_pInstance->GetData64(DATA_MOROES); - - if (Creature* pMoroes = m_creature->GetMap()->GetCreature(m_auiGuestGUID[0])) - { - for(uint8 i = 0; i < 3; ++i) - { - uint64 uiGUID = 0; - - if (boss_moroesAI* pMoroesAI = dynamic_cast(pMoroes->AI())) - uiGUID = pMoroesAI->m_auiAddGUID[i]; - - if (uiGUID && uiGUID != m_creature->GetGUID()) - m_auiGuestGUID[i+1] = uiGUID; - } - } - } - - Unit* SelectTarget() - { - if (uint64 uiTempGUID = m_auiGuestGUID[rand()%4]) - { - Creature* pTemp = m_creature->GetMap()->GetCreature(uiTempGUID); - if (pTemp && pTemp->isAlive()) - return pTemp; - } - - return m_creature; - } - - 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) - { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget && pTarget->getPowerType() == 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* newscript; - - newscript = new Script; - newscript->Name = "boss_moroes"; - newscript->GetAI = &GetAI_boss_moroes; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_baroness_dorothea_millstipe"; - newscript->GetAI = &GetAI_baroness_dorothea_millstipe; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_baron_rafe_dreuger"; - newscript->GetAI = &GetAI_baron_rafe_dreuger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lady_catriona_von_indi"; - newscript->GetAI = &GetAI_lady_catriona_von_indi; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lady_keira_berrybuck"; - newscript->GetAI = &GetAI_lady_keira_berrybuck; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lord_robin_daris"; - newscript->GetAI = &GetAI_lord_robin_daris; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lord_crispin_ference"; - newscript->GetAI = &GetAI_lord_crispin_ference; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_moroes"; + pNewScript->GetAI = &GetAI_boss_moroes; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp b/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp index 1c6e5efd48..a3454babc7 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,68 +26,94 @@ 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, -struct SpawnLocation -{ - float x, y, z; + MAX_PORTALS = 3, }; // at first spawn portals got fixed coords, should be shuffled in subsequent beam phases -static SpawnLocation PortalCoordinates[] = +static const LOCATION 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, }; +static const uint32 auiPortals[MAX_PORTALS] = +{ + NPC_PORTAL_GREEN, + NPC_PORTAL_BLUE, + NPC_PORTAL_RED, +}; + +/*###### +## boss_netherspite +######*/ + struct MANGOS_DLL_DECL boss_netherspiteAI : public ScriptedAI { boss_netherspiteAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -98,70 +124,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; + std::vector m_vPortalEntryList; void Reset() { - m_bIsEnraged = false; - m_uiActivePhase = BEAM_PHASE; - - m_uiEnrageTimer = MINUTE*9*IN_MILLISECONDS; + m_uiActivePhase = BEAM_PHASE; + + 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); - m_creature->SetInCombatWithZone(); } - 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); - m_uiNetherbreathTimer = 500; - m_uiPhaseSwitchTimer = (MINUTE/2)*IN_MILLISECONDS; + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + + 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].x, aPortalCoordinates[i].y, aPortalCoordinates[i].z, aPortalCoordinates[i].o, 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; @@ -170,13 +248,13 @@ struct MANGOS_DLL_DECL boss_netherspiteAI : public ScriptedAI SwitchPhases(); 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; @@ -187,28 +265,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(); } }; @@ -217,12 +307,122 @@ CreatureAI* GetAI_boss_netherspite(Creature* pCreature) return new boss_netherspiteAI(pCreature); } +/*###### +## npc_netherspite_portal +######*/ + +struct MANGOS_DLL_DECL 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* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_netherspite"; + pNewScript->GetAI = &GetAI_boss_netherspite; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_netherspite"; - newscript->GetAI = &GetAI_boss_netherspite; - newscript->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 2adc3364e6..8bcd888c3d 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,21 +16,385 @@ /* 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 MANGOS_DLL_DECL 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; + + void Reset() + { + m_uiPhase = PHASE_GROUND; + m_uiFlightPhase = 1; + + 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 JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NIGHTBANE, FAIL); + + // Reset escort waypoints + npc_escortAI::JustRespawned(); + } + + void EnterEvadeMode() override + { + // Use standard AI evade, in order to reset position + ScriptedAI::EnterEvadeMode(); + } + + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + + m_creature->SetInCombatWithZone(); + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE) + return; + + if (!m_creature->getVictim()) + npc_escortAI::MovementInform(uiMotionType, uiPointId); + else + { + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + 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 fdd108658f..c01b554f62 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,199 +22,102 @@ SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" -#define SAY_AGGRO -1532091 -#define SAY_AXE_TOSS1 -1532092 -#define SAY_AXE_TOSS2 -1532093 -#define SAY_SPECIAL1 -1532094 -#define SAY_SPECIAL2 -1532095 -#define SAY_SPECIAL3 -1532096 -#define SAY_SLAY1 -1532097 -#define SAY_SLAY2 -1532098 -#define SAY_SLAY3 -1532099 -#define SAY_SUMMON1 -1532100 -#define SAY_SUMMON2 -1532101 -#define SAY_DEATH -1532102 - -// 18 Coordinates for Infernal spawns -struct InfernalPoint +enum { - 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} -}; - -#define 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 - -#define SPELL_ENFEEBLE 30843 //Enfeeble during phase 1 and 2 -#define SPELL_ENFEEBLE_EFFECT 41624 - -#define SPELL_SHADOWNOVA 30852 //Shadownova used during all phases -#define SPELL_SW_PAIN 30854 //Shadow word pain during phase 1 and 3 (different targeting rules though) -#define SPELL_THRASH_PASSIVE 12787 //Extra attack chance during phase 2 -#define SPELL_SUNDER_ARMOR 30901 //Sunder armor during phase 2 -#define SPELL_THRASH_AURA 12787 //Passive proc chance for thrash -#define SPELL_EQUIP_AXES 30857 //Visual for axe equiping -#define SPELL_AMPLIFY_DAMAGE 39095 //Amplifiy during phase 3 -#define SPELL_CLEAVE 30131 //Same as Nightbane. -#define SPELL_HELLFIRE 30859 //Infenals' hellfire aura -#define NETHERSPITE_INFERNAL 17646 //The netherspite infernal creature -#define MALCHEZARS_AXE 17650 //Malchezar's axes (creatures), summoned during phase 3 - -#define INFERNAL_MODEL_INVISIBLE 11686 //Infernal Effects -#define SPELL_INFERNAL_RELAY 30834 - -#define EQUIP_ID_AXE 33542 //Axes info - -//---------Infernal code first -struct MANGOS_DLL_DECL netherspite_infernalAI : public ScriptedAI -{ - netherspite_infernalAI(Creature* pCreature) : ScriptedAI(pCreature) , - malchezaar(0), HellfireTimer(0), CleanupTimer(0), point(NULL) {Reset();} - - uint32 HellfireTimer; - uint32 CleanupTimer; - uint64 malchezaar; - InfernalPoint *point; - - void Reset() {} - void MoveInLineOfSight(Unit *who) {} - - void UpdateAI(const uint32 diff) - { - if (HellfireTimer) - { - if (HellfireTimer <= diff) - { - DoCastSpellIfCan(m_creature, SPELL_HELLFIRE); - HellfireTimer = 0; - } else HellfireTimer -= diff; - } - - if (CleanupTimer) - { - if (CleanupTimer <= diff) - { - Cleanup(); - CleanupTimer = 0; - } else CleanupTimer -= diff; - } - } - - void KilledUnit(Unit *who) - { - if (Creature *pMalchezaar = m_creature->GetMap()->GetCreature(malchezaar)) - pMalchezaar->AI()->KilledUnit(who); - } - - void SpellHit(Unit *who, const SpellEntry *spell) - { - if (spell->Id == SPELL_INFERNAL_RELAY) - { - m_creature->SetDisplayId(m_creature->GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID)); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - HellfireTimer = 4000; - CleanupTimer = 170000; - } - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (done_by->GetGUID() != malchezaar) - damage = 0; - } - - void Cleanup(); //below ... + 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_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 + + SPELL_HELLFIRE = 30859, // Infernal damage aura + + NPC_NETHERSPITE_INFERNAL = 17646, // The netherspite infernal creature + NPC_MALCHEZARS_AXE = 17650, // Malchezar's axes summoned during phase 3 + + EQUIP_ID_AXE = 23996, // Axes info + + ATTACK_TIMER_DEFAULT = 2000, // note: for TBC it was 2400 + ATTACK_TIMER_AXES = 1333, // note: for TBC it was 1600 + + MAX_ENFEEBLE_TARGETS = 5, }; struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI { boss_malchezaarAI(Creature* pCreature) : ScriptedAI(pCreature) { - for(uint8 i =0; i < 2; ++i) - axes[i] = 0; - + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - uint32 EnfeebleTimer; - uint32 EnfeebleResetTimer; - uint32 ShadowNovaTimer; - uint32 SWPainTimer; - uint32 SunderArmorTimer; - uint32 AmplifyDamageTimer; - uint32 Cleave_Timer; - uint32 InfernalTimer; - uint32 AxesTargetSwitchTimer; - uint32 InfernalCleanupTimer; + ScriptedInstance* m_pInstance; - std::vector infernals; - std::vector positions; + uint8 m_uiEnfeebleIndex; + uint32 m_uiEnfeebleTimer; + uint32 m_uiEnfeebleResetTimer; + uint32 m_uiShadowNovaTimer; + uint32 m_uiSWPainTimer; + uint32 m_uiSunderArmorTimer; + uint32 m_uiAmplifyDamageTimer; + uint32 m_uiInfernalTimer; - uint64 axes[2]; - uint64 enfeeble_targets[5]; - uint64 enfeeble_health[5]; + ObjectGuid m_aEnfeebleTargetGuid[MAX_ENFEEBLE_TARGETS]; + uint32 m_auiEnfeebleHealth[MAX_ENFEEBLE_TARGETS]; - uint32 phase; + uint8 m_uiPhase; void Reset() { - AxesCleanup(); - ClearWeapons(); - InfernalCleanup(); - positions.clear(); - - for(int i =0; i < 5; ++i) + for (uint8 i = 0; i < MAX_ENFEEBLE_TARGETS; ++i) { - enfeeble_targets[i] = 0; - enfeeble_health[i] = 0; + m_aEnfeebleTargetGuid[i].Clear(); + m_auiEnfeebleHealth[i] = 0; } - for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) - positions.push_back(&InfernalPoints[i]); - - EnfeebleTimer = 30000; - EnfeebleResetTimer = 38000; - ShadowNovaTimer = 35500; - SWPainTimer = 20000; - AmplifyDamageTimer = 5000; - Cleave_Timer = 8000; - InfernalTimer = 45000; - InfernalCleanupTimer = 47000; - AxesTargetSwitchTimer = urand(7500, 20000); - SunderArmorTimer = urand(5000, 10000); - phase = 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 *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; @@ -222,423 +125,240 @@ struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI } } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - AxesCleanup(); - ClearWeapons(); - InfernalCleanup(); - positions.clear(); + // Remove the summoned axe - which is considered a guardian + m_creature->RemoveGuardians(); - for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) - 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(std::vector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr) - { - Creature *pInfernal = m_creature->GetMap()->GetCreature(*itr); - if (pInfernal && pInfernal->isAlive()) - { - pInfernal->SetVisibility(VISIBILITY_OFF); - pInfernal->SetDeathState(JUST_DIED); - } - } - infernals.clear(); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALCHEZZAR, IN_PROGRESS); } - void AxesCleanup() + void JustReachedHome() override { - for(int i=0; i<2;++i) - { - Creature *axe = m_creature->GetMap()->GetCreature(axes[i]); - if (axe && axe->isAlive()) - axe->DealDamage(axe, axe->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - axes[i] = 0; - } - } - - void ClearWeapons() - { - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALCHEZZAR, FAIL); - //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); + // Remove the summoned axe - which is considered a guardian + m_creature->RemoveGuardians(); } - void EnfeebleHealthEffect() + void JustSummoned(Creature* pSummoned) 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 - { - Unit *target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - //only on alive players - if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); - } - - //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) - { - enfeeble_targets[i] = target->GetGUID(); - enfeeble_health[i] = target->GetHealth(); - - target->CastSpell(target, SPELL_ENFEEBLE, true, 0, 0, m_creature->GetGUID()); - target->SetHealth(1); - } - } - + if (pSummoned->GetEntry() == NPC_NETHERSPITE_INFERNAL) + pSummoned->CastSpell(pSummoned, SPELL_HELLFIRE, false); + else if (pSummoned->GetEntry() == NPC_MALCHEZARS_AXE) + pSummoned->SetInCombatWithZone(); } - void EnfeebleResetHealth() + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override { - for(int i = 0; i < 5; ++i) + // Target selection is already handled properly in core (doesn't affect tank) + if (pSpellEntry->Id == SPELL_ENFEEBLE && pTarget->GetTypeId() == TYPEID_PLAYER) { - Player* pTarget = m_creature->GetMap()->GetPlayer(enfeeble_targets[i]); - - if (pTarget && pTarget->isAlive()) - pTarget->SetHealth(enfeeble_health[i]); - - enfeeble_targets[i] = 0; - enfeeble_health[i] = 0; + // Workaround to handle health set to 1 + m_aEnfeebleTargetGuid[m_uiEnfeebleIndex] = pTarget->GetObjectGuid(); + m_auiEnfeebleHealth[m_uiEnfeebleIndex] = pTarget->GetHealth(); + pTarget->SetHealth(1); + ++m_uiEnfeebleIndex; } } - void SummonInfernal(const uint32 diff) + // Wrapper to reset health of the Enfeebled targets + void DoHandleEnfeebleHealthReset() { - InfernalPoint *point = NULL; - float posX,posY,posZ; - if ((m_creature->GetMapId() != 532) || positions.empty()) + for (int i = 0; i < m_uiEnfeebleIndex; ++i) { - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 60, posX, posY, posZ); - } - else - { - std::vector::iterator itr = positions.begin()+rand()%positions.size(); - point = *itr; - positions.erase(itr); - - posX = point->x; - posY = point->y; - posZ = INFERNAL_Z; - } + Player* pTarget = m_creature->GetMap()->GetPlayer(m_aEnfeebleTargetGuid[i]); - 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->point = point; - - pInfernalAI->malchezaar = m_creature->GetGUID(); - } + if (pTarget && pTarget->isAlive()) + pTarget->SetHealth(m_auiEnfeebleHealth[i]); - infernals.push_back(Infernal->GetGUID()); - DoCastSpellIfCan(Infernal, SPELL_INFERNAL_RELAY); + m_aEnfeebleTargetGuid[i].Clear(); + m_auiEnfeebleHealth[i] = 0; } - DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + m_uiEnfeebleIndex = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (EnfeebleResetTimer) - { - if (EnfeebleResetTimer <= diff) //Let's not forget to reset that - { - EnfeebleResetHealth(); - EnfeebleResetTimer=0; - } else EnfeebleResetTimer -= diff; - } - - if (m_creature->hasUnitState(UNIT_STAT_STUNNED)) //While shifting to phase 2 malchezaar stuns himself - return; - - if (m_creature->GetUInt64Value(UNIT_FIELD_TARGET)!=m_creature->getVictim()->GetGUID()) - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); - - if (phase == 1) + // Phase 1 - over 60% HP + if (m_uiPhase == 1) { + // transition to phase 2 if (m_creature->GetHealthPercent() < 60.0f) { - m_creature->InterruptNonMeleeSpells(false); - - phase = 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; + } } } - else if (phase == 2) + // Phase 2 - over 30% HP + else if (m_uiPhase == 2) { + // transition to phase 3 if (m_creature->GetHealthPercent() < 30.0f) { - InfernalTimer = 15000; - - phase = 3; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_AXES) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_ENFEEBLE_EFFECT, CAST_TRIGGERED); + DoScriptText(SAY_SPECIAL3, m_creature); - ClearWeapons(); + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + m_creature->SetAttackTime(BASE_ATTACK, ATTACK_TIMER_DEFAULT); - //remove thrash - m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); + // Reset Enfeebled targets if necessary + DoHandleEnfeebleHealthReset(); + m_uiEnfeebleResetTimer = 0; - DoScriptText(SAY_AXE_TOSS2, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); + m_uiShadowNovaTimer = m_uiEnfeebleTimer + 5000; + m_uiInfernalTimer = 15000; + m_uiPhase = 3; - Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - for(uint32 i=0; i<2; ++i) - { - Creature *axe = m_creature->SummonCreature(MALCHEZARS_AXE, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); - if (axe) - { - axe->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - axe->setFaction(m_creature->getFaction()); - - axes[i] = axe->GetGUID(); - if (target) - { - axe->AI()->AttackStart(target); - // axe->getThreatManager().tauntApply(target); //Taunt Apply and fade out does not work properly - // So we'll use a hack to add a lot of threat to our target - axe->AddThreat(target, 10000000.0f); - } - } + return; } - - if (ShadowNovaTimer > 35000) - ShadowNovaTimer = EnfeebleTimer + 5000; - - return; } - if (SunderArmorTimer < diff) + if (m_uiSunderArmorTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR); - SunderArmorTimer = urand(10000, 18000); - - }else SunderArmorTimer -= diff; - - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - Cleave_Timer = urand(6000, 12000); - - }else Cleave_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR) == CAST_OK) + m_uiSunderArmorTimer = urand(10000, 18000); + } + else + m_uiSunderArmorTimer -= uiDiff; } + // Phase 3 else { - if (AxesTargetSwitchTimer < diff) - { - AxesTargetSwitchTimer = 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(axes[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 AxesTargetSwitchTimer -= diff; - - if (AmplifyDamageTimer < diff) + if (m_uiAmplifyDamageTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_AMPLIFY_DAMAGE); - - AmplifyDamageTimer = urand(20000, 30000); - }else AmplifyDamageTimer -= diff; + 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 < diff) - { - SummonInfernal(diff); - InfernalTimer = phase == 3 ? 14500 : 44500; //15 secs in phase 3, 45 otherwise - }else InfernalTimer -= diff; - - if (ShadowNovaTimer < diff) + // Summon an infernal on timer + if (m_uiInfernalTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWNOVA); - ShadowNovaTimer = phase == 3 ? 31000 : -1; - } else ShadowNovaTimer -= diff; - - if (phase != 2) - { - if (SWPainTimer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_INFERNAL_RELAY_SUMMON) == CAST_OK) { - Unit* target = NULL; - if (phase == 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); - - SWPainTimer = 20000; - }else SWPainTimer -= diff; + DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + m_uiInfernalTimer = m_uiPhase == 3 ? 17000 : 45000; + } } + else + m_uiInfernalTimer -= uiDiff; - if (phase != 3) + // Cast shadow nova - on timer during phase 3, or after Enfeeble during phases 1 and 2 + if (m_uiShadowNovaTimer) { - if (EnfeebleTimer < diff) + if (m_uiShadowNovaTimer <= uiDiff) { - EnfeebleHealthEffect(); - EnfeebleTimer = 30000; - ShadowNovaTimer = 5000; - EnfeebleResetTimer = 9000; - }else EnfeebleTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_NOVA) == CAST_OK) + m_uiShadowNovaTimer = m_uiPhase == 3 ? 30000 : 0; + } + else + m_uiShadowNovaTimer -= uiDiff; } - if (phase==2) - DoMeleeAttacksIfReady(); - else - DoMeleeAttackIfReady(); - } - - void DoMeleeAttacksIfReady() - { - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE) && !m_creature->IsNonMeleeSpellCasted(false)) + // Cast SW pain during phase 1 and 3 + if (m_uiPhase != 2) { - //Check for base attack - if (m_creature->isAttackReady() && m_creature->getVictim()) + if (m_uiSWPainTimer < uiDiff) { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); + 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; } - //Check for offhand attack - if (m_creature->isAttackReady(OFF_ATTACK) && m_creature->getVictim()) + else + m_uiSWPainTimer -= uiDiff; + } + + // Cast Enfeeble during phase 1 and 2 + if (m_uiPhase != 3) + { + if (m_uiEnfeebleTimer < uiDiff) { - m_creature->AttackerStateUpdate(m_creature->getVictim(), OFF_ATTACK); - m_creature->resetAttackTimer(OFF_ATTACK); + if (DoCastSpellIfCan(m_creature, SPELL_ENFEEBLE) == CAST_OK) + { + m_uiEnfeebleTimer = 30000; + m_uiShadowNovaTimer = 5000; + m_uiEnfeebleResetTimer = 9000; + } } + else + m_uiEnfeebleTimer -= uiDiff; } - } - void Cleanup(Creature *infernal, InfernalPoint *point) - { - for(std::vector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr) - if (*itr == infernal->GetGUID()) + if (m_uiEnfeebleResetTimer) { - infernals.erase(itr); - break; + if (m_uiEnfeebleResetTimer <= uiDiff) + { + DoHandleEnfeebleHealthReset(); + m_uiEnfeebleResetTimer = 0; + } + else + m_uiEnfeebleResetTimer -= uiDiff; } - positions.push_back(point); + DoMeleeAttackIfReady(); } }; -void netherspite_infernalAI::Cleanup() +CreatureAI* GetAI_boss_malchezaar(Creature* pCreature) { - Creature* pMalchezaar = m_creature->GetMap()->GetCreature(malchezaar); - - if (pMalchezaar && pMalchezaar->isAlive()) - { - if (boss_malchezaarAI* pMalAI = dynamic_cast(pMalchezaar->AI())) - pMalAI->Cleanup(m_creature, point); - } + 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 MANGOS_DLL_DECL 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) -{ - return new boss_malchezaarAI(pCreature); -} + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; -void AddSC_netherspite_infernal() +CreatureAI* GetAI_npc_infernal_target(Creature* pCreature) { - Script *newscript; - newscript = new Script; - newscript->Name = "netherspite_infernal"; - newscript->GetAI = &GetAI_netherspite_infernal; - newscript->RegisterSelf(); + return new npc_infernal_targetAI(pCreature); } -void AddSC_boss_malchezaar() +void AddSC_boss_prince_malchezaar() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_malchezaar"; - newscript->GetAI = &GetAI_boss_malchezaar; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_malchezaar"; + pNewScript->GetAI = &GetAI_boss_malchezaar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 cae1e6146d..fb8dee118f 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,52 +35,58 @@ 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 @@ -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; - uint64 m_uiFlameWreathTarget[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() { - 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_uiFlameWreathTarget[i] = (*itr)->GetGUID(); - 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->instance->GetGameObject(m_pInstance->GetData64(DATA_GO_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_uiFireCooldown >= uiDiff) - m_uiFireCooldown -= uiDiff; - else - m_uiFireCooldown = 0; } - if (m_uiFrostCooldown) + if (m_bIsDrinking) { - 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,226 +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; + + // randomize so it won't be the same spell twice in a row + while (uiCurrentSpell == m_uiLastNormalSpell) + uiCurrentSpell = urand(0, 2); - //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; + m_uiLastNormalSpell = uiCurrentSpell; - //If no available spells wait 1 second and try again - if (uiAvailableSpells) + 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; + uint8 uiAvailableSpell = urand(SUPER_FLAME_WREATH, SUPER_ARCANE_EXPL); - case SUPER_FLAME: - DoScriptText(urand(0, 1) ? SAY_FLAMEWREATH1 : SAY_FLAMEWREATH2, m_creature); + // 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); - m_uiFlameWreath_Timer = 20000; - m_uiFlameWreathCheck_Timer = 500; + m_uiLastSuperSpell = uiAvailableSpell; - memset(&m_uiFlameWreathTarget, 0, sizeof(m_uiFlameWreathTarget)); - - 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_uiFlameWreathTarget[i]) - continue; - - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiFlameWreathTarget[i]); + 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); - if (pPlayer && !pPlayer->IsWithinDist2d(m_fFWTargPosX[i], m_fFWTargPosY[i], 3.0f)) - { - pPlayer->CastSpell(pPlayer, SPELL_EXPLOSION, true, 0, 0, m_creature->GetGUID()); - pPlayer->CastSpell(pPlayer, SPELL_KNOCKBACK_500, true); - m_uiFlameWreathTarget[i] = 0; - } - } - 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(); } }; @@ -538,22 +398,33 @@ 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 MANGOS_DLL_DECL 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() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_shade_of_aran"; - newscript->GetAI = &GetAI_boss_aran; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_shade_of_aran"; + pNewScript->GetAI = &GetAI_boss_aran; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_aran_elemental"; - newscript->GetAI = &GetAI_water_elemental; - newscript->RegisterSelf(); + pNewScript = new Script; + 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 625abba837..9bece670d7 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,203 +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(); - } - - uint64 m_uiSacrificeGUID; - - void Reset() - { - m_uiSacrificeGUID = 0; - } - - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - - void JustDied(Unit* pKiller) - { - if (m_uiSacrificeGUID) - { - if (Player* pSacrifice = m_creature->GetMap()->GetPlayer(m_uiSacrificeGUID)) - pSacrifice->RemoveAurasDueToSpell(SPELL_SACRIFICE); - } - } -}; - struct MANGOS_DLL_DECL boss_terestianAI : public ScriptedAI { boss_terestianAI(Creature* pCreature) : ScriptedAI(pCreature) { - memset(&m_uiPortalGUID, 0, sizeof(m_uiPortalGUID)); m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bSummonKilrek = true; Reset(); } ScriptedInstance* m_pInstance; - uint64 m_uiPortalGUID[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() { - 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_uiPortalGUID[i]) - { - if (Creature* pPortal = m_pInstance->instance->GetCreature(m_uiPortalGUID[i])) - pPortal->ForcedDespawn(); - - m_uiPortalGUID[i] = 0; - } - } - - 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 { - m_creature->SetInCombatWithZone(); - - 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); - else - ERROR_INST_DATA(m_creature); } - 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 + { + if (m_pInstance) + m_pInstance->SetData(TYPE_TERESTIAN, FAIL); + } + + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_PORTAL: - { - if (m_uiPortalGUID[0]) - { - m_uiPortalGUID[1] = pSummoned->GetGUID(); - - if (npc_fiendish_portalAI* pPortalAI = dynamic_cast(pSummoned->AI())) - pPortalAI->m_uiSummonTimer = 10000; - } - else + if (!m_bSummonedPortals) { - m_uiPortalGUID[0] = pSummoned->GetGUID(); + 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_uiPortalGUID[i]) - { - if (Creature* pPortal = m_pInstance->instance->GetCreature(m_uiPortalGUID[i])) - pPortal->ForcedDespawn(); - - m_uiPortalGUID[i] = 0; - } - } - - 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; @@ -240,91 +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) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) + 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_uiSacrificeGUID = pTarget->GetGUID(); - - 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 MANGOS_DLL_DECL 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() + { + m_uiSummonTimer = 5000; + } -void npc_fiendish_portalAI::UpdateAI(const uint32 uiDiff) -{ - if (m_uiSummonTimer < uiDiff) + void JustSummoned(Creature* pSummoned) override { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIENDISH_IMP); - m_uiSummonTimer = 10000; + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); + pSummoned->SetInCombatWithZone(); } - else - m_uiSummonTimer -= uiDiff; + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSummonTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIENDISH_IMP) == CAST_OK) + m_uiSummonTimer = 5000; + } + else + m_uiSummonTimer -= uiDiff; + } +}; + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct MANGOS_DLL_DECL 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) @@ -337,27 +282,22 @@ 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* newscript; - - newscript = new Script; - newscript->Name = "boss_terestian_illhoof"; - newscript->GetAI = &GetAI_boss_terestian_illhoof; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_fiendish_portal"; - newscript->GetAI = &GetAI_npc_fiendish_portal; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_demon_chain"; - newscript->GetAI = &GetAI_mob_demon_chain; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_terestian_illhoof"; + pNewScript->GetAI = &GetAI_boss_terestian_illhoof; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_fiendish_portal"; + pNewScript->GetAI = &GetAI_npc_fiendish_portal; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_demon_chain"; + pNewScript->GetAI = &GetAI_mob_demon_chain; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp b/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp index 11ed97e243..868a7f0aa8 100644 --- a/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp +++ b/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,76 +28,61 @@ 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 @@ -110,164 +95,129 @@ 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() { - 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 (m_uiIntroTimer <= uiDiff) + { + DoScriptText(SAY_DOROTHEE_AGGRO, m_creature); + m_uiIntroTimer = 0; + } + else + m_uiIntroTimer -= uiDiff; + } + + 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 (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(); - } - - uint64 DorotheeGUID; - uint32 YipTimer; - - void Reset() - { - DorotheeGUID = 0; - YipTimer = 10000; - } - - void JustDied(Unit* killer) - { - if (DorotheeGUID) + if (m_uiSummonTitoTimer) { - Creature* Dorothee = m_creature->GetMap()->GetCreature(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->DorotheeGUID = m_creature->GetGUID(); - - pTito->AI()->AttackStart(m_creature->getVictim()); - - SummonedTito = true; - TitoDied = false; - } -} - struct MANGOS_DLL_DECL boss_strawmanAI : public ScriptedAI { boss_strawmanAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -278,96 +228,92 @@ 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() { - 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() - { - m_creature->ForcedDespawn(); - } - - void SpellHit(Unit* caster, const SpellEntry *Spell) + void JustReachedHome() override { - 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(); } @@ -383,93 +329,91 @@ 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() { - 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(); } @@ -485,94 +429,105 @@ 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() { - 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(); } }; +static const float afCycloneSpawnLoc[4] = { -10907.68f, -1778.651f, 90.56018f, 0.61f}; + struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI { boss_croneAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -583,28 +538,30 @@ struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 CycloneTimer; - uint32 ChainLightningTimer; + uint32 m_uiChainLightningTimer; void Reset() { - 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); @@ -612,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); @@ -696,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->GetGUID()); + 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(); @@ -757,38 +676,31 @@ struct MANGOS_DLL_DECL boss_bigbadwolfAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 ChaseTimer; - uint32 FearTimer; - uint32 SwipeTimer; - - uint64 HoodGUID; - float TempThreat; - - bool IsChasing; + uint32 m_uiRedRidingHoodTimer; + uint32 m_uiFearTimer; + uint32 m_uiSwipeTimer; void Reset() { - ChaseTimer = 30000; - FearTimer = urand(25000, 35000); - SwipeTimer = 5000; - - HoodGUID = 0; - 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); @@ -796,66 +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) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (target && target->GetTypeId() == TYPEID_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); - - HoodGUID = target->GetGUID(); - m_creature->AddThreat(target, 1000000.0f); - ChaseTimer = 20000; - IsChasing = true; - } + DoScriptText(SAY_WOLF_HOOD, m_creature); + m_uiRedRidingHoodTimer = 30000; } - else - { - IsChasing = false; - - if (Player* target = m_creature->GetMap()->GetPlayer(HoodGUID)) - { - HoodGUID = 0; - - if (m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - m_creature->AddThreat(target, TempThreat); - TempThreat = 0; - } - - ChaseTimer = 40000; - } - }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(); } }; @@ -868,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 { - PHASE_JULIANNE = 0, - PHASE_ROMULO = 1, - PHASE_BOTH = 2, + /**** 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 }; -void PretendToDie(Creature* pCreature) +enum OperaPhase { - 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); + PHASE_JULIANNE = 0, + PHASE_ROMULO = 1, + PHASE_BOTH = 2, }; -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(); -}; +static const float afRomuloSpawnLoc[4] = { -10893.62f, -1760.78f, 90.55f, 4.76f}; struct MANGOS_DLL_DECL 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; - - uint64 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() { - RomuloGUID = 0; - 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; - - uint64 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() { - JulianneGUID = 0; - Phase = PHASE_ROMULO; + m_bIsFakingDeath = true; - BackwardLungeTimer = 15000; - DaringTimer = 20000; - DeadlySwatheTimer = 25000; - PoisonThrustTimer = 10000; - ResurrectTimer = 10000; - - 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 (JulianneGUID) + if (DoCastSpellIfCan(m_creature, SPELL_UNDYING_LOVE) == CAST_OK) { - Creature* Julianne = m_creature->GetMap()->GetCreature(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) + void UpdateAI(const uint32 uiDiff) override { - 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) - { - //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(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(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(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(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(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 MANGOS_DLL_DECL 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)) - { - RomuloGUID = pRomulo->GetGUID(); + ScriptedInstance* m_pInstance; - if (boss_romuloAI* pRomAI = dynamic_cast(pRomulo->AI())) - { - pRomAI->JulianneGUID = m_creature->GetGUID(); - pRomAI->Phase = PHASE_ROMULO; - } + OperaPhase m_Phase; - pRomulo->SetInCombatWithZone(); + uint32 m_uiBackwardLungeTimer; + uint32 m_uiDaringTimer; + uint32 m_uiDeadlySwatheTimer; + uint32 m_uiPoisonThrustTimer; + uint32 m_uiResurrectTimer; + uint32 m_uiResurrectSelfTimer; - //why? - pRomulo->setFaction(16); - } - SummonedRomulo = true; - }else SummonRomuloTimer -= diff; - } + bool m_bIsFakingDeath; - if (ResurrectSelfTimer) + void Reset() { - 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); - if (RomuloDead) + m_creature->ForcedDespawn(); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (ResurrectTimer < diff) - { - Creature* pRomulo = m_creature->GetMap()->GetCreature(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(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(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) { @@ -1457,64 +1279,55 @@ CreatureAI* GetAI_boss_romulo(Creature* pCreature) void AddSC_bosses_opera() { - Script* newscript; + Script* pNewScript; // Oz - newscript = new Script; - newscript->GetAI = &GetAI_boss_dorothee; - newscript->Name = "boss_dorothee"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_strawman; - newscript->Name = "boss_strawman"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_tinhead; - newscript->Name = "boss_tinhead"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_roar; - newscript->Name = "boss_roar"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_crone; - newscript->Name = "boss_crone"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_mob_tito; - newscript->Name = "mob_tito"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_mob_cyclone; - newscript->Name = "mob_cyclone"; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_dorothee"; + pNewScript->GetAI = &GetAI_boss_dorothee; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_strawman"; + pNewScript->GetAI = &GetAI_boss_strawman; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_tinhead"; + pNewScript->GetAI = &GetAI_boss_tinhead; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_roar"; + pNewScript->GetAI = &GetAI_boss_roar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crone"; + pNewScript->GetAI = &GetAI_boss_crone; + pNewScript->RegisterSelf(); // Hood - newscript = new Script; - newscript->pGossipHello = &GossipHello_npc_grandmother; - newscript->pGossipSelect = &GossipSelect_npc_grandmother; - newscript->Name = "npc_grandmother"; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_grandmother"; + pNewScript->pGossipHello = &GossipHello_npc_grandmother; + pNewScript->pGossipSelect = &GossipSelect_npc_grandmother; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->GetAI = &GetAI_boss_bigbadwolf; - newscript->Name = "boss_bigbadwolf"; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_bigbadwolf"; + pNewScript->GetAI = &GetAI_boss_bigbadwolf; + pNewScript->RegisterSelf(); // Romeo And Juliet - newscript = new Script; - newscript->GetAI = &GetAI_boss_julianne; - newscript->Name = "boss_julianne"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_romulo; - newscript->Name = "boss_romulo"; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_julianne"; + pNewScript->GetAI = &GetAI_boss_julianne; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_drink_poison; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 new file mode 100644 index 0000000000..e12cb3275c --- /dev/null +++ b/scripts/eastern_kingdoms/karazhan/chess_event.cpp @@ -0,0 +1,1765 @@ +/* Copyright (C) 2006 - 2013 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: chess_event +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 MANGOS_DLL_DECL 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() + { + 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 MANGOS_DLL_DECL 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() + { + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 MANGOS_DLL_DECL 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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->GetRecoveryTime() ? pSpell->GetRecoveryTime() : pSpell->GetCategoryRecoveryTime(); + } + + 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 554f705be5..7392812ade 100644 --- a/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp +++ b/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 */ @@ -28,259 +28,580 @@ EndScriptData */ 0 - Attumen + Midnight (optional) 1 - Moroes 2 - Maiden of Virtue (optional) -3 - Hyakiss the Lurker / Rokad the Ravager / Shadikith the Glider -4 - Opera Event -5 - Curator +3 - Opera Event +4 - Curator +5 - Terestian Illhoof (optional) 6 - Shade of Aran (optional) -7 - Terestian Illhoof (optional) -8 - Netherspite (optional) -9 - Chess Event -10 - Prince Malchezzar -11 - Nightbane +7 - Netherspite (optional) +8 - Chess Event +9 - Prince Malchezzar +10 - Nightbane */ -struct MANGOS_DLL_DECL instance_karazhan : public ScriptedInstance +instance_karazhan::instance_karazhan(Map* pMap) : ScriptedInstance(pMap), + m_uiOperaEvent(0), + m_uiOzDeathCount(0), + m_uiTeam(0), + m_uiChessResetTimer(0), + m_uiAllianceStalkerCount(0), + m_uiHordeStalkerCount(0), + m_bFriendlyGame(false) { - instance_karazhan(Map* pMap) : ScriptedInstance(pMap) {Initialize();} - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint32 m_uiOperaEvent; - uint32 m_uiOzDeathCount; - - uint64 m_uiCurtainGUID; - uint64 m_uiStageDoorLeftGUID; - uint64 m_uiStageDoorRightGUID; - uint64 m_uiTerestianGUID; - uint64 m_uiMoroesGUID; - uint64 m_uiLibraryDoor; // Door at Shade of Aran - uint64 m_uiMassiveDoor; // Door at Netherspite - uint64 m_uiSideEntranceDoor; // Side Entrance - uint64 m_uiGamesmansDoor; // Door before Chess - uint64 m_uiGamesmansExitDoor; // Door after Chess - uint64 m_uiNetherspaceDoor; // Door at Malchezaar - uint64 m_uiDustCoveredChest; // Chest respawn at event complete - - void Initialize() + Initialize(); +} + +void instance_karazhan::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +bool instance_karazhan::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - // 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered. - m_uiOperaEvent = urand(EVENT_OZ,EVENT_RAJ); - m_uiOzDeathCount = 0; - - m_uiCurtainGUID = 0; - m_uiStageDoorLeftGUID = 0; - m_uiStageDoorRightGUID = 0; - - m_uiTerestianGUID = 0; - m_uiMoroesGUID = 0; - - m_uiLibraryDoor = 0; - m_uiMassiveDoor = 0; - m_uiSideEntranceDoor = 0; - m_uiGamesmansDoor = 0; - m_uiGamesmansExitDoor = 0; - m_uiNetherspaceDoor = 0; - m_uiDustCoveredChest = 0; + if (m_auiEncounter[i] == IN_PROGRESS) + return true; } - bool IsEncounterInProgress() const - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; + return false; +} - 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 OnCreatureCreate(Creature* pCreature) +void instance_karazhan::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch (pCreature->GetEntry()) - { - case 15688: m_uiTerestianGUID = pCreature->GetGUID(); break; - case 15687: m_uiMoroesGUID = pCreature->GetGUID(); break; - } + 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 OnObjectCreate(GameObject* pGo) +void instance_karazhan::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pGo->GetEntry()) - { - case 183932: m_uiCurtainGUID = pGo->GetGUID(); break; - case 184278: - m_uiStageDoorLeftGUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 184279: - m_uiStageDoorRightGUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 184517: m_uiLibraryDoor = pGo->GetGUID(); break; - case 185521: m_uiMassiveDoor = pGo->GetGUID(); break; - case 184276: m_uiGamesmansDoor = pGo->GetGUID(); break; - case 184277: m_uiGamesmansExitDoor = pGo->GetGUID(); break; - case 185134: m_uiNetherspaceDoor = pGo->GetGUID(); break; - case 184275: - m_uiSideEntranceDoor = pGo->GetGUID(); - if (m_auiEncounter[4] != DONE) - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); - else - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); - break; - case 185119: m_uiDustCoveredChest = pGo->GetGUID(); break; - } + case GO_STAGE_DOOR_LEFT: + case GO_STAGE_DOOR_RIGHT: + if (m_auiEncounter[3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GAMESMANS_HALL_EXIT_DOOR: + if (m_auiEncounter[8] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SIDE_ENTRANCE_DOOR: + 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: + break; + + // Opera event backgrounds + case GO_OZ_BACKDROP: + case GO_HOOD_BACKDROP: + case GO_HOOD_HOUSE: + case GO_RAJ_BACKDROP: + case GO_RAJ_MOON: + case GO_RAJ_BALCONY: + break; + case GO_OZ_HAY: + m_lOperaHayGuidList.push_back(pGo->GetObjectGuid()); + return; + case GO_HOOD_TREE: + m_lOperaTreeGuidList.push_back(pGo->GetObjectGuid()); + return; - switch(m_uiOperaEvent) - { - //TODO: Set DoRespawnGameObject for Opera based on performance - case EVENT_OZ: - break; - case EVENT_HOOD: - break; - case EVENT_RAJ: - break; - } + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void SetData(uint32 uiType, uint32 uiData) +void instance_karazhan::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(uiType) - { - case TYPE_ATTUMEN: m_auiEncounter[0] = uiData; break; - case TYPE_MOROES: - if (m_auiEncounter[1] != DONE) - m_auiEncounter[1] = uiData; - break; - case TYPE_MAIDEN: m_auiEncounter[2] = uiData; break; - case TYPE_OPTIONAL_BOSS: m_auiEncounter[3] = uiData; break; - case TYPE_OPERA: - m_auiEncounter[4] = uiData; - if (uiData == DONE) + case TYPE_ATTUMEN: + m_auiEncounter[uiType] = uiData; + if (uiData == FAIL) + { + // Respawn Midnight on Fail + if (Creature* pMidnight = GetSingleCreatureFromStorage(NPC_MIDNIGHT)) { - DoUseDoorOrButton(m_uiStageDoorLeftGUID); - DoUseDoorOrButton(m_uiStageDoorRightGUID); - if (GameObject* pSideEntrance = instance->GetGameObject(m_uiSideEntranceDoor)) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + if (!pMidnight->isAlive()) + pMidnight->Respawn(); } + } + break; + case TYPE_MOROES: + case TYPE_MAIDEN: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_OPERA: + // Don't store the same data twice + if (uiData == m_auiEncounter[uiType]) break; - case TYPE_CURATOR: m_auiEncounter[5] = uiData; break; - case TYPE_ARAN: - m_auiEncounter[6] = uiData; - if (uiData != IN_PROGRESS) - DoUseDoorOrButton(m_uiLibraryDoor); - break; - case TYPE_TERESTIAN: m_auiEncounter[7] = uiData; break; - case TYPE_NETHERSPITE: - m_auiEncounter[8] = uiData; - DoUseDoorOrButton(m_uiMassiveDoor); - break; - case TYPE_CHESS: - if (uiData == DONE) - DoRespawnGameObject(m_uiDustCoveredChest,DAY); - m_auiEncounter[9] = uiData; - break; - case TYPE_MALCHEZZAR: m_auiEncounter[10] = uiData; break; - case TYPE_NIGHTBANE: m_auiEncounter[11] = uiData; break; - case DATA_OPERA_OZ_DEATHCOUNT: - if (uiData == SPECIAL) - ++m_uiOzDeathCount; - else if (uiData == IN_PROGRESS) - m_uiOzDeathCount = 0; - 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: + case TYPE_TERESTIAN: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_ARAN: + 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[uiType] = uiData; + DoUseDoorOrButton(GO_MASSIVE_DOOR); + break; + case TYPE_CHESS: + if (uiData == DONE) + { + // 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); + } - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; + // 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); + } - 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_uiChessResetTimer = 35000; + } + else if (uiData == IN_PROGRESS || uiData == SPECIAL) + DoPrepareChessEvent(); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_MALCHEZZAR: + DoUseDoorOrButton(GO_NETHERSPACE_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_NIGHTBANE: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_MASTERS_TERRACE_DOOR_1); + DoUseDoorOrButton(GO_MASTERS_TERRACE_DOOR_2); + break; + // Store the event type for the Opera + case TYPE_OPERA_PERFORMANCE: + m_uiOperaEvent = uiData; + break; + } - strInstData = saveStream.str(); + // Also save the opera performance, once it's set + if (uiData == DONE || uiType == TYPE_OPERA_PERFORMANCE) + { + OUT_SAVE_INST_DATA; - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + 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_uiOperaEvent; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_karazhan::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + if (uiType == TYPE_OPERA_PERFORMANCE) + return m_uiOperaEvent; + + return 0; +} + +void instance_karazhan::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; } - const char* Save() + 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] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_uiOperaEvent; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - return strInstData.c_str(); + if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. + m_auiEncounter[i] = NOT_STARTED; } - uint32 GetData(uint32 uiType) + 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) { - switch (uiType) + if (Creature* pChessPiece = instance->GetCreature(*itr)) { - case TYPE_ATTUMEN: return m_auiEncounter[0]; - case TYPE_MOROES: return m_auiEncounter[1]; - case TYPE_MAIDEN: return m_auiEncounter[2]; - case TYPE_OPTIONAL_BOSS: return m_auiEncounter[3]; - case TYPE_OPERA: return m_auiEncounter[4]; - case TYPE_CURATOR: return m_auiEncounter[5]; - case TYPE_ARAN: return m_auiEncounter[6]; - case TYPE_TERESTIAN: return m_auiEncounter[7]; - case TYPE_NETHERSPITE: return m_auiEncounter[8]; - case TYPE_CHESS: return m_auiEncounter[9]; - case TYPE_MALCHEZZAR: return m_auiEncounter[10]; - case TYPE_NIGHTBANE: return m_auiEncounter[11]; - case DATA_OPERA_PERFORMANCE: return m_uiOperaEvent; - case DATA_OPERA_OZ_DEATHCOUNT: return m_uiOzDeathCount; + 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); } - - return 0; } - uint64 GetData64(uint32 uiData) + for (GuidList::const_iterator itr = m_lChessPiecesHorde.begin(); itr != m_lChessPiecesHorde.end(); ++itr) { - switch (uiData) + if (Creature* pChessPiece = instance->GetCreature(*itr)) { - case DATA_TERESTIAN: return m_uiTerestianGUID; - case DATA_MOROES: return m_uiMoroesGUID; - case DATA_GO_STAGEDOORLEFT: return m_uiStageDoorLeftGUID; - case DATA_GO_STAGEDOORRIGHT: return m_uiStageDoorRightGUID; - case DATA_GO_CURTAINS: return m_uiCurtainGUID; - case DATA_GO_LIBRARY_DOOR: return m_uiLibraryDoor; - case DATA_GO_MASSIVE_DOOR: return m_uiMassiveDoor; - case DATA_GO_SIDE_ENTRANCE_DOOR: return m_uiSideEntranceDoor; - case DATA_GO_GAME_DOOR: return m_uiGamesmansDoor; - case DATA_GO_GAME_EXIT_DOOR: return m_uiGamesmansExitDoor; - case DATA_GO_NETHER_DOOR: return m_uiNetherspaceDoor; + 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; + } - return 0; + // 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); } - void Load(const char* chrIn) + if (lStalkers.empty()) { - if (!chrIn) + 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) { - OUT_LOAD_INST_DATA_FAIL; - return; + if (Creature* pStalker = instance->GetCreature(*itr)) + pStalker->HandleEmote(EMOTE_STATE_APPLAUD); } + } +} - OUT_LOAD_INST_DATA(chrIn); +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; + } - std::istringstream loadStream(chrIn); + SetData(TYPE_OPERA, IN_PROGRESS); +} - 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]; +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); + } + } - 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; + if (GetData(TYPE_CHESS) == FAIL) + SetData(TYPE_CHESS, NOT_STARTED); + else if (GetData(TYPE_CHESS) == DONE) + m_bFriendlyGame = true; - OUT_LOAD_INST_DATA_COMPLETE; + m_uiChessResetTimer = 0; + } + else + m_uiChessResetTimer -= uiDiff; } -}; +} InstanceData* GetInstanceData_instance_karazhan(Map* pMap) { @@ -289,9 +610,10 @@ InstanceData* GetInstanceData_instance_karazhan(Map* pMap) void AddSC_instance_karazhan() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_karazhan"; - newscript->GetInstanceData = &GetInstanceData_instance_karazhan; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_karazhan"; + pNewScript->GetInstanceData = &GetInstanceData_instance_karazhan; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/karazhan.cpp b/scripts/eastern_kingdoms/karazhan/karazhan.cpp index 40f1432db9..3eeb08b44e 100644 --- a/scripts/eastern_kingdoms/karazhan/karazhan.cpp +++ b/scripts/eastern_kingdoms/karazhan/karazhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 MANGOS_DLL_DECL 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; - - uint64 m_uiSpotlightGUID; - - uint32 m_uiTalkCount; - uint32 m_uiTalkTimer; - uint32 m_uiWipeTimer; - uint32 m_uiEventId; + instance_karazhan* m_pInstance; - bool m_bPerformanceReady; - bool m_bRaidWiped; + ObjectGuid m_spotlightGuid; void Reset() { - m_uiSpotlightGUID = 0; - - m_uiTalkCount = 0; - m_uiTalkTimer = 2000; - m_uiWipeTimer = 5000; - - m_bPerformanceReady = false; - - if (m_pInstance) - m_uiEventId = m_pInstance->GetData(DATA_OPERA_PERFORMANCE); + m_spotlightGuid.Clear(); } - 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, 0, 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); - m_pInstance->DoUseDoorOrButton(m_pInstance->GetData64(DATA_GO_STAGEDOORLEFT)); + 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_uiSpotlightGUID = pSpotlight->GetGUID(); + 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(m_pInstance->GetData64(DATA_GO_STAGEDOORLEFT)); - m_bPerformanceReady = true; + m_pInstance->DoUseDoorOrButton(GO_STAGE_DOOR_LEFT); break; case 9: - PrepareEncounter(); - m_pInstance->DoUseDoorOrButton(m_pInstance->GetData64(DATA_GO_CURTAINS)); - 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_uiSpotlightGUID)) - 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->GetGUID()); - else - pPlayer->SEND_GOSSIP_MENU(8975, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_OPERA_1, pCreature->GetObjectGuid()); - return true; - } + return true; } } - pPlayer->SEND_GOSSIP_MENU(8978, pCreature->GetGUID()); 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->GetGUID()); + 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: pPlayer (GUID " UI64FMTD ") manually set Opera event to EVENT_OZ", pPlayer->GetGUID()); + 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: pPlayer (GUID " UI64FMTD ") manually set Opera event to EVENT_HOOD", pPlayer->GetGUID()); + 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: pPlayer (GUID " UI64FMTD ") manually set Opera event to EVENT_RAJ", pPlayer->GetGUID()); + 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->GetGUID()); + 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,20 +286,256 @@ 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 MANGOS_DLL_DECL 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() { } + + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + } + } + + 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 MANGOS_DLL_DECL npc_image_arcanagosAI : public ScriptedAI +{ + npc_image_arcanagosAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() { } + + 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* newscript; - - newscript = new Script; - newscript->Name = "npc_barnes"; - newscript->GetAI = &GetAI_npc_barnesAI; - newscript->pGossipHello = &GossipHello_npc_barnes; - newscript->pGossipSelect = &GossipSelect_npc_barnes; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_berthold"; - newscript->pGossipHello = &GossipHello_npc_berthold; - newscript->pGossipSelect = &GossipSelect_npc_berthold; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_barnes"; + pNewScript->GetAI = &GetAI_npc_barnesAI; + pNewScript->pGossipHello = &GossipHello_npc_barnes; + pNewScript->pGossipSelect = &GossipSelect_npc_barnes; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_berthold"; + 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 e1d75d9731..eca060b68b 100644 --- a/scripts/eastern_kingdoms/karazhan/karazhan.h +++ b/scripts/eastern_kingdoms/karazhan/karazhan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,58 +7,199 @@ enum { - MAX_ENCOUNTER = 12, - - TYPE_ATTUMEN = 1, - TYPE_MOROES = 2, - TYPE_MAIDEN = 3, - TYPE_OPTIONAL_BOSS = 4, - TYPE_OPERA = 5, - TYPE_CURATOR = 6, - TYPE_ARAN = 7, - TYPE_TERESTIAN = 8, - TYPE_NETHERSPITE = 9, - TYPE_CHESS = 10, - TYPE_MALCHEZZAR = 11, - TYPE_NIGHTBANE = 12, - - DATA_OPERA_PERFORMANCE = 13, - DATA_OPERA_OZ_DEATHCOUNT = 14, - - DATA_TERESTIAN = 16, - DATA_MOROES = 17, - - DATA_GO_CURTAINS = 18, - DATA_GO_STAGEDOORLEFT = 19, - DATA_GO_STAGEDOORRIGHT = 20, - DATA_GO_LIBRARY_DOOR = 21, - DATA_GO_MASSIVE_DOOR = 22, - DATA_GO_NETHER_DOOR = 23, - DATA_GO_GAME_DOOR = 24, - DATA_GO_GAME_EXIT_DOOR = 25, - DATA_GO_SIDE_ENTRANCE_DOOR = 26 + MAX_ENCOUNTER = 11, + MAX_OZ_OPERA_MOBS = 4, + + TYPE_ATTUMEN = 0, + TYPE_MOROES = 1, + TYPE_MAIDEN = 2, + TYPE_OPERA = 3, + TYPE_CURATOR = 4, + TYPE_TERESTIAN = 5, + TYPE_ARAN = 6, + TYPE_NETHERSPITE = 7, + TYPE_CHESS = 8, + TYPE_MALCHEZZAR = 9, + TYPE_NIGHTBANE = 10, + TYPE_OPERA_PERFORMANCE = 11, // no regular encounter - just store one random opera event + + 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, + GO_STAGE_DOOR_RIGHT = 184279, + GO_PRIVATE_LIBRARY_DOOR = 184517, + GO_MASSIVE_DOOR = 185521, + GO_GAMESMANS_HALL_DOOR = 184276, + GO_GAMESMANS_HALL_EXIT_DOOR = 184277, + 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, + + // Opera event stage decoration + GO_OZ_BACKDROP = 183442, + GO_OZ_HAY = 183496, + GO_HOOD_BACKDROP = 183491, + GO_HOOD_TREE = 183492, + GO_HOOD_HOUSE = 183493, + 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; +}; + +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}, }; -#define ERROR_INST_DATA(a) error_log("SD2: Instance Data for Karazhan not set properly. Encounter for Creature Entry %u may not work properly.", a->GetEntry()); +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}; -class MANGOS_DLL_DECL npc_fiendish_portalAI : public ScriptedAI +static const float afChroneSpawnLoc[4] = { -10893.11f, -1757.85f, 90.55f, 4.60f}; + +class MANGOS_DLL_DECL instance_karazhan : public ScriptedInstance { public: - npc_fiendish_portalAI(Creature* pCreature); - ~npc_fiendish_portalAI() {} + instance_karazhan(Map* pMap); + ~instance_karazhan() {} + + 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; + + 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; + + 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 9671a4ed5d..5cd65de488 100644 --- a/scripts/eastern_kingdoms/loch_modan.cpp +++ b/scripts/eastern_kingdoms/loch_modan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -36,43 +36,43 @@ EndContentData */ bool GossipHello_npc_mountaineer_pebblebitty(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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->GetGUID()); + 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); - pPlayer->SEND_GOSSIP_MENU(1833, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1833, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ok, so what is this other way?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(1834, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1834, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Doesn't matter, i'm invulnerable.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(1835, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1835, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+4: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Yes...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(1836, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1836, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+5: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ok, i'll try to remember that.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(1837, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1837, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+6: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "A key? Ok!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - pPlayer->SEND_GOSSIP_MENU(1838, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1838, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+7: pPlayer->CLOSE_GOSSIP_MENU(); @@ -97,15 +97,10 @@ enum NPC_DARK_IRON_DWARF = 2149 }; -struct Location +static const LOCATION m_afAmbushSpawn[] = { - float m_fX, m_fY, m_fZ, m_fO; -}; - -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 @@ -123,14 +118,14 @@ struct MANGOS_DLL_DECL npc_miranAI: public npc_escortAI m_uiDwarves = 0; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { case 19: DoScriptText(SAY_MIRAN_1, m_creature); - m_creature->SummonCreature(NPC_DARK_IRON_DWARF, m_afAmbushSpawn[0].m_fX, m_afAmbushSpawn[0].m_fY, m_afAmbushSpawn[0].m_fZ, m_afAmbushSpawn[0].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000); - m_creature->SummonCreature(NPC_DARK_IRON_DWARF, m_afAmbushSpawn[1].m_fX, m_afAmbushSpawn[1].m_fY, m_afAmbushSpawn[1].m_fZ, m_afAmbushSpawn[1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000); + m_creature->SummonCreature(NPC_DARK_IRON_DWARF, m_afAmbushSpawn[0].x, m_afAmbushSpawn[0].y, m_afAmbushSpawn[0].z, m_afAmbushSpawn[0].o, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000); + m_creature->SummonCreature(NPC_DARK_IRON_DWARF, m_afAmbushSpawn[1].x, m_afAmbushSpawn[1].y, m_afAmbushSpawn[1].z, m_afAmbushSpawn[1].o, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000); break; case 23: DoScriptText(SAY_MIRAN_3, m_creature); @@ -140,7 +135,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 +145,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,8 +161,8 @@ 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())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + if (npc_miranAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -179,17 +174,17 @@ CreatureAI* GetAI_npc_miran(Creature* pCreature) void AddSC_loch_modan() { - Script* newscript; - - newscript = new Script; - newscript->Name = "npc_mountaineer_pebblebitty"; - newscript->pGossipHello = &GossipHello_npc_mountaineer_pebblebitty; - newscript->pGossipSelect = &GossipSelect_npc_mountaineer_pebblebitty; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_miran"; - newscript->GetAI = &GetAI_npc_miran; - newscript->pQuestAccept = &QuestAccept_npc_miran; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_mountaineer_pebblebitty"; + pNewScript->pGossipHello = &GossipHello_npc_mountaineer_pebblebitty; + pNewScript->pGossipSelect = &GossipSelect_npc_mountaineer_pebblebitty; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_miran"; + pNewScript->GetAI = &GetAI_npc_miran; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_miran; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp index 17126af400..ca727e99ad 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,238 +16,272 @@ /* 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" - -#define SAY_AGGRO -1585023 //This yell should be done when the room is cleared. For now, set it as a movelineofsight yell. -#define SAY_PHOENIX -1585024 -#define SAY_FLAMESTRIKE -1585025 -#define SAY_GRAVITY_LAPSE -1585026 -#define SAY_TIRED -1585027 -#define SAY_RECAST_GRAVITY -1585028 -#define SAY_DEATH -1585029 - -/*** Spells ***/ - -// Phase 1 spells -#define SPELL_FIREBALL_NORMAL 44189 // Deals 2700-3300 damage at current target -#define SPELL_FIREBALL_HEROIC 46164 // 4950-6050 - -#define SPELL_PHOENIX 44194 // Summons a phoenix (Doesn't work?) -#define SPELL_PHOENIX_BURN 44197 // A spell Phoenix uses to damage everything around -#define SPELL_REBIRTH_DMG 44196 // DMG if a Phoenix rebirth happen - -#define SPELL_FLAME_STRIKE_DUMMY 44191 // Flamestrike indicator before the damage -#define SPELL_FLAME_STRIKE 44192 // Summons the trigger + animation (projectile) - -#define SPELL_SHOCK_BARRIER 46165 // Heroic only; 10k damage shield, followed by Pyroblast -#define SPELL_PYROBLAST 36819 // Heroic only; 45-55k fire damage - -// Phase 2 spells -#define SPELL_GRAVITY_LAPSE_INITIAL 44224 // Cast at the beginning of every Gravity Lapse -#define SPELL_GRAVITY_LAPSE_CHANNEL 44251 // Channeled; blue beam animation to every enemy in range -#define SPELL_TELEPORT_CENTER 44218 // Should teleport people to the center. Requires DB entry in spell_target_position. -#define SPELL_GRAVITY_LAPSE_FLY 44227 // Hastens flyspeed and allows flying for 1 minute. For some reason removes 44226. -#define SPELL_GRAVITY_LAPSE_DOT 44226 // Knocks up in the air and applies a 300 DPS DoT. -#define SPELL_ARCANE_SPHERE_PASSIVE 44263 // Passive auras on Arcane Spheres -#define SPELL_POWER_FEEDBACK 44233 // Stuns him, making him take 50% more damage for 10 seconds. Cast after Gravity Lapse - -/*** Creatures ***/ -#define NPC_FLAME_STRIKE_TRIGGER 24666 -#define CREATURE_PHOENIX 24674 -#define CREATURE_PHOENIX_EGG 24675 -#define CREATURE_ARCANE_SPHERE 24708 - -/** Locations **/ -float KaelLocations[3][2]= + +enum { - {148.744659f, 181.377426f}, - {140.823883f, 195.403046f}, - {156.574188f, 195.650482f}, + 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, + SAY_TIRED = -1585027, + SAY_RECAST_GRAVITY = -1585028, + SAY_DEATH = -1585029, + + // 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_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 = 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_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, }; -#define LOCATION_Z -16.727455f +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}, +}; + +// Spells used to teleport players for Gravity Lapse +static const uint32 aGravityLapseSpells[] = {44219, 44220, 44221, 44222, 44223}; + +/*###### +## boss_felblood_kaelthas +######*/ -struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI +struct MANGOS_DLL_DECL 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(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 FireballTimer; - uint32 PhoenixTimer; - uint32 FlameStrikeTimer; - uint32 CombatPulseTimer; + uint32 m_uiFireballTimer; + uint32 m_uiPhoenixTimer; + uint32 m_uiFlameStrikeTimer; - //Heroic only - uint32 PyroblastTimer; + // Heroic only + uint32 m_uiShockBarrierTimer; + uint32 m_uiPyroblastTimer; - uint32 GravityLapseTimer; - uint32 GravityLapsePhase; - // 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_uiGravityLapseTimer; + uint32 m_uiGravityLapseStage; + uint8 m_uiGravityIndex; - bool FirstGravityLapse; - bool HasTaunted; - - uint8 Phase; - // 0 = Not started - // 1 = Fireball; Summon Phoenix; Flamestrike - // 2 = Gravity Lapses + bool m_bIsFirstPhase; + bool m_bFirstGravityLapse; + bool m_bHasTaunted; void Reset() { - // TODO: Timers - FireballTimer = 0; - PhoenixTimer = 10000; - FlameStrikeTimer = 25000; - CombatPulseTimer = 0; + m_uiFireballTimer = 0; + m_uiPhoenixTimer = 10000; + m_uiFlameStrikeTimer = 25000; - PyroblastTimer = 60000; + m_uiPyroblastTimer = 0; + m_uiShockBarrierTimer = 60000; - GravityLapseTimer = 0; - GravityLapsePhase = 0; + m_uiGravityLapseTimer = 1000; + m_uiGravityLapseStage = 0; + m_uiGravityIndex = 0; - FirstGravityLapse = true; - HasTaunted = false; + m_bFirstGravityLapse = true; + m_bIsFirstPhase = true; - Phase = 0; + SetCombatMovement(true); + } + void JustDied(Unit* /*pKiller*/) override + { if (m_pInstance) - { - m_pInstance->SetData(DATA_KAELTHAS_EVENT, NOT_STARTED); - - if (GameObject* pDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_KAEL_DOOR))) - pDoor->SetGoState(GO_STATE_ACTIVE); // Open the big encounter door. Close it in Aggro and open it only in JustDied(and here) - // Small door opened after event are expected to be closed by default - } + m_pInstance->SetData(TYPE_KAELTHAS, DONE); } - void JustDied(Unit *killer) + void Aggro(Unit* /*pWho*/) override { - DoScriptText(SAY_DEATH, m_creature); - - if (!m_pInstance) - return; - - if (GameObject* pEncounterDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_KAEL_DOOR))) - pEncounterDoor->SetGoState(GO_STATE_ACTIVE); // Open the encounter door + if (m_pInstance) + m_pInstance->SetData(TYPE_KAELTHAS, IN_PROGRESS); } - void DamageTaken(Unit* done_by, uint32 &damage) + void JustReachedHome() override { - if (damage > m_creature->GetHealth()) - RemoveGravityLapse(); // Remove Gravity Lapse so that players fall to ground if they kill him when in air. + if (m_pInstance) + m_pInstance->SetData(TYPE_KAELTHAS, FAIL); } - void Aggro(Unit *who) + // 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_pInstance) + if (uiDamage < m_creature->GetHealth()) return; - if (GameObject* pEncounterDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_KAEL_DOOR))) - pEncounterDoor->SetGoState(GO_STATE_READY); //Close the encounter door, open it in JustDied/Reset + // Make sure it won't die by accident + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + uiDamage = 0; + return; + } + + 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 MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { - if (!HasTaunted && m_creature->IsWithinDistInMap(who, 40.0)) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->IsWithinDistInMap(pWho, 40.0) && m_creature->IsWithinLOSInMap(pWho)) { - DoScriptText(SAY_AGGRO, m_creature); - HasTaunted = true; + StartNextDialogueText(SAY_INTRO_1); + m_creature->HandleEmote(EMOTE_STATE_TALK); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_bHasTaunted = true; } - ScriptedAI::MoveInLineOfSight(who); - } + // Allow him to finish intro + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) + return; - void JustSummoned(Creature* pSummoned) - { - if (pSummoned->GetEntry() == NPC_FLAME_STRIKE_TRIGGER) - pSummoned->CastSpell(pSummoned, SPELL_FLAME_STRIKE_DUMMY, false, NULL, NULL, m_creature->GetGUID()); + ScriptedAI::MoveInLineOfSight(pWho); } - void SetThreatList(Creature* SummonedUnit) + void JustDidDialogueStep(int32 iEntry) override { - if (!SummonedUnit) - return; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + 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 { - float x = KaelLocations[0][0]; - float y = KaelLocations[0][1]; - - DoCastSpellIfCan(m_creature, SPELL_TELEPORT_CENTER, CAST_TRIGGERED); - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + if (m_creature->Attack(pWho, true)) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - 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->GetGUID()); + // 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 { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + // Handle Gravity Lapse on targets + if (pSpell->Id == SPELL_GRAVITY_LAPSE && pTarget->GetTypeId() == TYPEID_PLAYER) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - // 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->GetGUID()); + 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() { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + GuidVector vGuids; + m_creature->FillGuidsListFromThreatList(vGuids); + + for (GuidVector::const_iterator itr = vGuids.begin(); itr != vGuids.end(); ++itr) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); + Unit* pUnit = m_creature->GetMap()->GetUnit(*itr); if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) { @@ -257,331 +291,342 @@ struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { + DialogueUpdate(uiDiff); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - switch(Phase) + // 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 (PyroblastTimer < diff) + 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); - PyroblastTimer = 60000; - }else PyroblastTimer -= diff; + m_uiPyroblastTimer = 1000; + m_uiShockBarrierTimer = 60000; + } } + else + m_uiShockBarrierTimer -= uiDiff; - if (FireballTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FIREBALL_NORMAL : SPELL_FIREBALL_HEROIC); - FireballTimer = urand(2000, 6000); - }else FireballTimer -= diff; - - if (PhoenixTimer < diff) + if (m_uiPyroblastTimer) { - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) + if (m_uiPyroblastTimer <= uiDiff) { - uint32 random = urand(1, 2); - float x = KaelLocations[random][0]; - float y = KaelLocations[random][1]; - - if (Creature* Phoenix = m_creature->SummonCreature(CREATURE_PHOENIX, x, y, LOCATION_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000)) - { - Phoenix->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - SetThreatList(Phoenix); - Phoenix->AI()->AttackStart(pTarget); - DoScriptText(SAY_PHOENIX, m_creature); - } + if (DoCastSpellIfCan(m_creature, SPELL_PYROBLAST) == CAST_OK) + m_uiPyroblastTimer = 0; } + else + m_uiPyroblastTimer -= uiDiff; + } + } + + 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 = urand(2000, 4000); + } + } + else + m_uiFireballTimer -= uiDiff; - PhoenixTimer = 60000; - }else PhoenixTimer -= diff; + if (m_uiPhoenixTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PHOENIX) == CAST_OK) + { + DoScriptText(SAY_PHOENIX, m_creature); + m_uiPhoenixTimer = 45000; + } + } + else + m_uiPhoenixTimer -= uiDiff; - if (FlameStrikeTimer < diff) + 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) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(pTarget, SPELL_FLAME_STRIKE); DoScriptText(SAY_FLAMESTRIKE, m_creature); + m_uiFlameStrikeTimer = urand(15000, 25000); } - FlameStrikeTimer = urand(15000, 25000); - }else FlameStrikeTimer -= diff; + } + } + 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(); - GravityLapseTimer = 0; - GravityLapsePhase = 0; - Phase = 1; - } - DoMeleeAttackIfReady(); + m_bIsFirstPhase = false; + } } - break; - case 1: + DoMeleeAttackIfReady(); + } + else + { + if (m_uiGravityLapseTimer < uiDiff) { - if (GravityLapseTimer < diff) + switch (m_uiGravityLapseStage) { - switch(GravityLapsePhase) - { - case 0: - if (FirstGravityLapse) // 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); - FirstGravityLapse = false; - - if (m_pInstance) - { - if (GameObject* pKaelLeft = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_KAEL_STATUE_LEFT))) - pKaelLeft->SetGoState(GO_STATE_ACTIVE); - - if (GameObject* pKaelRight = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_KAEL_STATUE_RIGHT))) - pKaelRight->SetGoState(GO_STATE_ACTIVE); - } + m_bFirstGravityLapse = false; } else - { DoScriptText(SAY_RECAST_GRAVITY, m_creature); - } - DoCastSpellIfCan(m_creature, SPELL_GRAVITY_LAPSE_INITIAL); - GravityLapseTimer = 2000 + diff;// Don't interrupt the visual spell - GravityLapsePhase = 1; - break; - - case 1: - TeleportPlayersToSelf(); - GravityLapseTimer = 1000; - GravityLapsePhase = 2; - break; - - case 2: - CastGravityLapseKnockUp(); - GravityLapseTimer = 1000; - GravityLapsePhase = 3; - break; - - case 3: - CastGravityLapseFly(); - GravityLapseTimer = 30000; - GravityLapsePhase = 4; - - - for(uint8 i = 0; i < 3; ++i) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - if (Creature* Orb = DoSpawnCreature(CREATURE_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(); - GravityLapseTimer = 10000; - GravityLapsePhase = 0; - break; - } - }else GravityLapseTimer -= diff; + m_uiGravityLapseTimer = 10000; + m_uiGravityLapseStage = 0; + } + break; + } } - break; + else + m_uiGravityLapseTimer -= uiDiff; } } }; +/*###### +## mob_felkael_phoenix +######*/ + struct MANGOS_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI { - mob_felkael_phoenixAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_felkael_phoenixAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiBurnTimer; + + bool m_bFakeDeath; + + void Reset() { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); + m_uiBurnTimer = 2000; + m_bFakeDeath = false; } - ScriptedInstance* m_pInstance; - uint32 BurnTimer; - uint32 Death_Timer; - bool Rebirth; - bool FakeDeath; + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_PHOENIX_BURN); + } - void Reset() + void EnterEvadeMode() override { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - m_creature->CastSpell(m_creature,SPELL_PHOENIX_BURN,true); + // Don't evade during ember blast + if (m_bFakeDeath) + return; - BurnTimer = 2000; - Death_Timer = 3000; - Rebirth = false; - FakeDeath = false; + ScriptedAI::EnterEvadeMode(); } - void DamageTaken(Unit* pKiller, uint32 &damage) + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override { - if (damage < m_creature->GetHealth()) + if (uiDamage < m_creature->GetHealth()) return; - //Prevent glitch if in fake death - if (FakeDeath) + // Prevent glitch if in fake death + if (m_bFakeDeath) { - damage = 0; + uiDamage = 0; return; - } - //Don't really die in all phases of Kael'Thas - if (m_pInstance && m_pInstance->GetData(DATA_KAELTHAS_EVENT) == 0) - { - //prevent death - damage = 0; - FakeDeath = 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->SetUInt64Value(UNIT_FIELD_TARGET,0); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - - } + // prevent death + uiDamage = 0; + DoSetFakeDeath(); } - void JustDied(Unit* slayer) + void DoSetFakeDeath() { - m_creature->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + 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 diff) + 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 revbirth and after that we kill the phoenix to spawn the egg. - if (FakeDeath) + // Remove fake death on egg despawn after 10 secs + if (DoCastSpellIfCan(m_creature, SPELL_REBIRTH_DMG) == CAST_OK) { - if (!Rebirth) - { - DoCastSpellIfCan(m_creature, SPELL_REBIRTH_DMG); - Rebirth = true; - } - - if (Rebirth) - { - - if (Death_Timer < diff) - { - m_creature->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - Rebirth = false; - }else Death_Timer -= diff; - } - + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); + m_bFakeDeath = false; + DoCastSpellIfCan(m_creature, SPELL_PHOENIX_BURN, CAST_TRIGGERED); } + } + + 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 (BurnTimer < diff) - { - //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); - BurnTimer += 2000; - } BurnTimer -= diff; + 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 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; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_felkael_phoenix_eggAI : public ScriptedAI -{ - mob_felkael_phoenix_eggAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 HatchTimer; +/*###### +## mob_felkael_phoenix_egg +######*/ - void Reset() - { - HatchTimer = 10000; +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct MANGOS_DLL_DECL mob_felkael_phoenix_eggAI : public Scripted_NoMovementAI +{ + mob_felkael_phoenix_eggAI(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 {} +}; - void MoveInLineOfSight(Unit* who) {} +/*###### +## mob_arcane_sphere +######*/ - void UpdateAI(const uint32 diff) +struct MANGOS_DLL_DECL mob_arcane_sphereAI : public ScriptedAI +{ + mob_arcane_sphereAI(Creature* pCreature) : ScriptedAI(pCreature) { - if (HatchTimer < diff) - { - m_creature->SummonCreature(CREATURE_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 HatchTimer -= diff; - + 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 DespawnTimer; - uint32 ChangeTargetTimer; + uint32 m_uiDespawnTimer; + uint32 m_uiChangeTargetTimer; void Reset() { - DespawnTimer = 30000; - ChangeTargetTimer = urand(6000, 12000); + 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 diff) + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override { - if (DespawnTimer < diff) + // 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); - else DespawnTimer -= diff; - - if (!m_creature->getVictim() || !m_creature->SelectHostileTarget()) - return; + m_uiDespawnTimer = 0; + } + else + m_uiDespawnTimer -= uiDiff; - if (ChangeTargetTimer < diff) + 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); - AttackStart(pTarget); + if (Unit* pTarget = pKael->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->GetMotionMaster()->MoveFollow(pTarget, 0, 0); } - ChangeTargetTimer = urand(5000, 15000); - }else ChangeTargetTimer -= diff; + m_uiChangeTargetTimer = urand(5000, 15000); + } + else + m_uiChangeTargetTimer -= uiDiff; } }; @@ -607,25 +652,25 @@ CreatureAI* GetAI_mob_felkael_phoenix_egg(Creature* pCreature) void AddSC_boss_felblood_kaelthas() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_felblood_kaelthas"; - newscript->GetAI = &GetAI_boss_felblood_kaelthas; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_arcane_sphere"; - newscript->GetAI = &GetAI_mob_arcane_sphere; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_felkael_phoenix"; - newscript->GetAI = &GetAI_mob_felkael_phoenix; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_felkael_phoenix_egg"; - newscript->GetAI = &GetAI_mob_felkael_phoenix_egg; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_felblood_kaelthas"; + pNewScript->GetAI = &GetAI_boss_felblood_kaelthas; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_arcane_sphere"; + pNewScript->GetAI = &GetAI_mob_arcane_sphere; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_felkael_phoenix"; + pNewScript->GetAI = &GetAI_mob_felkael_phoenix; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_felkael_phoenix_egg"; + pNewScript->GetAI = &GetAI_mob_felkael_phoenix_egg; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp index f6f7146683..0c9b87ba35 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,74 +16,48 @@ /* 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 { @@ -91,233 +65,208 @@ struct MANGOS_DLL_DECL boss_priestess_delrissaAI : public ScriptedAI { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - memset(&m_auiLackeyGUID, 0, sizeof(m_auiLackeyGUID)); - LackeyEntryList.clear(); Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - std::vector LackeyEntryList; - uint64 m_auiLackeyGUID[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() { - 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(DATA_DELRISSA_EVENT, FAIL); + 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_auiLackeyGUID[i])) - { - if (!pAdd->getVictim()) - { - pWho->SetInCombatWith(pAdd); - pAdd->AddThreat(pWho); - } - } - } + DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) - m_pInstance->SetData(DATA_DELRISSA_EVENT, IN_PROGRESS); + 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_auiLackeyGUID[j] = pAdd->GetGUID(); + 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_auiLackeyGUID[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_auiLackeyGUID[j] = pAdd->GetGUID(); - } - ++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(DATA_DELRISSA_DEATH_COUNT) == MAX_ACTIVE_LACKEY) - m_pInstance->SetData(DATA_DELRISSA_EVENT, DONE); + // 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_auiLackeyGUID[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_auiLackeyGUID[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_auiLackeyGUID[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_auiLackeyGUID[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(); } @@ -328,26 +277,24 @@ 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 MANGOS_DLL_DECL 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(); - memset(&m_auiLackeyGUIDs, 0, sizeof(m_auiLackeyGUIDs)); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); - AcquireGUIDs(); } ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - uint64 m_auiLackeyGUIDs[MAX_ACTIVE_LACKEY]; uint32 m_uiResetThreatTimer; + uint32 m_uiMedallionTimer; bool m_bUsedPotion; void Reset() @@ -359,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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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_auiLackeyGUIDs[i])) - { - if (!pAdd->getVictim() && pAdd != m_creature) - { - pWho->SetInCombatWith(pAdd); - pAdd->AddThreat(pWho); - } - } - } - - if (Creature* pDelrissa = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_DELRISSA)); - uint32 uiLackeyDeathCount = m_pInstance->GetData(DATA_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(DATA_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(DATA_DELRISSA_EVENT, 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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_DELRISSA))) - pDelrissa->AI()->KilledUnit(pVictim); - } - - void AcquireGUIDs() - { - if (!m_pInstance) - return; - if (Creature* pDelrissa = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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_auiLackeyGUIDs[i] = pDelrissaAI->m_auiLackeyGUID[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(); } }; @@ -481,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 MANGOS_DLL_DECL 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() { - 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 MANGOS_DLL_DECL 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() { - 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 MANGOS_DLL_DECL 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() { - 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 @@ -716,123 +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 MANGOS_DLL_DECL 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() { - 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) { - bool InMeleeRange = false; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + // 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 (Unit* target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) - { - //if in melee range - if (target->IsWithinDistInMap(m_creature, 5)) - { - InMeleeRange = true; - break; - } - } + if (DoCastSpellIfCan(m_creature, SPELL_BLINK) == CAST_OK) + m_uiBlinkTimer = 8000; } + else + m_uiBlinkTimer = 2000; + } + else + m_uiBlinkTimer -= uiDiff; - //if anybody is in melee range than escape by blink - if (InMeleeRange) - DoCastSpellIfCan(m_creature, SPELL_BLINK); - - Blink_Timer = 8000; - }else Blink_Timer -= diff; - - 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 @@ -846,492 +824,497 @@ enum SPELL_MORTAL_STRIKE = 44268 }; -struct MANGOS_DLL_DECL boss_warlord_salarisAI : public boss_priestess_lackey_commonAI +/*###### +## npc_warlord_salaris - Warrior +######*/ + +struct MANGOS_DLL_DECL 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() { - 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) { - bool InMeleeRange = false; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + // 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* target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_INTERCEPT_STUN, SELECT_FLAG_NOT_IN_MELEE_RANGE | SELECT_FLAG_IN_LOS)) { - //if in melee range - if (target->IsWithinDistInMap(m_creature, ATTACK_DISTANCE)) - { - InMeleeRange = true; - break; - } + if (DoCastSpellIfCan(pTarget, SPELL_INTERCEPT_STUN) == CAST_OK) + m_uiInterceptStunTimer = 10000; } } + else + m_uiInterceptStunTimer = 2000; + } + else + m_uiInterceptStunTimer -= uiDiff; - //if nobody is in melee range than try to use Intercept - if (!InMeleeRange) - { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_INTERCEPT_STUN); - } - - Intercept_Stun_Timer = 10000; - }else Intercept_Stun_Timer -= diff; - - 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); - m_uiPetGUID = 0; - Reset(); - } +/*###### +## npc_garaxxas - Hunter +######*/ - uint64 m_uiPetGUID; +struct MANGOS_DLL_DECL 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() { - 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_uiPetGUID); - 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_uiPetGUID = pSummoned->GetGUID(); + 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->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + 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 MANGOS_DLL_DECL 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() { - 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(); - // uint64 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 MANGOS_DLL_DECL 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() { - 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_auiLackeyGUIDs[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 *newscript; - - newscript = new Script; - newscript->Name = "boss_priestess_delrissa"; - newscript->GetAI = &GetAI_boss_priestess_delrissa; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_kagani_nightstrike"; - newscript->GetAI = &GetAI_boss_kagani_nightstrike; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_ellris_duskhallow"; - newscript->GetAI = &GetAI_ellris_duskhallow; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_eramas_brightblaze"; - newscript->GetAI = &GetAI_eramas_brightblaze; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_yazzai"; - newscript->GetAI = &GetAI_yazzai; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_warlord_salaris"; - newscript->GetAI = &GetAI_warlord_salaris; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_garaxxas"; - newscript->GetAI = &GetAI_garaxxas; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_apoko"; - newscript->GetAI = &GetAI_apoko; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_zelfan"; - newscript->GetAI = &GetAI_zelfan; - newscript->RegisterSelf(); - - /*newscript = new Script; - newscript->Name = "mob_high_explosive_sheep"; - newscript->GetAI = &GetAI_mob_high_explosive_sheep; - newscript->RegisterSelf();*/ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_priestess_delrissa"; + pNewScript->GetAI = &GetAI_boss_priestess_delrissa; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_kagani_nightstrike"; + pNewScript->GetAI = &GetAI_npc_kagani_nightstrike; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ellris_duskhallow"; + pNewScript->GetAI = &GetAI_npc_ellris_duskhallow; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_eramas_brightblaze"; + pNewScript->GetAI = &GetAI_npc_eramas_brightblaze; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_yazzai"; + pNewScript->GetAI = &GetAI_npc_yazzai; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_warlord_salaris"; + pNewScript->GetAI = &GetAI_npc_warlord_salaris; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_garaxxas"; + pNewScript->GetAI = &GetAI_npc_garaxxas; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_apoko"; + pNewScript->GetAI = &GetAI_npc_apoko; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_zelfan"; + pNewScript->GetAI = &GetAI_npc_zelfan; + 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 5f7f237238..effa424ae7 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,310 +17,232 @@ /* ScriptData SDName: Boss_Selin_Fireheart SD%Complete: 90 -SDComment: Heroic and Normal Support. Needs further testing. +SDComment: Timers. SDCategory: Magister's Terrace EndScriptData */ #include "precompiled.h" #include "magisters_terrace.h" -#define SAY_AGGRO -1585000 -#define SAY_ENERGY -1585001 -#define SAY_EMPOWERED -1585002 -#define SAY_KILL_1 -1585003 -#define SAY_KILL_2 -1585004 -#define SAY_DEATH -1585005 -#define EMOTE_CRYSTAL -1585006 - -//Crystal effect spells -#define SPELL_FEL_CRYSTAL_COSMETIC 44374 -#define SPELL_FEL_CRYSTAL_DUMMY 44329 -#define SPELL_FEL_CRYSTAL_VISUAL 44355 -#define SPELL_MANA_RAGE 44320 // This spell triggers 44321, which changes scale and regens mana Requires an entry in spell_script_target - -//Selin's spells -#define SPELL_DRAIN_LIFE 44294 -#define SPELL_FEL_EXPLOSION 44314 - -#define SPELL_DRAIN_MANA 46153 // Heroic only - -#define CRYSTALS_NUMBER 5 -#define DATA_CRYSTALS 6 - -#define CREATURE_FEL_CRYSTAL 24722 +enum +{ + SAY_AGGRO = -1585000, + SAY_ENERGY = -1585001, + SAY_EMPOWERED = -1585002, + SAY_KILL_1 = -1585003, + SAY_KILL_2 = -1585004, + SAY_DEATH = -1585005, + EMOTE_CRYSTAL = -1585006, + + // 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 { boss_selin_fireheartAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_magisters_terrace*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - - Crystals.clear(); - //GUIDs per instance is static, so we only need to load them once. - if (m_pInstance) - { - uint32 size = m_pInstance->GetData(DATA_FEL_CRYSTAL_SIZE); - for(uint8 i = 0; i < size; ++i) - { - uint64 guid = m_pInstance->GetData64(DATA_FEL_CRYSTAL); - debug_log("SD2: Selin: Adding Fel Crystal " UI64FMTD " to list", guid); - Crystals.push_back(guid); - } - } Reset(); } - ScriptedInstance* m_pInstance; + instance_magisters_terrace* m_pInstance; bool m_bIsRegularMode; - std::list Crystals; + uint32 m_uiDrainLifeTimer; + uint32 m_uiDrainManaTimer; + uint32 m_uiFelExplosionTimer; + uint32 m_uiDrainCrystalTimer; + uint32 m_uiManaRageTimer; - uint32 DrainLifeTimer; - uint32 DrainManaTimer; - uint32 FelExplosionTimer; - uint32 DrainCrystalTimer; - uint32 EmpowerTimer; + bool m_bDrainingCrystal; - bool IsDraining; - bool DrainingCrystal; - - uint64 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() { - if (m_pInstance) - { - //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) - { - //Creature* pUnit = m_creature->GetMap()->GetCreature(FelCrystals[i]); - 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); - } - } + m_uiDrainLifeTimer = urand(3000, 7000); + m_uiDrainManaTimer = m_uiDrainLifeTimer + 5000; + m_uiFelExplosionTimer = 2100; + m_uiDrainCrystalTimer = m_bIsRegularMode ? urand(20000, 25000) : urand(10000, 15000); + m_uiManaRageTimer = 0; - if (GameObject* pDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR))) - pDoor->SetGoState(GO_STATE_ACTIVE); // Open the big encounter door. Close it in Aggro and open it only in JustDied(and here) - // Small door opened after event are expected to be closed by default - // Set Inst data for encounter - m_pInstance->SetData(DATA_SELIN_EVENT, NOT_STARTED); - }else error_log(ERROR_INST_DATA); - - DrainLifeTimer = urand(3000, 7000); - DrainManaTimer = DrainLifeTimer + 5000; - FelExplosionTimer = 2100; - DrainCrystalTimer = urand(10000, 15000); - DrainCrystalTimer = urand(20000, 25000); - EmpowerTimer = 10000; - - IsDraining = false; - DrainingCrystal = false; - CrystalGUID = 0; + m_bDrainingCrystal = false; } - void SelectNearestCrystal() + // Get the closest alive crystal for draining + bool DoSelectNearestCrystal() { - if (Crystals.empty()) - return; + // Wait to finish casting + if (m_creature->IsNonMeleeSpellCasted(false)) + return false; - float ShortestDistance = 0; - CrystalGUID = 0; - Creature* pCrystal = NULL; - Creature* CrystalChosen = NULL; - //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) - { - pCrystal = m_creature->GetMap()->GetCreature(*itr); - - if (pCrystal && pCrystal->isAlive()) - { - // select nearest - if (!CrystalChosen || m_creature->GetDistanceOrder(pCrystal, CrystalChosen, false)) - { - CrystalGUID = pCrystal->GetGUID(); - CrystalChosen = pCrystal; // Store a copy of pCrystal so we don't need to recreate a pointer to closest crystal for the movement and yell. - } - } - } - if (CrystalChosen) + 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); - CrystalChosen->CastSpell(CrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true); + 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; - float x, y, z; // coords that we move to, close to the crystal. - CrystalChosen->GetClosePoint(x, y, z, m_creature->GetObjectBoundingRadius(), CONTACT_DISTANCE); - - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - m_creature->GetMotionMaster()->MovePoint(1, x, y, z); - DrainingCrystal = true; + return true; } + + return false; } - void ShatterRemainingCrystals() + void Aggro(Unit* /*pWho*/) override { - if (Crystals.empty()) - return; - - //for(uint8 i = 0; i < CRYSTALS_NUMBER; ++i) - for(std::list::iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr) - { - //Creature* pCrystal = m_creature->GetMap()->GetCreature(FelCrystals[i]); - Creature* pCrystal = m_creature->GetMap()->GetCreature(*itr); + DoScriptText(SAY_AGGRO, m_creature); - if (pCrystal && pCrystal->isAlive()) - pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_SELIN, IN_PROGRESS); } - void Aggro(Unit* who) + void JustReachedHome() override { - DoScriptText(SAY_AGGRO, m_creature); - if (m_pInstance) - { - //Close the encounter door, open it in JustDied/Reset - if (GameObject* pEncounterDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR))) - pEncounterDoor->SetGoState(GO_STATE_READY); - } + m_pInstance->SetData(TYPE_SELIN, FAIL); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void MovementInform(uint32 type, uint32 id) + void MovementInform(uint32 uiType, uint32 uiPointId) override { - if (type == POINT_MOTION_TYPE && id == 1) + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + Creature* pCrystal = m_creature->GetMap()->GetCreature(m_crystalGuid); + if (pCrystal && pCrystal->isAlive()) { - Creature* CrystalChosen = m_creature->GetMap()->GetCreature(CrystalGUID); - if (CrystalChosen && CrystalChosen->isAlive()) - { - // Make the crystal attackable - // We also remove NON_ATTACKABLE in case the database has it set. - CrystalChosen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); - CrystalChosen->CastSpell(m_creature, SPELL_MANA_RAGE, true); - IsDraining = true; - } - else + if (DoCastSpellIfCan(pCrystal, SPELL_MANA_RAGE) == CAST_OK) { - // 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 despawned"); - DrainingCrystal = 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* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - if (!m_pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - m_pInstance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete! - - if (GameObject* pEncounterDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR))) - pEncounterDoor->SetGoState(GO_STATE_ACTIVE); // Open the encounter door - - if (GameObject* pContinueDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_SELIN_DOOR))) - pContinueDoor->SetGoState(GO_STATE_ACTIVE); // Open the door leading further in + 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!DrainingCrystal) + if (!m_bDrainingCrystal) { - uint32 maxPowerMana = m_creature->GetMaxPower(POWER_MANA); - if (maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10)) + if (m_creature->GetPower(POWER_MANA) * 100 / m_creature->GetMaxPower(POWER_MANA) < 10) { - if (DrainLifeTimer < diff) + if (m_uiDrainLifeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_DRAIN_LIFE); - - DrainLifeTimer = 10000; - }else DrainLifeTimer -= diff; + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_DRAIN_LIFE : SPELL_DRAIN_LIFE_H) == CAST_OK) + m_uiDrainLifeTimer = 10000; + } + } + else + m_uiDrainLifeTimer -= uiDiff; // Heroic only if (!m_bIsRegularMode) { - if (DrainManaTimer < diff) + if (m_uiDrainManaTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - DoCastSpellIfCan(pTarget, SPELL_DRAIN_MANA); - - DrainManaTimer = 10000; - }else DrainManaTimer -= diff; + 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 (FelExplosionTimer < diff) - { - if (!m_creature->IsNonMeleeSpellCasted(false)) + if (m_uiDrainCrystalTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_FEL_EXPLOSION); - FelExplosionTimer = 2000; + if (DoSelectNearestCrystal()) + m_uiDrainCrystalTimer = m_bIsRegularMode ? urand(20000, 25000) : urand(10000, 15000); } - }else FelExplosionTimer -= diff; + else + m_uiDrainCrystalTimer -= uiDiff; + } - // If below 10% mana, start recharging - maxPowerMana = m_creature->GetMaxPower(POWER_MANA); - if (maxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / maxPowerMana) < 10)) + if (m_uiFelExplosionTimer < uiDiff) { - if (DrainCrystalTimer < diff) - { - SelectNearestCrystal(); - - if (m_bIsRegularMode) - DrainCrystalTimer = urand(20000, 25000); - else - DrainCrystalTimer = urand(10000, 15000); - - }else DrainCrystalTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_FEL_EXPLOSION) == CAST_OK) + m_uiFelExplosionTimer = 2000; } + else + m_uiFelExplosionTimer -= uiDiff; - }else + DoMeleeAttackIfReady(); + } + else { - if (IsDraining) + if (m_uiManaRageTimer) { - if (EmpowerTimer < diff) + if (m_uiManaRageTimer <= uiDiff) { - IsDraining = false; - DrainingCrystal = false; - DoScriptText(SAY_EMPOWERED, m_creature); + ManaRageComplete(); - Creature* CrystalChosen = m_creature->GetMap()->GetCreature(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); - - CrystalGUID = 0; + // 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_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - }else EmpowerTimer -= diff; + m_uiManaRageTimer = 0; + } + else + m_uiManaRageTimer -= uiDiff; } } - - DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun. } }; @@ -333,36 +255,56 @@ struct MANGOS_DLL_DECL mob_fel_crystalAI : public ScriptedAI { mob_fel_crystalAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) {} + GuidSet m_sWretchedGuids; + + uint32 m_uiVisualTimer; + + void Reset() + { + m_uiVisualTimer = 1000; + m_sWretchedGuids.clear(); + } + + void AttackStart(Unit* /*pWho*/) override {} + + 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* killer) + void JustDied(Unit* /*pKiller*/) override { if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) { - Creature* pSelin = m_creature->GetMap()->GetCreature(pInstance->GetData64(DATA_SELIN)); + Creature* pSelin = pInstance->GetSingleCreatureFromStorage(NPC_SELIN_FIREHEART); + if (!pSelin || !pSelin->isAlive()) + return; + + // Mark Mana rage as completed + pSelin->InterruptNonMeleeSpells(false); + if (boss_selin_fireheartAI* pBossAI = dynamic_cast(pSelin->AI())) + pBossAI->ManaRageComplete(); + } + } - if (pSelin && pSelin->isAlive()) + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiVisualTimer) + { + if (m_uiVisualTimer <= uiDiff) { - boss_selin_fireheartAI* pSelinAI = dynamic_cast(pSelin->AI()); - - if (pSelinAI && pSelinAI->CrystalGUID == m_creature->GetGUID()) - { - // Set this to false if we are the creature that Selin is draining so his AI flows properly - pSelinAI->DrainingCrystal = false; - pSelinAI->IsDraining = false; - pSelinAI->EmpowerTimer = 10000; - - if (pSelin->getVictim()) - { - pSelin->AI()->AttackStart(pSelin->getVictim()); - pSelin->GetMotionMaster()->MoveChase(pSelin->getVictim()); - } - } + if (DoCastSpellIfCan(m_creature, SPELL_FEL_CRYSTAL_VISUAL) == CAST_OK) + m_uiVisualTimer = 0; } - }else error_log(ERROR_INST_DATA); + else + m_uiVisualTimer -= uiDiff; + } } }; @@ -373,15 +315,15 @@ CreatureAI* GetAI_mob_fel_crystal(Creature* pCreature) void AddSC_boss_selin_fireheart() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_selin_fireheart"; - newscript->GetAI = &GetAI_boss_selin_fireheart; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_selin_fireheart"; + pNewScript->GetAI = &GetAI_boss_selin_fireheart; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_fel_crystal"; - newscript->GetAI = &GetAI_mob_fel_crystal; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_fel_crystal"; + pNewScript->GetAI = &GetAI_mob_fel_crystal; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp index 34cf1fa2d1..2e4840555e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,29 +33,27 @@ 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 @@ -70,106 +68,116 @@ 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() { - ChainLightningTimer = 8000; - ArcaneShockTimer = 5000; - OverloadTimer = 1200; - IntervalHealthAmount = 1; - Enraged = false; - - if (m_pInstance) - m_pInstance->SetData(DATA_VEXALLUS_EVENT, 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(DATA_VEXALLUS_EVENT, DONE); + m_pInstance->SetData(TYPE_VEXALLUS, DONE); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) - m_pInstance->SetData(DATA_VEXALLUS_EVENT, IN_PROGRESS); + 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->GetGUID()); + 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(); @@ -187,7 +195,7 @@ struct MANGOS_DLL_DECL mob_pure_energyAI : public ScriptedAI void Reset() { } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (m_creature->IsTemporarySummon()) { @@ -201,13 +209,13 @@ struct MANGOS_DLL_DECL mob_pure_energyAI : public ScriptedAI return; if (Player* pPlayer = pKiller->GetCharmerOrOwnerPlayerOrPlayerItself()) - pPlayer->CastSpell(pPlayer, SPELL_ENERGY_FEEDBACK, true, NULL, NULL, pVex->GetGUID()); + pPlayer->CastSpell(pPlayer, SPELL_ENERGY_FEEDBACK, true, NULL, NULL, pVex->GetObjectGuid()); } } } - 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) @@ -217,15 +225,15 @@ CreatureAI* GetAI_mob_pure_energy(Creature* pCreature) void AddSC_boss_vexallus() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_vexallus"; - newscript->GetAI = &GetAI_boss_vexallus; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_vexallus"; + pNewScript->GetAI = &GetAI_boss_vexallus; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_pure_energy"; - newscript->GetAI = &GetAI_mob_pure_energy; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_pure_energy"; + pNewScript->GetAI = &GetAI_mob_pure_energy; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp b/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp index 111c2ecf6a..b78f452b55 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,16 +16,14 @@ /* ScriptData SDName: Instance_Magisters_Terrace -SD%Complete: 60 -SDComment: Designed only for Selin Fireheart +SD%Complete: 80 +SDComment: SDCategory: Magister's Terrace EndScriptData */ #include "precompiled.h" #include "magisters_terrace.h" -#define MAX_ENCOUNTER 4 - /* 0 - Selin Fireheart 1 - Vexallus @@ -33,163 +31,196 @@ EndScriptData */ 3 - Kael'thas Sunstrider */ -struct MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance +instance_magisters_terrace::instance_magisters_terrace(Map* pMap) : ScriptedInstance(pMap), + m_uiDelrissaDeathCount(0) { - instance_magisters_terrace(Map* pMap) : ScriptedInstance(pMap) {Initialize();} - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint32 m_uiDelrissaDeathCount; - - std::list FelCrystals; - std::list::iterator CrystalItr; - - uint64 m_uiSelinGUID; - uint64 m_uiDelrissaGUID; - uint64 m_uiVexallusDoorGUID; - uint64 m_uiSelinDoorGUID; - uint64 m_uiSelinEncounterDoorGUID; - uint64 m_uiDelrissaDoorGUID; - uint64 m_uiKaelDoorGUID; - uint64 m_auiKaelStatue[2]; + Initialize(); +} - bool m_bInitializedItr; +void instance_magisters_terrace::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_magisters_terrace::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_auiKaelStatue, 0, sizeof(m_auiKaelStatue)); - - FelCrystals.clear(); - - m_uiDelrissaDeathCount = 0; - - m_uiSelinGUID = 0; - m_uiDelrissaGUID = 0; - m_uiVexallusDoorGUID = 0; - m_uiSelinDoorGUID = 0; - m_uiSelinEncounterDoorGUID = 0; - m_uiDelrissaDoorGUID = 0; - m_uiKaelDoorGUID = 0; - - m_bInitializedItr = false; + 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: + m_lFelCrystalGuid.push_back(pCreature->GetObjectGuid()); + break; } +} - bool IsEncounterInProgress() const +void instance_magisters_terrace::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - return false; + case GO_VEXALLUS_DOOR: + if (m_auiEncounter[TYPE_VEXALLUS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SELIN_DOOR: + if (m_auiEncounter[TYPE_SELIN] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DELRISSA_DOOR: + if (m_auiEncounter[TYPE_DELRISSA] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SELIN_ENCOUNTER_DOOR: + case GO_KAEL_DOOR: + case GO_ESCAPE_QUEL_DANAS: + break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - uint32 GetData(uint32 identifier) +void instance_magisters_terrace::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(identifier) - { - case DATA_SELIN_EVENT: return m_auiEncounter[0]; - case DATA_VEXALLUS_EVENT: return m_auiEncounter[1]; - case DATA_DELRISSA_EVENT: return m_auiEncounter[2]; - case DATA_KAELTHAS_EVENT: return m_auiEncounter[3]; - case DATA_DELRISSA_DEATH_COUNT: return m_uiDelrissaDeathCount; - case DATA_FEL_CRYSTAL_SIZE: return FelCrystals.size(); - } - return 0; + 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 SetData(uint32 identifier, uint32 data) +void instance_magisters_terrace::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(identifier) - { - case DATA_SELIN_EVENT: - m_auiEncounter[0] = data; - break; - case DATA_VEXALLUS_EVENT: - if (data == DONE) - DoUseDoorOrButton(m_uiVexallusDoorGUID); - m_auiEncounter[1] = data; - break; - case DATA_DELRISSA_EVENT: - if (data == DONE) - DoUseDoorOrButton(m_uiDelrissaDoorGUID); - if (data == IN_PROGRESS) - m_uiDelrissaDeathCount = 0; - m_auiEncounter[2] = data; - break; - case DATA_KAELTHAS_EVENT: - m_auiEncounter[3] = data; - break; - case DATA_DELRISSA_DEATH_COUNT: - if (data == SPECIAL) - ++m_uiDelrissaDeathCount; - else - m_uiDelrissaDeathCount = 0; - break; - } + 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; + case TYPE_VEXALLUS: + if (uiData == DONE) + DoUseDoorOrButton(GO_VEXALLUS_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_DELRISSA: + if (uiData == DONE) + DoUseDoorOrButton(GO_DELRISSA_DOOR); + if (uiData == IN_PROGRESS) + m_uiDelrissaDeathCount = 0; + m_auiEncounter[uiType] = 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; } - void OnCreatureCreate(Creature* pCreature) + if (uiData == DONE) { - switch(pCreature->GetEntry()) - { - case 24723: m_uiSelinGUID = pCreature->GetGUID(); break; - case 24560: m_uiDelrissaGUID = pCreature->GetGUID(); break; - case 24722: FelCrystals.push_back(pCreature->GetGUID()); break; - } + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - void OnObjectCreate(GameObject* go) +void instance_magisters_terrace::Load(const char* chrIn) +{ + if (!chrIn) { - switch(go->GetEntry()) - { - case 187896: m_uiVexallusDoorGUID = go->GetGUID(); break; - //SunwellRaid Gate 02 - case 187979: m_uiSelinDoorGUID = go->GetGUID(); break; - //Assembly Chamber Door - case 188065: m_uiSelinEncounterDoorGUID = go->GetGUID(); break; - case 187770: m_uiDelrissaDoorGUID = go->GetGUID(); break; - case 188064: m_uiKaelDoorGUID = go->GetGUID(); break; - case 188165: m_auiKaelStatue[0] = go->GetGUID(); break; - case 188166: m_auiKaelStatue[1] = go->GetGUID(); break; - } + OUT_LOAD_INST_DATA_FAIL; + return; } - uint64 GetData64(uint32 identifier) - { - switch(identifier) - { - case DATA_SELIN: return m_uiSelinGUID; - case DATA_DELRISSA: return m_uiDelrissaGUID; - case DATA_VEXALLUS_DOOR: return m_uiVexallusDoorGUID; - case DATA_SELIN_DOOR: return m_uiSelinDoorGUID; - case DATA_SELIN_ENCOUNTER_DOOR: return m_uiSelinEncounterDoorGUID; - case DATA_DELRISSA_DOOR: return m_uiDelrissaDoorGUID; - case DATA_KAEL_DOOR: return m_uiKaelDoorGUID; - case DATA_KAEL_STATUE_LEFT: return m_auiKaelStatue[0]; - case DATA_KAEL_STATUE_RIGHT: return m_auiKaelStatue[1]; - - case DATA_FEL_CRYSTAL: - { - if (FelCrystals.empty()) - { - error_log("SD2: Magisters Terrace: No Fel Crystals loaded in Inst Data"); - return 0; - } + OUT_LOAD_INST_DATA(chrIn); - if (!m_bInitializedItr) - { - CrystalItr = FelCrystals.begin(); - m_bInitializedItr = true; - } + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - uint64 guid = *CrystalItr; - ++CrystalItr; - return guid; - } - } - return 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; +} + +uint32 instance_magisters_terrace::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} InstanceData* GetInstanceData_instance_magisters_terrace(Map* pMap) { @@ -198,10 +229,10 @@ InstanceData* GetInstanceData_instance_magisters_terrace(Map* pMap) void AddSC_instance_magisters_terrace() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "instance_magisters_terrace"; - newscript->GetInstanceData = &GetInstanceData_instance_magisters_terrace; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "instance_magisters_terrace"; + pNewScript->GetInstanceData = &GetInstanceData_instance_magisters_terrace; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp b/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp index 034f8d6306..0c8cf5113a 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,6 +26,7 @@ npc_kalecgos EndContentData */ #include "precompiled.h" +#include "magisters_terrace.h" /*###### ## npc_kalecgos @@ -35,17 +36,12 @@ 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 @@ -57,62 +53,46 @@ struct MANGOS_DLL_DECL npc_kalecgosAI : public ScriptedAI void Reset() { + // 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,53 +102,31 @@ 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->GetGUID()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(12498, pCreature->GetGUID()); - - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->SEND_GOSSIP_MENU(12608, pCreature->GetGUID()); - 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() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_kalecgos"; - newscript->GetAI = &GetAI_npc_kalecgos; - newscript->pGossipHello = &GossipHello_npc_kalecgos; - newscript->pGossipSelect = &GossipSelect_npc_kalecgos; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_kalecgos"; + pNewScript->GetAI = &GetAI_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 b976287577..2b08234e9b 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h +++ b/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h @@ -1,30 +1,74 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef DEF_MAGISTERS_TERRACE_H #define DEF_MAGISTERS_TERRACE_H -#define DATA_SELIN_EVENT 1 -#define DATA_VEXALLUS_EVENT 2 -#define DATA_DELRISSA_EVENT 3 -#define DATA_KAELTHAS_EVENT 4 +enum +{ + MAX_ENCOUNTER = 4, + MAX_DELRISSA_ADDS = 4, -#define DATA_SELIN 5 -#define DATA_FEL_CRYSTAL 6 -#define DATA_FEL_CRYSTAL_SIZE 7 + TYPE_SELIN = 0, + TYPE_VEXALLUS = 1, + TYPE_DELRISSA = 2, + TYPE_KAELTHAS = 3, -#define DATA_VEXALLUS_DOOR 8 -#define DATA_SELIN_DOOR 9 -#define DATA_DELRISSA 10 -#define DATA_DELRISSA_DOOR 11 -#define DATA_SELIN_ENCOUNTER_DOOR 12 + NPC_SELIN_FIREHEART = 24723, + NPC_DELRISSA = 24560, + NPC_FEL_CRYSTAL = 24722, + NPC_KALECGOS_DRAGON = 24844, + NPC_KAELTHAS = 24664, -#define DATA_KAEL_DOOR 13 -#define DATA_KAEL_STATUE_LEFT 14 -#define DATA_KAEL_STATUE_RIGHT 15 + // 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, -#define DATA_DELRISSA_DEATH_COUNT 16 + GO_VEXALLUS_DOOR = 187896, + GO_SELIN_DOOR = 187979, // SunwellRaid Gate 02 + GO_DELRISSA_DOOR = 187770, + GO_SELIN_ENCOUNTER_DOOR = 188065, // Assembly Chamber Door + + GO_KAEL_DOOR = 188064, + // GO_KAEL_STATUE_LEFT = 188165, // animation statues - they do not reset on fail + // GO_KAEL_STATUE_RIGHT = 188166, + GO_ESCAPE_QUEL_DANAS = 188173, +}; + +static const int32 aDelrissaAddDeath[MAX_DELRISSA_ADDS] = { -1585013, -1585014, -1585015, -1585016}; + +class MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance +{ + public: + instance_magisters_terrace(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureDeath(Creature* pCreature) override; + + uint32 GetData(uint32 uiType) const override; + void SetData(uint32 uiType, uint32 uiData) 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; + + uint32 m_uiDelrissaDeathCount; + + GuidList m_lFelCrystalGuid; +}; -#define ERROR_INST_DATA "SD2 Error: Instance Data not set properly for Magister's Terrace instance (map 585). Encounters will be buggy." #endif diff --git a/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp b/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp deleted file mode 100644 index 5f4136d051..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Geddon -SD%Complete: 100 -SDComment: -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -#define EMOTE_SERVICE -1409000 - -#define SPELL_INFERNO 19695 -#define SPELL_IGNITEMANA 19659 -#define SPELL_LIVINGBOMB 20475 -#define SPELL_ARMAGEDDOM 20479 - -struct MANGOS_DLL_DECL boss_baron_geddonAI : public ScriptedAI -{ - boss_baron_geddonAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Inferno_Timer; - uint32 IgniteMana_Timer; - uint32 LivingBomb_Timer; - - void Reset() - { - Inferno_Timer = 45000; //These times are probably wrong - IgniteMana_Timer = 30000; - LivingBomb_Timer = 35000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //If we are <2% hp cast Armageddom - if (m_creature->GetHealthPercent() <= 2.0f) - { - m_creature->InterruptNonMeleeSpells(true); - - DoCastSpellIfCan(m_creature,SPELL_ARMAGEDDOM); - DoScriptText(EMOTE_SERVICE, m_creature); - return; - } - - //Inferno_Timer - if (Inferno_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_INFERNO); - Inferno_Timer = 45000; - }else Inferno_Timer -= diff; - - //IgniteMana_Timer - if (IgniteMana_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_IGNITEMANA); - - IgniteMana_Timer = 30000; - }else IgniteMana_Timer -= diff; - - //LivingBomb_Timer - if (LivingBomb_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_LIVINGBOMB); - - LivingBomb_Timer = 35000; - }else LivingBomb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_baron_geddon(Creature* pCreature) -{ - return new boss_baron_geddonAI(pCreature); -} - -void AddSC_boss_baron_geddon() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_baron_geddon"; - newscript->GetAI = &GetAI_boss_baron_geddon; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_garr.cpp b/scripts/eastern_kingdoms/molten_core/boss_garr.cpp deleted file mode 100644 index 847c4d14e3..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_garr.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Garr -SD%Complete: 50 -SDComment: Adds NYI -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -// Garr spells -#define SPELL_ANTIMAGICPULSE 19492 -#define SPELL_MAGMASHACKLES 19496 -#define SPELL_ENRAGE 19516 //Stacking enrage (stacks to 10 times) - -//Add spells -#define SPELL_ERUPTION 19497 -#define SPELL_IMMOLATE 20294 - -struct MANGOS_DLL_DECL boss_garrAI : public ScriptedAI -{ - boss_garrAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 AntiMagicPulse_Timer; - uint32 MagmaShackles_Timer; - uint32 CheckAdds_Timer; - uint64 Add[8]; - bool Enraged[8]; - - void Reset() - { - AntiMagicPulse_Timer = 25000; //These times are probably wrong - MagmaShackles_Timer = 15000; - CheckAdds_Timer = 2000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //AntiMagicPulse_Timer - if (AntiMagicPulse_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_ANTIMAGICPULSE); - AntiMagicPulse_Timer = urand(10000, 15000); - }else AntiMagicPulse_Timer -= diff; - - //MagmaShackles_Timer - if (MagmaShackles_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_MAGMASHACKLES); - MagmaShackles_Timer = urand(8000, 12000); - }else MagmaShackles_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI -{ - mob_fireswornAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Immolate_Timer; - - void Reset() - { - Immolate_Timer = 4000; //These times are probably wrong - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_IMMOLATE); - - Immolate_Timer = urand(5000, 10000); - }else Immolate_Timer -= diff; - - //Cast Erruption and let them die - if (m_creature->GetHealthPercent() <= 10.0f) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ERUPTION); - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_garr(Creature* pCreature) -{ - return new boss_garrAI(pCreature); -} - -CreatureAI* GetAI_mob_firesworn(Creature* pCreature) -{ - return new mob_fireswornAI(pCreature); -} - -void AddSC_boss_garr() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_garr"; - newscript->GetAI = &GetAI_boss_garr; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_firesworn"; - newscript->GetAI = &GetAI_mob_firesworn; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp b/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp deleted file mode 100644 index f5b181d75c..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Gehennas -SD%Complete: 90 -SDComment: Adds MC NYI -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWBOLT 19728 -#define SPELL_RAINOFFIRE 19717 -#define SPELL_GEHENNASCURSE 19716 - -struct MANGOS_DLL_DECL boss_gehennasAI : public ScriptedAI -{ - boss_gehennasAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowBolt_Timer; - uint32 RainOfFire_Timer; - uint32 GehennasCurse_Timer; - - void Reset() - { - ShadowBolt_Timer = 6000; - RainOfFire_Timer = 10000; - GehennasCurse_Timer = 12000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - if (Unit* bTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(bTarget,SPELL_SHADOWBOLT); - ShadowBolt_Timer = 7000; - }else ShadowBolt_Timer -= diff; - - //RainOfFire_Timer - if (RainOfFire_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_RAINOFFIRE); - - RainOfFire_Timer = urand(4000, 12000); - }else RainOfFire_Timer -= diff; - - //GehennasCurse_Timer - if (GehennasCurse_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GEHENNASCURSE); - GehennasCurse_Timer = urand(22000, 30000); - }else GehennasCurse_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gehennas(Creature* pCreature) -{ - return new boss_gehennasAI(pCreature); -} - -void AddSC_boss_gehennas() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_gehennas"; - newscript->GetAI = &GetAI_boss_gehennas; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp b/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp deleted file mode 100644 index 44dc42ef09..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Lucifron -SD%Complete: 100 -SDComment: -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_IMPENDINGDOOM 19702 -#define SPELL_LUCIFRONCURSE 19703 -#define SPELL_SHADOWSHOCK 20603 - -struct MANGOS_DLL_DECL boss_lucifronAI : public ScriptedAI -{ - boss_lucifronAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ImpendingDoom_Timer; - uint32 LucifronCurse_Timer; - uint32 ShadowShock_Timer; - - void Reset() - { - ImpendingDoom_Timer = 10000; //Initial cast after 10 seconds so the debuffs alternate - LucifronCurse_Timer = 20000; //Initial cast after 20 seconds - ShadowShock_Timer = 6000; //6 seconds - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Impending doom timer - if (ImpendingDoom_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_IMPENDINGDOOM); - ImpendingDoom_Timer = 20000; - }else ImpendingDoom_Timer -= diff; - - //Lucifron's curse timer - if (LucifronCurse_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_LUCIFRONCURSE); - LucifronCurse_Timer = 15000; - }else LucifronCurse_Timer -= diff; - - //Shadowshock - if (ShadowShock_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWSHOCK); - ShadowShock_Timer = 6000; - }else ShadowShock_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lucifron(Creature* pCreature) -{ - return new boss_lucifronAI(pCreature); -} - -void AddSC_boss_lucifron() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_lucifron"; - newscript->GetAI = &GetAI_boss_lucifron; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp b/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp deleted file mode 100644 index f3bae4976f..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Magmadar -SD%Complete: 75 -SDComment: Conflag on ground nyi, fear causes issues without VMAPs -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -enum -{ - EMOTE_GENERIC_FRENZY_KILL = -1000001, - - SPELL_FRENZY = 19451, - SPELL_MAGMASPIT = 19449, //This is actually a buff he gives himself - SPELL_PANIC = 19408, - SPELL_LAVABOMB = 19411, //This calls a dummy server side effect that isn't implemented yet - SPELL_LAVABOMB_ALT = 19428 //This is the spell that the lava bomb casts -}; - -struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI -{ - boss_magmadarAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Frenzy_Timer; - uint32 Panic_Timer; - uint32 Lavabomb_Timer; - - void Reset() - { - Frenzy_Timer = 30000; - Panic_Timer = 20000; - Lavabomb_Timer = 12000; - - m_creature->CastSpell(m_creature,SPELL_MAGMASPIT,true); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Frenzy_Timer - if (Frenzy_Timer < diff) - { - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - DoCastSpellIfCan(m_creature,SPELL_FRENZY); - Frenzy_Timer = 15000; - }else Frenzy_Timer -= diff; - - //Panic_Timer - if (Panic_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_PANIC); - Panic_Timer = 35000; - }else Panic_Timer -= diff; - - //Lavabomb_Timer - if (Lavabomb_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_LAVABOMB_ALT); - - Lavabomb_Timer = 12000; - }else Lavabomb_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_magmadar(Creature* pCreature) -{ - return new boss_magmadarAI(pCreature); -} - -void AddSC_boss_magmadar() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_magmadar"; - newscript->GetAI = &GetAI_boss_magmadar; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp b/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp deleted file mode 100644 index 24cfb9dfe2..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Majordomo_Executus -SD%Complete: 30 -SDComment: Correct spawning and Event NYI -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO -1409003 -#define SAY_SPAWN -1409004 -#define SAY_SLAY -1409005 -#define SAY_SPECIAL -1409006 -#define SAY_DEFEAT -1409007 - -#define SAY_SUMMON_MAJ -1409008 -#define SAY_ARRIVAL1_RAG -1409009 -#define SAY_ARRIVAL2_MAJ -1409010 -#define SAY_ARRIVAL3_RAG -1409011 -#define SAY_ARRIVAL5_RAG -1409012 - -#define SPAWN_RAG_X 838.51 -#define SPAWN_RAG_Y -829.84 -#define SPAWN_RAG_Z -232.00 -#define SPAWN_RAG_O 1.70 - -#define SPELL_MAGIC_REFLECTION 20619 -#define SPELL_DAMAGE_REFLECTION 21075 -#define SPELL_BLASTWAVE 20229 -#define SPELL_AEGIS 20620 //This is self casted whenever we are below 50% -#define SPELL_TELEPORT 20618 -#define SPELL_SUMMON_RAGNAROS 19774 - -#define ENTRY_FLAMEWALKER_HEALER 11663 -#define ENTRY_FLAMEWALKER_ELITE 11664 - -struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI -{ - boss_majordomoAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 MagicReflection_Timer; - uint32 DamageReflection_Timer; - uint32 Blastwave_Timer; - - void Reset() - { - MagicReflection_Timer = 30000; //Damage reflection first so we alternate - DamageReflection_Timer = 15000; - Blastwave_Timer = 10000; - } - - void KilledUnit(Unit* victim) - { - if (urand(0, 4)) - return; - - DoScriptText(SAY_SLAY, m_creature); - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Cast Ageis if less than 50% hp - if (m_creature->GetHealthPercent() < 50.0f) - { - DoCastSpellIfCan(m_creature,SPELL_AEGIS); - } - - //MagicReflection_Timer - // if (MagicReflection_Timer < diff) - // { - // DoCastSpellIfCan(m_creature, SPELL_MAGICREFLECTION); - - //60 seconds until we should cast this agian - // MagicReflection_Timer = 30000; - // }else MagicReflection_Timer -= diff; - - //DamageReflection_Timer - // if (DamageReflection_Timer < diff) - // { - // DoCastSpellIfCan(m_creature, SPELL_DAMAGEREFLECTION); - - //60 seconds until we should cast this agian - // DamageReflection_Timer = 30000; - // }else DamageReflection_Timer -= diff; - - //Blastwave_Timer - if (Blastwave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BLASTWAVE); - Blastwave_Timer = 10000; - }else Blastwave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_majordomo(Creature* pCreature) -{ - return new boss_majordomoAI(pCreature); -} - -void AddSC_boss_majordomo() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_majordomo"; - newscript->GetAI = &GetAI_boss_majordomo; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp b/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp deleted file mode 100644 index 2d82991a6a..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Ragnaros -SD%Complete: 75 -SDComment: Intro Dialog and event NYI -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -#define SAY_REINFORCEMENTS1 -1409013 -#define SAY_REINFORCEMENTS2 -1409014 -#define SAY_HAND -1409015 -#define SAY_WRATH -1409016 -#define SAY_KILL -1409017 -#define SAY_MAGMABURST -1409018 - -#define SPELL_HANDOFRAGNAROS 19780 -#define SPELL_WRATHOFRAGNAROS 20566 -#define SPELL_LAVABURST 21158 - -#define SPELL_MAGMABURST 20565 //Ranged attack - -#define SPELL_SONSOFFLAME_DUMMY 21108 //Server side effect -#define SPELL_RAGSUBMERGE 21107 //Stealth aura -#define SPELL_RAGEMERGE 20568 -#define SPELL_MELTWEAPON 21388 -#define SPELL_ELEMENTALFIRE 20564 -#define SPELL_ERRUPTION 17731 - -#define ADD_1X 848.740356 -#define ADD_1Y -816.103455 -#define ADD_1Z -229.74327 -#define ADD_1O 2.615287 - -#define ADD_2X 852.560791 -#define ADD_2Y -849.861511 -#define ADD_2Z -228.560974 -#define ADD_2O 2.836073 - -#define ADD_3X 808.710632 -#define ADD_3Y -852.845764 -#define ADD_3Z -227.914963 -#define ADD_3O 0.964207 - -#define ADD_4X 786.597107 -#define ADD_4Y -821.132874 -#define ADD_4Z -226.350128 -#define ADD_4O 0.949377 - -#define ADD_5X 796.219116 -#define ADD_5Y -800.948059 -#define ADD_5Z -226.010361 -#define ADD_5O 0.560603 - -#define ADD_6X 821.602539 -#define ADD_6Y -782.744109 -#define ADD_6Z -226.023575 -#define ADD_6O 6.157440 - -#define ADD_7X 844.924744 -#define ADD_7Y -769.453735 -#define ADD_7Z -225.521698 -#define ADD_7O 4.4539958 - -#define ADD_8X 839.823364 -#define ADD_8Y -810.869385 -#define ADD_8Z -229.683182 -#define ADD_8O 4.693108 - -struct MANGOS_DLL_DECL boss_ragnarosAI : public ScriptedAI -{ - boss_ragnarosAI(Creature* pCreature) : ScriptedAI(pCreature) - { - SetCombatMovement(false); - Reset(); - } - - uint32 WrathOfRagnaros_Timer; - uint32 HandOfRagnaros_Timer; - uint32 LavaBurst_Timer; - uint32 MagmaBurst_Timer; - uint32 ElementalFire_Timer; - uint32 Erruption_Timer; - uint32 Submerge_Timer; - uint32 Attack_Timer; - Creature *Summoned; - bool HasYelledMagmaBurst; - bool HasSubmergedOnce; - bool WasBanished; - bool HasAura; - - void Reset() - { - WrathOfRagnaros_Timer = 30000; - HandOfRagnaros_Timer = 25000; - LavaBurst_Timer = 10000; - MagmaBurst_Timer = 2000; - Erruption_Timer = 15000; - ElementalFire_Timer = 3000; - Submerge_Timer = 180000; - Attack_Timer = 90000; - HasYelledMagmaBurst = false; - HasSubmergedOnce = false; - WasBanished = false; - - m_creature->CastSpell(m_creature,SPELL_MELTWEAPON,true); - HasAura = true; - } - - void KilledUnit(Unit* victim) - { - if (urand(0, 4)) - return; - - DoScriptText(SAY_KILL, m_creature); - } - - void UpdateAI(const uint32 diff) - { - if (WasBanished && Attack_Timer < diff) - { - //Become unbanished again - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoCastSpellIfCan(m_creature,SPELL_RAGEMERGE); - WasBanished = false; - } else if (WasBanished) - { - Attack_Timer -= diff; - //Do nothing while banished - return; - } - - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //WrathOfRagnaros_Timer - if (WrathOfRagnaros_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_WRATHOFRAGNAROS); - - if (urand(0, 1)) - DoScriptText(SAY_WRATH, m_creature); - - WrathOfRagnaros_Timer = 30000; - }else WrathOfRagnaros_Timer -= diff; - - //HandOfRagnaros_Timer - if (HandOfRagnaros_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_HANDOFRAGNAROS); - - if (urand(0, 1)) - DoScriptText(SAY_HAND, m_creature); - - HandOfRagnaros_Timer = 25000; - }else HandOfRagnaros_Timer -= diff; - - //LavaBurst_Timer - if (LavaBurst_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_LAVABURST); - LavaBurst_Timer = 10000; - }else LavaBurst_Timer -= diff; - - //Erruption_Timer - if (LavaBurst_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ERRUPTION); - Erruption_Timer = urand(20000, 45000); - }else Erruption_Timer -= diff; - - //ElementalFire_Timer - if (ElementalFire_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ELEMENTALFIRE); - ElementalFire_Timer = urand(10000, 14000); - }else ElementalFire_Timer -= diff; - - //Submerge_Timer - if (!WasBanished && Submerge_Timer < diff) - { - //Creature spawning and ragnaros becomming unattackable - //is not very well supported in the core - //so added normaly spawning and banish workaround and attack again after 90 secs. - - m_creature->InterruptNonMeleeSpells(false); - //Root self - DoCastSpellIfCan(m_creature,23973); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - - if (!HasSubmergedOnce) - { - DoScriptText(SAY_REINFORCEMENTS1, m_creature); - - // summon 10 elementals - for(int i = 0; i < 9; ++i) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - if (Creature* pSummoned = m_creature->SummonCreature(12143,pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(),0.0f,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,900000)) - pSummoned->AI()->AttackStart(pTarget); - } - } - - HasSubmergedOnce = true; - WasBanished = true; - DoCastSpellIfCan(m_creature,SPELL_RAGSUBMERGE); - Attack_Timer = 90000; - } - else - { - DoScriptText(SAY_REINFORCEMENTS2, m_creature); - - for(int i = 0; i < 9; ++i) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - if (Creature* pSummoned = m_creature->SummonCreature(12143,pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(),0.0f,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,900000)) - pSummoned->AI()->AttackStart(pTarget); - } - } - - WasBanished = true; - DoCastSpellIfCan(m_creature,SPELL_RAGSUBMERGE); - Attack_Timer = 90000; - } - - Submerge_Timer = 180000; - }else Submerge_Timer -= diff; - - //If we are within range melee the target - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - //Make sure our attack is ready and we arn't currently casting - if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } - else - { - //MagmaBurst_Timer - if (MagmaBurst_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MAGMABURST); - - if (!HasYelledMagmaBurst) - { - DoScriptText(SAY_MAGMABURST, m_creature); - HasYelledMagmaBurst = true; - } - - MagmaBurst_Timer = 2500; - }else MagmaBurst_Timer -= diff; - } - } -}; -CreatureAI* GetAI_boss_ragnaros(Creature* pCreature) -{ - return new boss_ragnarosAI(pCreature); -} - -void AddSC_boss_ragnaros() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_ragnaros"; - newscript->GetAI = &GetAI_boss_ragnaros; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp b/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp deleted file mode 100644 index f5cff54b3f..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Shazzrah -SD%Complete: 75 -SDComment: Teleport NYI -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_ARCANEEXPLOSION = 19712, - SPELL_SHAZZRAHCURSE = 19713, - SPELL_DEADENMAGIC = 19714, - SPELL_COUNTERSPELL = 19715, - SPELL_GATE_DUMMY = 23138 // effect spell: 23139 -}; - -struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI -{ - boss_shazzrahAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ArcaneExplosion_Timer; - uint32 ShazzrahCurse_Timer; - uint32 DeadenMagic_Timer; - uint32 Countspell_Timer; - uint32 Blink_Timer; - - void Reset() - { - ArcaneExplosion_Timer = 6000; //These times are probably wrong - ShazzrahCurse_Timer = 10000; - DeadenMagic_Timer = 24000; - Countspell_Timer = 15000; - Blink_Timer = 30000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ArcaneExplosion_Timer - if (ArcaneExplosion_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANEEXPLOSION); - ArcaneExplosion_Timer = urand(5000, 9000); - }else ArcaneExplosion_Timer -= diff; - - //ShazzrahCurse_Timer - if (ShazzrahCurse_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_SHAZZRAHCURSE); - - ShazzrahCurse_Timer = urand(25000, 30000); - }else ShazzrahCurse_Timer -= diff; - - //DeadenMagic_Timer - if (DeadenMagic_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_DEADENMAGIC); - DeadenMagic_Timer = 35000; - }else DeadenMagic_Timer -= diff; - - //Countspell_Timer - if (Countspell_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_COUNTERSPELL); - Countspell_Timer = urand(16000, 20000); - }else Countspell_Timer -= diff; - - //Blink_Timer - if (Blink_Timer < diff) - { - // Teleporting him to a random gamer and casting Arcane Explosion after that. - DoCastSpellIfCan(m_creature, SPELL_GATE_DUMMY, CAST_TRIGGERED); - - // manual, until added effect of dummy properly - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - m_creature->NearTeleportTo(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_creature->GetOrientation()); - - DoCastSpellIfCan(m_creature, SPELL_ARCANEEXPLOSION); - - DoResetThreat(); - - Blink_Timer = 45000; - }else Blink_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_shazzrah(Creature* pCreature) -{ - return new boss_shazzrahAI(pCreature); -} - -void AddSC_boss_shazzrah() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_shazzrah"; - newscript->GetAI = &GetAI_boss_shazzrah; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp b/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp deleted file mode 100644 index 1985e5160d..0000000000 --- a/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Sulfuron_Harbringer -SD%Complete: 80 -SDComment: Adds NYI -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" -#include "molten_core.h" - -#define SPELL_DARKSTRIKE 19777 -#define SPELL_DEMORALIZINGSHOUT 19778 -#define SPELL_INSPIRE 19779 -#define SPELL_KNOCKDOWN 19780 -#define SPELL_FLAMESPEAR 19781 - -//Adds Spells -#define SPELL_HEAL 19775 -#define SPELL_SHADOWWORDPAIN 19776 -#define SPELL_IMMOLATE 20294 - -struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI -{ - boss_sulfuronAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - uint32 Darkstrike_Timer; - uint32 DemoralizingShout_Timer; - uint32 Inspire_Timer; - uint32 Knockdown_Timer; - uint32 Flamespear_Timer; - ScriptedInstance* m_pInstance; - - void Reset() - { - Darkstrike_Timer=10000; //These times are probably wrong - DemoralizingShout_Timer = 15000; - Inspire_Timer = 13000; - Knockdown_Timer = 6000; - Flamespear_Timer = 2000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //DemoralizingShout_Timer - if (DemoralizingShout_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DEMORALIZINGSHOUT); - DemoralizingShout_Timer = urand(15000, 20000); - }else DemoralizingShout_Timer -= diff; - - //Inspire_Timer - if (Inspire_Timer < diff) - { - Creature* target = NULL; - std::list pList = DoFindFriendlyMissingBuff(45.0f,SPELL_INSPIRE); - if (!pList.empty()) - { - std::list::iterator i = pList.begin(); - advance(i, (rand()%pList.size())); - target = (*i); - } - - if (target) - DoCastSpellIfCan(target,SPELL_INSPIRE); - - DoCastSpellIfCan(m_creature,SPELL_INSPIRE); - - Inspire_Timer = urand(20000, 26000); - }else Inspire_Timer -= diff; - - //Knockdown_Timer - if (Knockdown_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKDOWN); - Knockdown_Timer = urand(12000, 15000); - }else Knockdown_Timer -= diff; - - //Flamespear_Timer - if (Flamespear_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_FLAMESPEAR); - - Flamespear_Timer = urand(12000, 16000); - }else Flamespear_Timer -= diff; - - //DarkStrike_Timer - if (Darkstrike_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_DARKSTRIKE); - Darkstrike_Timer = urand(15000, 18000); - }else Darkstrike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_flamewaker_priestAI : public ScriptedAI -{ - mob_flamewaker_priestAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - uint32 Heal_Timer; - uint32 ShadowWordPain_Timer; - uint32 Immolate_Timer; - - ScriptedInstance* m_pInstance; - - void Reset() - { - Heal_Timer = urand(15000, 30000); - ShadowWordPain_Timer = 2000; - Immolate_Timer = 8000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Casting Heal to Sulfuron or other Guards. - if (Heal_Timer < diff) - { - Unit* pUnit = DoSelectLowestHpFriendly(60.0f, 1); - if (!pUnit) - return; - - DoCastSpellIfCan(pUnit, SPELL_HEAL); - - Heal_Timer = urand(15000, 20000); - }else Heal_Timer -= diff; - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_SHADOWWORDPAIN); - - ShadowWordPain_Timer = urand(18000, 26000); - }else ShadowWordPain_Timer -= diff; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_IMMOLATE); - - Immolate_Timer = urand(15000, 25000); - }else Immolate_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_sulfuron(Creature* pCreature) -{ - return new boss_sulfuronAI(pCreature); -} - -CreatureAI* GetAI_mob_flamewaker_priest(Creature* pCreature) -{ - return new mob_flamewaker_priestAI(pCreature); -} - -void AddSC_boss_sulfuron() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_sulfuron"; - newscript->GetAI = &GetAI_boss_sulfuron; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_flamewaker_priest"; - newscript->GetAI = &GetAI_mob_flamewaker_priest; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp b/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp deleted file mode 100644 index 70b9fa60a6..0000000000 --- a/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Instance_Molten_Core -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Molten Core -EndScriptData */ - -#include "precompiled.h" -#include "molten_core.h" - -struct MANGOS_DLL_DECL instance_molten_core : public ScriptedInstance -{ - instance_molten_core(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiLucifronGUID, m_uiMagmadarGUID, m_uiGehennasGUID, m_uiGarrGUID, m_uiGeddonGUID, m_uiShazzrahGUID, m_uiSulfuronGUID, m_uiGolemaggGUID, m_uiMajorDomoGUID, m_uiRagnarosGUID, m_uiFlamewakerPriestGUID; - uint64 m_uiRuneKoroGUID, m_uiRuneZethGUID, m_uiRuneMazjGUID, m_uiRuneTheriGUID, m_uiRuneBlazGUID, m_uiRuneKressGUID, m_uiRuneMohnGUID, m_uiFirelordCacheGUID; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiLucifronGUID = 0; - m_uiMagmadarGUID = 0; - m_uiGehennasGUID = 0; - m_uiGarrGUID = 0; - m_uiGeddonGUID = 0; - m_uiShazzrahGUID = 0; - m_uiSulfuronGUID = 0; - m_uiGolemaggGUID = 0; - m_uiMajorDomoGUID = 0; - m_uiRagnarosGUID = 0; - m_uiFlamewakerPriestGUID = 0; - - m_uiRuneKoroGUID = 0; - m_uiRuneZethGUID = 0; - m_uiRuneMazjGUID = 0; - m_uiRuneTheriGUID = 0; - m_uiRuneBlazGUID = 0; - m_uiRuneKressGUID = 0; - m_uiRuneMohnGUID = 0; - - m_uiFirelordCacheGUID = 0; - } - - bool IsEncounterInProgress() const - { - return false; - } - - void OnObjectCreate(GameObject* pGo) - { - switch(pGo->GetEntry()) - { - case 176951: //Sulfuron - m_uiRuneKoroGUID = pGo->GetGUID(); - break; - case 176952: //Geddon - m_uiRuneZethGUID = pGo->GetGUID(); - break; - case 176953: //Shazzrah - m_uiRuneMazjGUID = pGo->GetGUID(); - break; - case 176954: //Golemagg - m_uiRuneTheriGUID = pGo->GetGUID(); - break; - case 176955: //Garr - m_uiRuneBlazGUID = pGo->GetGUID(); - break; - case 176956: //Magmadar - m_uiRuneKressGUID = pGo->GetGUID(); - break; - case 176957: //Gehennas - m_uiRuneMohnGUID = pGo->GetGUID(); - break; - case 179703: - m_uiFirelordCacheGUID = pGo->GetGUID(); //majordomo event chest - break; - } - } - - void OnCreatureCreate(Creature* pCreature) - { - switch(pCreature->GetEntry()) - { - case NPC_LUCIFRON: - m_uiLucifronGUID = pCreature->GetGUID(); - break; - case NPC_MAGMADAR: - m_uiMagmadarGUID = pCreature->GetGUID(); - break; - case NPC_GEHENNAS: - m_uiGehennasGUID = pCreature->GetGUID(); - break; - case NPC_GARR: - m_uiGarrGUID = pCreature->GetGUID(); - break; - case NPC_GEDDON: - m_uiGeddonGUID = pCreature->GetGUID(); - break; - case NPC_SHAZZRAH: - m_uiShazzrahGUID = pCreature->GetGUID(); - break; - case NPC_SULFURON: - m_uiSulfuronGUID = pCreature->GetGUID(); - break; - case NPC_GOLEMAGG: - m_uiGolemaggGUID = pCreature->GetGUID(); - break; - case NPC_DOMO: - m_uiMajorDomoGUID = pCreature->GetGUID(); - break; - case NPC_RAGNAROS: - m_uiRagnarosGUID = pCreature->GetGUID(); - break; - case NPC_FLAMEWAKERPRIEST: - m_uiFlamewakerPriestGUID = pCreature->GetGUID(); - break; - } - } - - void SetData(uint32 uiType, uint32 uiData) - { - switch(uiType) - { - case TYPE_SULFURON: - m_auiEncounter[0] = uiData; - break; - case TYPE_GEDDON: - m_auiEncounter[1] = uiData; - break; - case TYPE_SHAZZRAH: - m_auiEncounter[2] = uiData; - break; - case TYPE_GOLEMAGG: - m_auiEncounter[3] = uiData; - break; - case TYPE_GARR: - m_auiEncounter[4] = uiData; - break; - case TYPE_MAGMADAR: - m_auiEncounter[5] = uiData; - break; - case TYPE_GEHENNAS: - m_auiEncounter[6] = uiData; - break; - case TYPE_LUCIFRON: - m_auiEncounter[7] = uiData; - break; - case TYPE_MAJORDOMO: - if (uiData == DONE) - DoRespawnGameObject(m_uiFirelordCacheGUID); - m_auiEncounter[8] = uiData; - break; - case TYPE_RAGNAROS: - m_auiEncounter[9] = 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_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9]; - - strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } - - const char* Save() - { - return strInstData.c_str(); - } - - bool CanSpawnMajorDomo() - { - return m_auiEncounter[0] && m_auiEncounter[1] && m_auiEncounter[2] && m_auiEncounter[3] && - m_auiEncounter[4] && m_auiEncounter[5] && m_auiEncounter[6]; - } - - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_SULFURON: - return m_auiEncounter[0]; - case TYPE_GEDDON: - return m_auiEncounter[1]; - case TYPE_SHAZZRAH: - return m_auiEncounter[2]; - case TYPE_GOLEMAGG: - return m_auiEncounter[3]; - case TYPE_GARR: - return m_auiEncounter[4]; - case TYPE_MAGMADAR: - return m_auiEncounter[5]; - case TYPE_GEHENNAS: - return m_auiEncounter[6]; - case TYPE_LUCIFRON: - return m_auiEncounter[7]; - case TYPE_MAJORDOMO: - return m_auiEncounter[8]; - case TYPE_RAGNAROS: - return m_auiEncounter[9]; - } - return 0; - } - - uint64 GetData64(uint32 uiData) - { - switch(uiData) - { - case DATA_SULFURON: - return m_uiSulfuronGUID; - case DATA_GOLEMAGG: - return m_uiGolemaggGUID; - case DATA_GARR: - return m_uiGarrGUID; - case DATA_MAJORDOMO: - return m_uiMajorDomoGUID; - } - - return 0; - } - - void 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] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9]; - - 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; - } -}; - -InstanceData* GetInstance_instance_molten_core(Map* pMap) -{ - return new instance_molten_core(pMap); -} - -void AddSC_instance_molten_core() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_molten_core"; - newscript->GetInstanceData = &GetInstance_instance_molten_core; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/molten_core/molten_core.h b/scripts/eastern_kingdoms/molten_core/molten_core.h deleted file mode 100644 index f7ed5e9a22..0000000000 --- a/scripts/eastern_kingdoms/molten_core/molten_core.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_MOLTEN_CORE_H -#define DEF_MOLTEN_CORE_H - -enum -{ - MAX_ENCOUNTER = 10, - - NPC_LUCIFRON = 12118, - NPC_MAGMADAR = 11982, - NPC_GEHENNAS = 12259, - NPC_GARR = 12057, - NPC_GEDDON = 12056, - NPC_SHAZZRAH = 12264, - NPC_GOLEMAGG = 11988, - NPC_SULFURON = 12098, - NPC_DOMO = 12018, - NPC_RAGNAROS = 11502, - NPC_FLAMEWAKERPRIEST = 11662, - - TYPE_SULFURON = 1, - TYPE_GEDDON = 2, - TYPE_SHAZZRAH = 3, - TYPE_GOLEMAGG = 4, - TYPE_GARR = 5, - TYPE_MAGMADAR = 6, - TYPE_GEHENNAS = 7, - TYPE_LUCIFRON = 8, - TYPE_MAJORDOMO = 9, - TYPE_RAGNAROS = 10, - - DATA_SULFURON = 11, - DATA_GOLEMAGG = 12, - DATA_GARR = 13, - DATA_MAJORDOMO = 14, - - DATA_BOSSES_DEAD_CHECK = 15 -}; - -#endif diff --git a/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_armsmaster_harlan.cpp b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_armsmaster_harlan.cpp new file mode 100644 index 0000000000..272eb9334e --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_armsmaster_harlan.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_armsmaster_harlan +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Halls (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_armsmaster_harlan() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_flameweaver_koegler.cpp b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_flameweaver_koegler.cpp new file mode 100644 index 0000000000..5ea1117f94 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_flameweaver_koegler.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_flameweaver_koegler +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Halls (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_flameweaver_koegler() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_houndmaster_braun.cpp b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_houndmaster_braun.cpp new file mode 100644 index 0000000000..f0b007fac7 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_boss_houndmaster_braun.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_houndmaster_braun +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Halls (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_houndmaster_braun() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_halls/mop_instance_scarlet_halls.cpp b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_instance_scarlet_halls.cpp new file mode 100644 index 0000000000..32b9dfa5bb --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_instance_scarlet_halls.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_instance_scarlet_halls +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Halls (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_instance_scarlet_halls() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_halls/mop_scarlet_halls.h b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_scarlet_halls.h new file mode 100644 index 0000000000..b685db9db5 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_halls/mop_scarlet_halls.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MOPSCARLETHALLS_H +#define DEF_MOPSCARLETHALLS_H + +#endif diff --git a/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_brother_korloff.cpp b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_brother_korloff.cpp new file mode 100644 index 0000000000..97aaf94e7b --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_brother_korloff.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_brother_korloff +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Monastery (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_brother_korloff() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_high_inquisitor_whitemane.cpp b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_high_inquisitor_whitemane.cpp new file mode 100644 index 0000000000..a9ce749490 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_high_inquisitor_whitemane.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_high_inquisitor_whitemane +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Monastery (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_high_inquisitor_whitemane() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_thalnos_the_soulrender.cpp b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_thalnos_the_soulrender.cpp new file mode 100644 index 0000000000..ff354b689e --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_boss_thalnos_the_soulrender.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_thalnos_the_soulrender +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Monastery (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_thalnos_the_soulrender() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_instance_scarlet_monastery.cpp b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_instance_scarlet_monastery.cpp new file mode 100644 index 0000000000..d78da2972a --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_instance_scarlet_monastery.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_instance_scarlet_monastery +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scarlet Monastery (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_instance_scarlet_monastery() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_scarlet_monastery.h b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_scarlet_monastery.h new file mode 100644 index 0000000000..3b769c4688 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scarlet_monastery/mop_scarlet_monastery.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MOPSCARLETMONASTERY_H +#define DEF_MOPSCARLETMONASTERY_H + +#endif diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_boss_darkmaster_gandling.cpp b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_darkmaster_gandling.cpp new file mode 100644 index 0000000000..f930746e95 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_darkmaster_gandling.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_darkmaster_gandling +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scholomance (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_darkmaster_gandling() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_boss_instructor_chillheart.cpp b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_instructor_chillheart.cpp new file mode 100644 index 0000000000..04186fc179 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_instructor_chillheart.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_instructor_chillheart +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scholomance (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_instructor_chillheart() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_boss_jandice_barov.cpp b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_jandice_barov.cpp new file mode 100644 index 0000000000..284326c062 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_jandice_barov.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_jandice_barov +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scholomance (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_jandice_barov() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_boss_lilian_voss.cpp b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_lilian_voss.cpp new file mode 100644 index 0000000000..4f5f46f120 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_lilian_voss.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_lilian_voss +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scholomance (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_lilian_voss() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_boss_rattlegore.cpp b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_rattlegore.cpp new file mode 100644 index 0000000000..4df24974e3 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_boss_rattlegore.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_boss_rattlegore +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scholomance (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_boss_rattlegore() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_instance_scholomance.cpp b/scripts/eastern_kingdoms/mop_scholomance/mop_instance_scholomance.cpp new file mode 100644 index 0000000000..8c06cb6042 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_instance_scholomance.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: mop_instance_scholomance +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Scholomance (MoP) +EndScriptData */ + +#include "precompiled.h" + +void AddSC_mop_instance_scholomance() +{ +} diff --git a/scripts/eastern_kingdoms/mop_scholomance/mop_scholomance.h b/scripts/eastern_kingdoms/mop_scholomance/mop_scholomance.h new file mode 100644 index 0000000000..beacc087b1 --- /dev/null +++ b/scripts/eastern_kingdoms/mop_scholomance/mop_scholomance.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MOPSCHOLOMANCE_H +#define DEF_MOPSCHOLOMANCE_H + +#endif diff --git a/scripts/eastern_kingdoms/redridge_mountains.cpp b/scripts/eastern_kingdoms/redridge_mountains.cpp index df978bb4a0..f3573f820f 100644 --- a/scripts/eastern_kingdoms/redridge_mountains.cpp +++ b/scripts/eastern_kingdoms/redridge_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -58,29 +58,38 @@ struct MANGOS_DLL_DECL npc_corporal_keeshan_escortAI : public npc_escortAI 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); + 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,12 +97,12 @@ 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; - + if (m_uiMockingBlowTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_MOCKING_BLOW); @@ -122,24 +131,18 @@ 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->GetGUID(), pQuest); - } - } + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); return true; } void AddSC_redridge_mountains() { - Script* NewScript; + Script* pNewScript; - NewScript = new Script; - NewScript->Name = "npc_corporal_keeshan"; - NewScript->GetAI = &GetAI_npc_corporal_keeshan; - NewScript->pQuestAccept = &QuestAccept_npc_corporal_keeshan; - NewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_corporal_keeshan"; + pNewScript->GetAI = &GetAI_npc_corporal_keeshan; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_corporal_keeshan; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp b/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp index dc6e6eb1eb..fef17f9d99 100644 --- a/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp +++ b/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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 +17,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, 12727, 12733, 12739(and 12742 to 12750), 12801, 12848, 12720, 12701. Special Npc (npc_valkyr_battle_maiden) SDCategory: Ebon Hold EndScriptData */ @@ -27,10 +28,31 @@ npc_death_knight_initiate npc_unworthy_initiate_anchor npc_unworthy_initiate go_acherus_soul_prison +npc_koltira_deathweaver +Mob scarlet miner +npc_scarlet_miner +Gothik +npc_eye_of_acherus +npc_mine_cart +scourge_gryphon +npc_valkyr_battle_maiden +npc_crusade_persuaded +npc_scarlet_ghoul +npc_highlord_darion_mograine +npc_fellow_death_knight +npc_acherus_deathcharger EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "world_map_ebon_hold.h" +#include "pet_ai.h" +#include "ObjectMgr.h" +#include "TemporarySummon.h" +#include "WorldPacket.h" +#include "Vehicle.h" +// not inuse yet but will be +// #define LESS_LAG // if you do not have a good server and do not want it to be laggy as hell -- uncomment this if you do /*###### ## npc_a_special_surprise @@ -98,22 +120,22 @@ enum SpecialSurprise struct MANGOS_DLL_DECL 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; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; - void Reset() + void Reset() override { m_uiExecuteSpeech_Timer = 0; m_uiExecuteSpeech_Counter = 0; - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); } bool MeetQuestCondition(Player* pPlayer) { - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case 29061: // Ellen Stanbridge if (pPlayer->GetQuestStatus(12742) == QUEST_STATUS_INCOMPLETE) @@ -160,22 +182,22 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI return false; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (m_uiPlayerGUID || pWho->GetTypeId() != TYPEID_PLAYER || !pWho->IsWithinDist(m_creature, INTERACTION_DISTANCE)) + if (m_playerGuid || pWho->GetTypeId() != TYPEID_PLAYER || !pWho->IsWithinDist(m_creature, INTERACTION_DISTANCE)) return; if (MeetQuestCondition((Player*)pWho)) - m_uiPlayerGUID = pWho->GetGUID(); + m_playerGuid = pWho->GetObjectGuid(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_uiPlayerGUID && !m_creature->getVictim() && m_creature->isAlive()) + if (m_playerGuid && !m_creature->getVictim() && m_creature->isAlive()) { if (m_uiExecuteSpeech_Timer < uiDiff) { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pPlayer) { @@ -183,12 +205,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 +238,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 +266,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 +294,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; @@ -299,8 +321,8 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI return; } break; - case RACE_UNDEAD_PLAYER: - switch(m_uiExecuteSpeech_Counter) + case RACE_UNDEAD: + 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 +350,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 +378,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 +406,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 +434,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 +462,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 +525,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 +555,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 { npc_death_knight_initiateAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 m_uiDuelerGUID; + 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_uiDuelStartStage = 0; + m_uiDuelTimer = 0; + m_bIsDuelComplete = false; - m_uiDuelerGUID = 0; - m_uiDuelTimer = 5000; - m_bIsDuelInProgress = 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_uiDuelerGUID = pCaster->GetGUID(); - 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_uiDuelerGUID)) - 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_uiDuelerGUID)) + 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,36 +723,42 @@ 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->GetGUID()); + 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; } +bool EffectDummyCreature_npc_death_knight_initiate(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_DUEL_TRIGGERED && uiEffIndex == EFFECT_INDEX_0) + { + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_START_EVENT, pCaster, pCreatureTarget); + return true; + } + + return false; +} + /*###### ## npc_koltira_deathweaver ######*/ @@ -662,33 +784,35 @@ enum eKoltira NPC_CRIMSON_ACOLYTE = 29007, NPC_HIGH_INQUISITOR_VALROTH = 29001, NPC_KOLTIRA_ALT = 28447, + NPC_KOLTIRA = 28912, - //not sure about this id - //NPC_DEATH_KNIGHT_MOUNT = 29201, + // 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 { - npc_koltira_deathweaverAI(Creature *pCreature) : npc_escortAI(pCreature) { Reset(); } + npc_koltira_deathweaverAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } uint32 m_uiWave; uint32 m_uiWave_Timer; - uint64 m_uiValrothGUID; + ObjectGuid m_valrothGuid; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { m_uiWave = 0; m_uiWave_Timer = 3000; - m_uiValrothGUID = 0; + m_creature->UpdateEntry(NPC_KOLTIRA); // needs to go back to regular entry at reset + m_valrothGuid.Clear(); } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: DoScriptText(SAY_BREAKOUT1, m_creature); @@ -698,14 +822,14 @@ struct MANGOS_DLL_DECL npc_koltira_deathweaverAI : public npc_escortAI break; case 2: m_creature->SetStandState(UNIT_STAND_STATE_STAND); - //m_creature->UpdateEntry(NPC_KOLTIRA_ALT); //unclear if we must update or not + // 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 + m_creature->UpdateEntry(NPC_KOLTIRA_ALT); // actual change // used to update to npc w antimagic zone template aura read sql for more notes break; case 4: SetRun(true); @@ -719,55 +843,60 @@ struct MANGOS_DLL_DECL npc_koltira_deathweaverAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (Player* pPlayer = GetPlayerForEscort()) - { pSummoned->AI()->AttackStart(pPlayer); - pSummoned->AddThreat(m_creature); - } if (pSummoned->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH) - m_uiValrothGUID = pSummoned->GetGUID(); + 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); + for (uint32 i = 0; i < uiAmount; ++i) + m_creature->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (HasEscortState(STATE_ESCORT_PAUSED)) { + if (m_uiWave < 4 && !m_creature->HasAura(SPELL_ANTI_MAGIC_ZONE)) + DoCast(m_creature, SPELL_ANTI_MAGIC_ZONE, true); + if (m_uiWave_Timer < uiDiff) { - switch(m_uiWave) + switch (m_uiWave) { case 0: + SetCombatMovement(false); // needed or he moves and doesnt stay in place DoScriptText(SAY_BREAKOUT3, m_creature); SummonAcolyte(3); m_uiWave_Timer = 20000; break; case 1: + SetCombatMovement(false); // needed or he moves and doesnt stay in place DoScriptText(SAY_BREAKOUT4, m_creature); SummonAcolyte(3); m_uiWave_Timer = 20000; break; case 2: + SetCombatMovement(false); // needed or he moves and doesnt stay in place DoScriptText(SAY_BREAKOUT5, m_creature); SummonAcolyte(4); m_uiWave_Timer = 20000; break; case 3: + SetCombatMovement(false); // needed or he moves and doesnt stay in place 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_creature->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 1000); m_uiWave_Timer = 1000; break; + // missing script text 7 = SAY_BREAKOUT7 case 4: { - Creature* pTemp = m_creature->GetMap()->GetCreature(m_uiValrothGUID); + Creature* pTemp = m_creature->GetMap()->GetCreature(m_valrothGuid); if (!pTemp || !pTemp->isAlive()) { @@ -777,12 +906,13 @@ struct MANGOS_DLL_DECL npc_koltira_deathweaverAI : public npc_escortAI else { m_uiWave_Timer = 2500; - return; //return, we don't want m_uiWave to increment now + return; // return, we don't want m_uiWave to increment now } break; } case 5: DoScriptText(SAY_BREAKOUT9, m_creature); + SetCombatMovement(true); // OK,OK deathweaver do your thing m_creature->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE); m_uiWave_Timer = 2500; break; @@ -817,13 +947,13 @@ bool QuestAccept_npc_koltira_deathweaver(Player* pPlayer, Creature* pCreature, c pCreature->SetStandState(UNIT_STAND_STATE_STAND); if (npc_koltira_deathweaverAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } /*###### -## +## npc_unworthy_initiate_anchor ######*/ enum @@ -831,17 +961,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, @@ -850,73 +975,39 @@ 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 { - npc_unworthy_initiate_anchorAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_uiMyInitiate = 0; - Reset(); - } + npc_unworthy_initiate_anchorAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 m_uiMyInitiate; - uint64 m_uiMyPrisonGUID; + ObjectGuid m_myInitiateGuid; + ObjectGuid m_myPrisonGuid; - void Reset() { } + void Reset() override {} - void NotifyMe(Unit* pSource, uint64 uiPrisonGuid) + void NotifyMe(Unit* pSource, GameObject* pGo) { - m_uiMyPrisonGUID = uiPrisonGuid; - Creature* pInitiate = m_creature->GetMap()->GetCreature(m_uiMyInitiate); + m_myPrisonGuid = pGo->GetObjectGuid(); + Creature* pInitiate = m_creature->GetMap()->GetCreature(m_myInitiateGuid); if (pInitiate && pSource) { pInitiate->SetLootRecipient(pSource); - m_creature->CastSpell(pInitiate,SPELL_CHAINED_PESANT_BREATH,true); + m_creature->CastSpell(pInitiate, SPELL_CHAINED_PESANT_BREATH, true); } } - void RegisterCloseInitiate(uint64 uiGuid) + void RegisterCloseInitiate(Creature* pCreature) { - m_uiMyInitiate = uiGuid; + m_myInitiateGuid = pCreature->GetObjectGuid(); } void ResetPrison() { - if (GameObject* pPrison = m_creature->GetMap()->GetGameObject(m_uiMyPrisonGUID)) + if (GameObject* pPrison = m_creature->GetMap()->GetGameObject(m_myPrisonGuid)) pPrison->ResetDoorOrButton(); } }; @@ -934,28 +1025,10 @@ struct MANGOS_DLL_DECL 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; - - uint64 m_uiMyAnchorGUID; - uint32 m_uiNormFaction; + ObjectGuid m_myAnchorGuid; uint32 m_uiAnchorCheckTimer; uint32 m_uiPhase; uint32 m_uiPhaseTimer; @@ -964,12 +1037,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_uiMyAnchorGUID = 0; m_uiAnchorCheckTimer = 5000; m_uiPhase = PHASE_INACTIVE_OR_COMBAT; m_uiPhaseTimer = 7500; @@ -979,12 +1048,18 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI m_uiPlagueStrike_Timer = 5000; } - void JustReachedHome() + void JustReachedHome() override { SetAnchor(); + + if (Creature* pAnchor = GetAnchor()) + { + if (npc_unworthy_initiate_anchorAI* pAnchorAI = dynamic_cast(pAnchor->AI())) + pAnchorAI->ResetPrison(); + } } - void JustRespawned() + void JustRespawned() override { if (Creature* pAnchor = GetAnchor()) { @@ -997,15 +1072,15 @@ 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() { - if (m_uiMyAnchorGUID) - return m_creature->GetMap()->GetCreature(m_uiMyAnchorGUID); + 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() @@ -1013,9 +1088,10 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if (Creature* pAnchor = GetAnchor()) { if (npc_unworthy_initiate_anchorAI* pAnchorAI = dynamic_cast(pAnchor->AI())) - pAnchorAI->RegisterCloseInitiate(m_creature->GetGUID()); + pAnchorAI->RegisterCloseInitiate(m_creature); pAnchor->CastSpell(m_creature, SPELL_CHAINED_PESANT_CHEST, false); + m_myAnchorGuid = pAnchor->GetObjectGuid(); m_uiAnchorCheckTimer = 0; return; @@ -1024,7 +1100,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) { @@ -1038,7 +1114,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiAnchorCheckTimer) { @@ -1055,7 +1131,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 @@ -1063,7 +1139,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 @@ -1071,7 +1147,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 @@ -1079,7 +1155,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 @@ -1093,19 +1169,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; @@ -1133,51 +1203,2909 @@ CreatureAI* GetAI_npc_unworthy_initiate(Creature* pCreature) ## go_acherus_soul_prison ######*/ -bool GOHello_go_acherus_soul_prison(Player* pPlayer, GameObject* pGo) +bool GOUse_go_acherus_soul_prison(Player* pPlayer, GameObject* pGo) { if (Creature* pAnchor = GetClosestCreatureWithEntry(pGo, NPC_ANCHOR, INTERACTION_DISTANCE)) { if (npc_unworthy_initiate_anchorAI* pAnchorAI = dynamic_cast(pAnchor->AI())) - pAnchorAI->NotifyMe(pPlayer, pGo->GetGUID()); + pAnchorAI->NotifyMe(pPlayer, 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(); + DISPLAYID_EYE_HUGE = 26320, + DISPLAYID_EYE_SMALL = 25499, - 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(); + SPELL_EYE_PHASEMASK = 70889, - pNewScript = new Script; - pNewScript->Name = "npc_koltira_deathweaver"; - pNewScript->GetAI = &GetAI_npc_koltira_deathweaver; - pNewScript->pQuestAccept = &QuestAccept_npc_koltira_deathweaver; - pNewScript->RegisterSelf(); + EMOTE_DESTIANTION = -1609089, + EMOTE_CONTROL = -1609090, - pNewScript = new Script; - pNewScript->Name = "npc_unworthy_initiate"; - pNewScript->GetAI = &GetAI_npc_unworthy_initiate; - pNewScript->RegisterSelf(); + POINT_EYE_DESTINATION = 0 +}; - pNewScript = new Script; - pNewScript->Name = "npc_unworthy_initiate_anchor"; - pNewScript->GetAI = &GetAI_npc_unworthy_initiate_anchor; - pNewScript->RegisterSelf(); +// movement destination coords +static const float aEyeDestination[3] = {1750.8276f, -5873.788f, 147.2266f}; - pNewScript = new Script; - pNewScript->Name = "go_acherus_soul_prison"; - pNewScript->pGOHello = &GOHello_go_acherus_soul_prison; +struct MANGOS_DLL_DECL 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(); + } + + bool m_bIsInitialized; + + void Reset() override + { + m_creature->SetDisplayId(DISPLAYID_EYE_HUGE); + } + + 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); + + m_creature->SetDisplayId(DISPLAYID_EYE_SMALL); + 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->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 MANGOS_DLL_DECL 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); + 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 MANGOS_DLL_DECL 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) override + { + 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 the lich king in dawn of light +######*/ + +enum _spells +{ + // Koltira Deathweaver & Orbaz Bloodbane are using the same abilities + SPELL_DEATH_GRIP = 49576, + SPELL_PLAGUE_STRIKE1 = 50668, + + // others + SPELL_CLEAVE = 53631, + SPELL_CLEAVE1 = 53633, + SPELL_SCOURGE_HOOK = 50335, + + SPELL_STOMP = 53634, + SPELL_THUNDERCLAP = 36706, + + NPC_ACHERUS_GHOUL = 29219, // just ghoul.... + SPELL_GHOULPLOSION = 53632, + + // ---- Dawn npc -------------------- + // Highlord Tirion Fordring + EQUIP_HIGHLORD_TIRION_FORDRING = 13262, + SPELL_TIRION_CHARGE_VISUAL = 53706, +}; + +/*###### +## npc orbaz, koltira, tassarian +######*/ +struct MANGOS_DLL_DECL npc_minibosses_dawn_of_lightAI : public ScriptedAI +{ + npc_minibosses_dawn_of_lightAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 uiIcyTouchTimer; + uint32 uiBloodStrikeTimer; + uint32 uiPlagueStrikeTimer; + + void Reset() + { + uiIcyTouchTimer = urand(10000, 20000); + uiBloodStrikeTimer = urand(10000, 20000); + uiPlagueStrikeTimer = urand(10000, 20000); + } + + bool EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) + { + m_creature->GetMotionMaster()->MoveIdle(); + return false; + } + void EnterEvadeMode() override + { + m_creature->GetMotionMaster()->MoveIdle(); + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->getVictim() || !m_creature->SelectHostileTarget() ) + return; + + if (uiIcyTouchTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICY_TOUCH); + uiIcyTouchTimer = urand(10000, 20000); + } + else uiIcyTouchTimer -= uiDiff; + + if (uiBloodStrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLOOD_STRIKE); + uiBloodStrikeTimer = urand(10000, 20000); + } + else uiBloodStrikeTimer -= uiDiff; + + if (uiPlagueStrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE1); + uiPlagueStrikeTimer = urand(10000, 20000); + } + else uiPlagueStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## Acherus Ghoul (29219) +######*/ +struct MANGOS_DLL_DECL mob_acherus_ghoulAI : public ScriptedAI +{ + mob_acherus_ghoulAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsReady = false; + m_bIsSpawned = false; + m_bIsInBattle = (m_creature->GetPositionX() < 2300.0f) ? true : false; + + m_pMap = m_creature->GetMap(); + + Reset(); + } + + Map *m_pMap; + + uint32 m_uiReadyTimer; + uint32 m_uiGhoulplosionTimer; + + bool m_bIsReady; + bool m_bIsSpawned; + bool m_bIsInBattle; + + void EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) { return; } + + void Reset() + { + m_uiReadyTimer = 4000; + m_uiGhoulplosionTimer = 30000; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIsReady) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void AttackStart(Unit* pWho) override + { + if (!m_bIsReady) + return; + + ScriptedAI::AttackStart(pWho); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsReady) + { + if (!m_bIsSpawned) + { + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + m_bIsSpawned = true; + } + + if (m_uiReadyTimer <= uiDiff) + m_bIsReady = true; + else m_uiReadyTimer -= uiDiff; + + return; + } + + if (!m_creature->getVictim() || !m_creature->SelectHostileTarget() ) + { + if (m_bIsInBattle && m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CONFUSED_MOTION_TYPE) + m_creature->GetMotionMaster()->MoveConfused(); + + return; + } + + if (m_uiGhoulplosionTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_GHOULPLOSION); + m_uiGhoulplosionTimer = 30000; + } + else m_uiGhoulplosionTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_valkyr_battle_maiden +######*/ + +enum +{ + SPELL_REVIVE = 51918, +}; + +#define REVIVE_WHISPER "It is not yet your time, champion. Rise! Rise and fight once more!" + +struct MANGOS_DLL_DECL npc_valkyr_battle_maidenAI : ScriptedAI +{ + npc_valkyr_battle_maidenAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + float x, y, z; + + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + ObjectGuid m_summonerGuid; + + void Reset() + { + m_summonerGuid = m_creature->GetGuidValue(UNIT_FIELD_SUMMONEDBY); + if (m_creature->IsTemporarySummon()) + m_summonerGuid = ((TemporarySummon*)m_creature)->GetSummonerGuid(); + else + script_error_log("npc_valkyr_battle_maiden: Creature %s must be tempSummoned, but seems as regular summon. Pleas, correct DB contains!", m_creature->GetObjectGuid().GetString().c_str()); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetLevitate(true); + m_uiPhase = 0; + m_uiPhaseTimer = 0; + } + + void UpdateAI(const uint32 uiDiff) override + { + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_summonerGuid); + if (!pPlayer) + m_uiPhase = 3; + + if (m_uiPhaseTimer <= uiDiff) + { + switch (m_uiPhase) + { + case 0: + pPlayer->GetClosePoint(x, y, z, m_creature->GetObjectBoundingRadius()); + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMap()->CreatureRelocation(m_creature, x-2.0f , y-1.5f, z+2.5f, 0); + m_creature->SetFacingToObject(pPlayer); + m_creature->SetVisibility(VISIBILITY_ON); + m_uiPhase++; + break; + case 1: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pPlayer->GetObjectGuid()); + m_uiPhase++; + break; + case 2: + DoCast(pPlayer, SPELL_REVIVE, true); + m_creature->MonsterWhisper(REVIVE_WHISPER, pPlayer); + // cause 51918 has cast time of 2 seconds + m_uiPhaseTimer = 3000; + m_uiPhase++; + break; + case 3: + m_creature->ForcedDespawn(); + default: + break; + } + } + else + m_uiPhaseTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_valkyr_battle_maiden(Creature* pCreature) +{ + return new npc_valkyr_battle_maidenAI(pCreature); +}; + +/*###### +## mob_warrior_of_the_frozen_wastes (53631) +######*/ +struct MANGOS_DLL_DECL mob_warrior_of_the_frozen_wastesAI : public ScriptedAI +{ + mob_warrior_of_the_frozen_wastesAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsReady = false; + m_bIsSpawned = false; + m_bIsInBattle = (m_creature->GetPositionX() < 2300.0f) ? true : false; + + Reset(); + } + + uint32 m_uiReadyTimer; + uint32 m_uiCleaveTimer; + + bool m_bIsReady; + bool m_bIsSpawned; + bool m_bIsInBattle; + + void EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) { return; } + + void Reset() + { + m_uiReadyTimer = 4000; + m_uiCleaveTimer = urand(3000, 5000); + } + + void AttackStart(Unit* pWho) override + { + if (!m_bIsReady) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIsReady) + return; + + CreatureAI::MoveInLineOfSight(pWho); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsReady) + { + if (!m_bIsSpawned) + { + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + m_bIsSpawned = true; + } + + if (m_uiReadyTimer <= uiDiff) + m_bIsReady = true; + else m_uiReadyTimer -= uiDiff; + + return; + } + + if (!m_creature->getVictim() || !m_creature->SelectHostileTarget() ) + { + if (m_bIsInBattle && m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CONFUSED_MOTION_TYPE) + m_creature->GetMotionMaster()->MoveConfused(); + + return; + } + + if (m_uiCleaveTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); + m_uiCleaveTimer = urand(13000, 15000); + } + else m_uiCleaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_mine_car +######*/ + +struct MANGOS_DLL_DECL npc_mine_carAI : public ScriptedAI +{ + npc_mine_carAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + Reset(); + } + + ObjectGuid m_scarletMinerGuid; + + void Reset() + { + m_scarletMinerGuid.Clear(); + } + + void MoveInLineOfSight(Unit* /*pUnit*/) override + { + return; + } + + void EnterCombat(Unit* /*pUnit*/) override + { + return; + } + + void AttackStart(Unit* /*pUnit*/) + { + return; + } + + void SetScarletMinerGuid(const ObjectGuid &guid) + { + m_scarletMinerGuid = guid; + } + + void FollowMiner() + { + if(Creature* pMiner = m_creature->GetMap()->GetCreature(m_scarletMinerGuid)) + { + // buggy sometimes... + m_creature->SetSpeedRate(MOVE_WALK, 1.5f, true); + m_creature->SetSpeedRate(MOVE_RUN, 1.5f, true); + m_creature->SetWalk(false); + + m_creature->GetMotionMaster()->MoveFollow(pMiner, 1.0f, 0); + } + } + + void ExitMineCar() + { + if (Creature* pMiner = m_creature->GetMap()->GetCreature(m_scarletMinerGuid)) + pMiner->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->GetVehicleKit() || m_creature->GetVehicleKit()->HasEmptySeat(0)) + { + m_creature->ForcedDespawn(); + } + } +}; + +/*###### +## npc_scarlet_miner +######*/ + +enum +{ + SPELL_CAR_DRAG = 52465, + SPELL_CAR_CHECK = 54173 +}; + +#define SAY_SCARLET_MINER1 "Where'd this come from? I better get this down to the ships before the foreman sees it!" +#define SAY_SCARLET_MINER2 "Now I can have a rest!" + +struct MANGOS_DLL_DECL npc_scarlet_minerAI : public npc_escortAI +{ + npc_scarlet_minerAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Reset(); + } + + uint32 m_uiMonoTimer; + uint32 m_uiMonoPhase; + + ObjectGuid m_mineCarGuid; + ObjectGuid m_playerGuid; + + bool m_bReachedShip; + uint32 m_uiShipDelay; + + void Reset() + { + m_uiMonoTimer = 0; + m_uiMonoPhase = 0; + + m_mineCarGuid.Clear(); + m_playerGuid.Clear(); + + m_bReachedShip = false; + m_uiShipDelay = 3000; + } + + void StartCarEvent(Player *pPlayer) + { + if (pPlayer->GetVehicle()) + { + m_mineCarGuid = pPlayer->GetVehicle()->GetBase()->GetObjectGuid(); + m_playerGuid = pPlayer->GetObjectGuid(); + Start(false, pPlayer); + } + } + + void WaypointReached(uint32 uiWp) override + { + switch(uiWp) + { + case 0: + if (Unit* pMineCar = m_creature->GetMap()->GetCreature(m_mineCarGuid)) + m_creature->SetInFront(pMineCar); + + SetRun(true); + m_uiMonoTimer = 4000; + m_uiMonoPhase = 1; + break; + case 17: + m_bReachedShip = true; + break; + default: + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiMonoPhase) + { + if (m_uiMonoTimer <= uiDiff) + { + if (m_uiMonoPhase == 1) + { + m_creature->MonsterSay(SAY_SCARLET_MINER1,LANG_UNIVERSAL, NULL); + + if (Creature *pMineCar = m_creature->GetMap()->GetCreature(m_mineCarGuid)) + DoCast(pMineCar, SPELL_CAR_DRAG); + + m_uiMonoTimer = 800; + m_uiMonoPhase = 2; + } + else + { + if (Creature *pMineCar = m_creature->GetMap()->GetCreature(m_mineCarGuid)) + { + if(npc_mine_carAI* pMineCarAI = dynamic_cast(pMineCar->AI())) + { + pMineCarAI->FollowMiner(); + } + m_uiMonoPhase = 0; + } + } + } + else + m_uiMonoTimer -= uiDiff; + } + + if (m_bReachedShip) + { + if (m_uiShipDelay <= uiDiff) + { + if (Creature *pMineCar = m_creature->GetMap()->GetCreature(m_mineCarGuid)) + { + m_creature->SetInFront(pMineCar); + m_creature->MonsterSay(SAY_SCARLET_MINER2,LANG_UNIVERSAL, NULL); + pMineCar->Relocate(pMineCar->GetPositionX(), pMineCar->GetPositionY(), pMineCar->GetPositionZ() + 1); + pMineCar->GetMotionMaster()->MovementExpired(); + pMineCar->StopMoving(); + pMineCar->RemoveAurasDueToSpell(SPELL_CAR_DRAG); + + if (Player *pPlayer = m_creature->GetMap()->GetPlayer(ObjectGuid(m_playerGuid))) + { + if (pPlayer->GetVehicle()) + pPlayer->ExitVehicle(); + } + + if (npc_mine_carAI* pMineCarAI = dynamic_cast(pMineCar->AI())) + { + pMineCarAI->ExitMineCar(); + } + + m_bReachedShip = false; + } + } + else + m_uiShipDelay -= uiDiff; + } + npc_escortAI::UpdateAI(uiDiff); + } +}; + +/*###### +## go_inconspicous_mine_car +######*/ + +enum +{ + QUEST_MASSACRE_AT_LIGHTS_POINT = 12701, + + ENTRY_SCARLET_MINER = 28841, + ENTRY_MINE_CAR = 28817, + + SPELL_MINE_CAR_SUMM = 52463 +}; + +bool GOUse_go_inconspicous_mine_car(Player* pPlayer, GameObject* /*pGo*/) +{ + if (pPlayer->GetQuestStatus(QUEST_MASSACRE_AT_LIGHTS_POINT) == QUEST_STATUS_INCOMPLETE) + { + if (pPlayer->GetVehicle()) + return false; + + if (Creature* pMiner = pPlayer->SummonCreature(ENTRY_SCARLET_MINER, 2383.869f, -5900.312f, 107.996f, pPlayer->GetOrientation(),TEMPSUMMON_DEAD_DESPAWN, 1)) + { + pPlayer->CastSpell(pPlayer, SPELL_MINE_CAR_SUMM, true); + if (Creature* pMineCar = (Creature*)pPlayer->GetVehicle()->GetBase()) + { + if (npc_mine_carAI* pMineCarAI = dynamic_cast(pMineCar->AI())) + { + pMineCarAI->SetScarletMinerGuid(pMiner->GetObjectGuid()); + if (npc_scarlet_minerAI* pMinerAI = dynamic_cast(pMiner->AI())) + { + pMinerAI->StartCarEvent(pPlayer); + } + } + } + } + } + return true; +} + +/*###### +## npc_scourge_gryphon +######*/ + +enum +{ + RIDE_VEHICLE_HARDCODED = 46598 +}; + +struct MANGOS_DLL_DECL npc_scourge_gryphonAI : public npc_escortAI +{ + npc_scourge_gryphonAI(Creature* pCreature) : npc_escortAI(pCreature) + { + //m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Reset(); + } + + void Reset() + { + } + + void SpellHit(Unit* pUnit, const SpellEntry* pSpell) override + { + if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) + { + if (pSpell->Id == RIDE_VEHICLE_HARDCODED) + { + FlyToDeathsBreach((Player*)pUnit); + } + } + } + + void FlyToDeathsBreach(Player* pPlayer) + { + pPlayer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + // Need to be set here. If flag is applied earlier, the Spell Immune Mask + // makes the vehicle mount spell (ID - 46598 Ride Vehicle Hardcoded) disfunctional + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetLevitate(true); + + Start(true, pPlayer); + } + + void WaypointReached(uint32 uiWp) override + { + switch(uiWp) + { + case 0: + SetRun(); + break; + case 4: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_creature->ForcedDespawn(); // should be enough to remove players just take the vehicle away 8) + return; + default: + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + npc_escortAI::UpdateAI(uiDiff); + } +}; + +/*###### +## quest How To Win Friends And Influence Enemies && replaces EventAI for these npcs overall +######*/ +enum win_friends +{ + QUEST_HOW_TO_WIN_FRIENDS = 12720, + + NPC_PREACHER = 28939, + SPELL_HOLY_FURY_OOC = 34809, + SPELL_HOLY_SMITE = 15498, + + NPC_MARKSMEN = 28610, + SPELL_RAPTOR_STRIKE = 32915, + + SAY_PERSUADE1 = -1609101, + SAY_PERSUADE2 = -1609102, + SAY_PERSUADE3 = -1609103, + SAY_PERSUADE4 = -1609104, + SAY_PERSUADE5 = -1609105, + SAY_PERSUADE6 = -1609106, + SAY_PERSUADE7 = -1609107, + SAY_CRUSADER1 = -1609108, + SAY_CRUSADER2 = -1609109, + SAY_CRUSADER3 = -1609110, + SAY_CRUSADER4 = -1609111, + SAY_CRUSADER5 = -1609112, + SAY_CRUSADER6 = -1609113, + SAY_PERSUADED1 = -1609114, + SAY_PERSUADED2 = -1609115, + SAY_PERSUADED3 = -1609116, + SAY_PERSUADED4 = -1609117, + SAY_PERSUADED5 = -1609118, + SAY_PERSUADED6 = -1609119, + + SPELL_PERSUASIVE_STRIKE = 52781 +}; + +struct MANGOS_DLL_DECL npc_crusade_persuadedAI : public ScriptedAI +{ + npc_crusade_persuadedAI(Creature *pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + ObjectGuid m_playerGUID; + uint32 m_uiSpeech_timer; + uint32 m_uiSpeech_counter; + uint32 m_uiCrusade_faction; + + uint32 m_uiHOLYFURYTimer; + uint32 m_uiHOLYSMITETimer; + uint32 m_uiRATORSTRIKETimer; + + void Reset() + { + m_uiSpeech_timer = 0; + m_uiSpeech_counter = 0; + m_uiCrusade_faction = 0; + m_playerGUID.Clear(); + + m_uiHOLYFURYTimer = 60000; + m_uiHOLYSMITETimer = 5500; + + m_uiRATORSTRIKETimer = 4500; + } + + void SpellHit(Unit* caster, const SpellEntry* spell) override + { + if (caster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && spell->Id == SPELL_PERSUASIVE_STRIKE && m_uiSpeech_counter == 0) + { + if(((Player*)caster)->GetQuestStatus(QUEST_HOW_TO_WIN_FRIENDS) == QUEST_STATUS_INCOMPLETE) + { + if (rand()%100 > 90) // chance + { + m_playerGUID = ((Player*)caster)->GetObjectGuid(); + m_uiCrusade_faction = m_creature->getFaction(); + m_uiSpeech_timer = 1000; + m_uiSpeech_counter = 1; + m_creature->setFaction(35); + } + else if (m_uiSpeech_counter == 0) + { + switch(rand()%6) + { + case 0: DoScriptText(SAY_PERSUADE1, caster);break; + case 1: DoScriptText(SAY_PERSUADE2, caster);break; + case 2: DoScriptText(SAY_PERSUADE3, caster);break; + case 3: DoScriptText(SAY_PERSUADE4, caster);break; + case 4: DoScriptText(SAY_PERSUADE5, caster);break; + case 5: DoScriptText(SAY_PERSUADE6, caster);break; + case 6: DoScriptText(SAY_PERSUADE7, caster);break; + } + switch(rand()%5) + { + case 0: DoScriptText(SAY_CRUSADER1, m_creature);break; + case 1: DoScriptText(SAY_CRUSADER2, m_creature);break; + case 2: DoScriptText(SAY_CRUSADER3, m_creature);break; + case 3: DoScriptText(SAY_CRUSADER4, m_creature);break; + case 4: DoScriptText(SAY_CRUSADER5, m_creature);break; + case 5: DoScriptText(SAY_CRUSADER6, m_creature);break; + } + } + } + } + } + + void UpdateAI(const uint32 diff) + { + if (m_uiSpeech_counter >= 1 && m_uiSpeech_counter <= 6) + { + if (m_uiSpeech_timer < diff) + { + m_creature->CombatStop(true); + m_creature->StopMoving(); + if (Unit* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGUID)) + { + switch(m_uiSpeech_counter) + { + case 1: DoScriptText(SAY_PERSUADED1, m_creature); m_uiSpeech_timer = 8000; m_uiSpeech_counter++; break; + case 2: DoScriptText(SAY_PERSUADED2, m_creature); m_uiSpeech_timer = 8000; m_uiSpeech_counter++; break; + case 3: DoScriptText(SAY_PERSUADED3, m_creature); m_uiSpeech_timer = 8000; m_uiSpeech_counter++; break; + case 4: DoScriptText(SAY_PERSUADED4, m_creature); m_uiSpeech_timer = 8000; m_uiSpeech_counter++; break; + case 5: DoScriptText(SAY_PERSUADED5, pPlayer); m_uiSpeech_timer = 8000; m_uiSpeech_counter++; break; + case 6: + DoScriptText(SAY_PERSUADED6, m_creature); + m_creature->setFaction(m_uiCrusade_faction); + m_uiSpeech_timer = 0; + m_uiCrusade_faction = 0; + m_uiSpeech_counter++; + AttackStart(pPlayer); + if(((Player*)pPlayer)->GetQuestStatus(QUEST_HOW_TO_WIN_FRIENDS) == QUEST_STATUS_INCOMPLETE) + ((Player*)pPlayer)->AreaExploredOrEventHappens(QUEST_HOW_TO_WIN_FRIENDS); + break; + } + } + } + else + m_uiSpeech_timer -= diff; + } + else + { + if (m_creature->GetEntry() == NPC_PREACHER) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHOLYSMITETimer < diff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_SMITE); + m_uiHOLYSMITETimer = 5500 + rand()%1400; + }else m_uiHOLYSMITETimer -= diff; + + if (m_uiHOLYFURYTimer < diff) + { + DoCastSpellIfCan(m_creature, SPELL_HOLY_FURY_OOC); + m_uiHOLYFURYTimer = 1000 + rand()%90000; + }else m_uiHOLYFURYTimer -= diff; + + DoMeleeAttackIfReady(); + } + else + { + if (m_creature->GetEntry() == NPC_MARKSMEN) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiRATORSTRIKETimer < diff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_RAPTOR_STRIKE); + m_uiRATORSTRIKETimer = 4500 + rand()%1400; + }else m_uiRATORSTRIKETimer -= diff; + DoMeleeAttackIfReady(); + } + } + } + } +}; + +//Scarlet courier +enum ScarletCourierEnum +{ + SAY_TREE1 = -1609531, + SAY_TREE2 = -1609532, + GO_INCONSPICUOUS_TREE = 191144, + NPC_SCARLET_COURIER = 29076 +}; + +struct MANGOS_DLL_DECL mob_scarlet_courierAI : ScriptedAI +{ + mob_scarlet_courierAI(Creature *pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint8 m_uiStage; + uint32 m_uiStageTimer; + + void Reset() + { + m_creature->Mount(14338); // not sure about this id + m_uiStage = 1; + m_uiStageTimer = 3*IN_MILLISECONDS; + } + + void EnterCombat(Unit* pWho) override + { + DoScriptText(SAY_TREE2, m_creature); + m_creature->Unmount(); + m_uiStage = 0; + } + + void MovementInform(uint32 m_uiType, uint32 m_uiId) override + { + if (m_uiType != POINT_MOTION_TYPE) + return; + + if (m_uiId == 1) + m_uiStage = 2; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiStage && !m_creature->isInCombat()) + { + if (m_uiStageTimer <= uiDiff) + { + switch(m_uiStage) + { + case 1: + m_creature->SetWalk(true); + if (GameObject* tree = GetClosestGameObjectWithEntry(m_creature,GO_INCONSPICUOUS_TREE, 40.0f)) + { + DoScriptText(SAY_TREE1, m_creature); + float x, y, z; + tree->GetContactPoint(m_creature, x, y, z); + m_creature->GetMotionMaster()->MovePoint(1, x, y, z); + } + break; + case 2: + if (GameObject* tree = GetClosestGameObjectWithEntry(m_creature,GO_INCONSPICUOUS_TREE, 40.0f)) + if (Unit *unit = tree->GetOwner()) + AttackStart(unit); + break; + default: + break; + } + + m_uiStageTimer = 3*IN_MILLISECONDS; + m_uiStage = 0; + } + else + m_uiStageTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_scarlet_courier(Creature* pCreature) +{ + return new mob_scarlet_courierAI(pCreature); +}; + +CreatureAI* GetAI_npc_crusade_persuaded(Creature* pCreature) +{ + return new npc_crusade_persuadedAI(pCreature); +}; + +CreatureAI* GetAI_npc_minibosses_dawn_of_light(Creature* pCreature) +{ + return new npc_minibosses_dawn_of_lightAI (pCreature); +}; + +CreatureAI* GetAI_mob_warrior_of_the_frozen_wastes(Creature* pCreature) +{ + return new mob_warrior_of_the_frozen_wastesAI(pCreature); +}; + +CreatureAI* GetAI_mob_acherus_ghoul(Creature* pCreature) +{ + return new mob_acherus_ghoulAI(pCreature); +}; + +CreatureAI* GetAI_npc_mine_car(Creature* pCreature) +{ + return new npc_mine_carAI(pCreature); +}; + +CreatureAI* GetAI_npc_scarlet_miner(Creature* pCreature) +{ + return new npc_scarlet_minerAI(pCreature); +}; + +CreatureAI* GetAI_npc_scourge_gryphon(Creature* pCreature) +{ + return new npc_scourge_gryphonAI(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_koltira_deathweaver"; + pNewScript->GetAI = &GetAI_npc_koltira_deathweaver; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_koltira_deathweaver; + 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_minibosses_dawn_of_light"; + pNewScript->GetAI = &GetAI_npc_minibosses_dawn_of_light; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_acherus_ghoul"; + pNewScript->GetAI = &GetAI_mob_acherus_ghoul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_mine_car"; + pNewScript->GetAI = &GetAI_npc_mine_car; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_inconspicous_mine_car"; + pNewScript->pGOUse = &GOUse_go_inconspicous_mine_car; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scourge_gryphon"; + pNewScript->GetAI = &GetAI_npc_scourge_gryphon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_warrior_of_the_frozen_wastes"; + pNewScript->GetAI = &GetAI_mob_warrior_of_the_frozen_wastes; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name= "npc_valkyr_battle_maiden"; + pNewScript->GetAI = &GetAI_npc_valkyr_battle_maiden; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_crusade_persuaded"; + pNewScript->GetAI = &GetAI_npc_crusade_persuaded; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name= "mob_scarlet_courier"; + pNewScript->GetAI = &GetAI_mob_scarlet_courier; + 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_miner"; + pNewScript->GetAI = &GetAI_npc_scarlet_miner; 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 0000000000..0cca286e43 --- /dev/null +++ b/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.cpp @@ -0,0 +1,294 @@ +/* Copyright (C) 2006 - 2013 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: 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 0000000000..daee851a4d --- /dev/null +++ b/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.h @@ -0,0 +1,147 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * 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 +}; + +// light champions +static EVENTLOCATION 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 EVENTLOCATION 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 EVENTLOCATION 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 MANGOS_DLL_DECL 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 f7a09a9ca3..6f6c70b8d9 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,89 +29,102 @@ enum SAY_SPECIALAE = -1189020, SPELL_POLYMORPH = 13323, - SPELL_AOESILENCE = 8988, - SPELL_ARCANEEXPLOSION = 9433, - SPELL_FIREAOE = 9435, - SPELL_ARCANEBUBBLE = 9438, + SPELL_SILENCE = 8988, + SPELL_ARCANE_EXPLOSION = 9433, + SPELL_DETONATION = 9435, + SPELL_ARCANE_BUBBLE = 9438, }; struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI { boss_arcanist_doanAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 Polymorph_Timer; - uint32 AoESilence_Timer; - uint32 ArcaneExplosion_Timer; - bool bCanDetonate; + uint32 m_uiPolymorphTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiArcaneExplosionTimer; + uint32 m_uiDetonationTimer; bool bShielded; void Reset() { - Polymorph_Timer = 20000; - AoESilence_Timer = 15000; - ArcaneExplosion_Timer = 3000; - bCanDetonate = false; - bShielded = false; + m_uiPolymorphTimer = 15000; + m_uiSilenceTimer = 7500; + m_uiArcaneExplosionTimer = urand(1000, 3000); + m_uiDetonationTimer = 0; + bShielded = false; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (bShielded && bCanDetonate) + if (m_uiDetonationTimer) { - DoCastSpellIfCan(m_creature,SPELL_FIREAOE); - bCanDetonate = false; + if (m_uiDetonationTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DETONATION) == CAST_OK) + { + DoScriptText(SAY_SPECIALAE, m_creature); + m_uiDetonationTimer = 0; + } + } + else + m_uiDetonationTimer -= uiDiff; } - if (m_creature->HasAura(SPELL_ARCANEBUBBLE)) + // Do not attack while having the bubble active + if (m_creature->HasAura(SPELL_ARCANE_BUBBLE)) return; - //If we are <50% hp cast Arcane Bubble + // If we are <50% hp cast Arcane Bubble if (!bShielded && m_creature->GetHealthPercent() <= 50.0f) { - //wait if we already casting - if (m_creature->IsNonMeleeSpellCasted(false)) - return; - - DoScriptText(SAY_SPECIALAE, m_creature); - DoCastSpellIfCan(m_creature,SPELL_ARCANEBUBBLE); - - bCanDetonate = true; - bShielded = true; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_BUBBLE) == CAST_OK) + { + m_uiDetonationTimer = 1000; + bShielded = true; + } } - if (Polymorph_Timer < diff) + if (m_uiPolymorphTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target,SPELL_POLYMORPH); - - Polymorph_Timer = 20000; - }else Polymorph_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_POLYMORPH) == CAST_OK) + m_uiPolymorphTimer = 20000; + } + } + else + m_uiPolymorphTimer -= uiDiff; - //AoESilence_Timer - if (AoESilence_Timer < diff) + // Silence_Timer + if (m_uiSilenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_AOESILENCE); - AoESilence_Timer = urand(15000, 20000); - }else AoESilence_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = urand(15000, 22000); + } + else + m_uiSilenceTimer -= uiDiff; - //ArcaneExplosion_Timer - if (ArcaneExplosion_Timer < diff) + // ArcaneExplosion_Timer + if (m_uiArcaneExplosionTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANEEXPLOSION); - ArcaneExplosion_Timer = 8000; - }else ArcaneExplosion_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = urand(2500, 8500); + } + else + m_uiArcaneExplosionTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_arcanist_doan(Creature* pCreature) { return new boss_arcanist_doanAI(pCreature); @@ -119,9 +132,10 @@ CreatureAI* GetAI_boss_arcanist_doan(Creature* pCreature) void AddSC_boss_arcanist_doan() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_arcanist_doan"; - newscript->GetAI = &GetAI_boss_arcanist_doan; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_arcanist_doan"; + pNewScript->GetAI = &GetAI_boss_arcanist_doan; + pNewScript->RegisterSelf(); } 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 ecb71f9d4f..0000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (C) 2006 - 2010 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; - - 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 *newscript; - newscript = new Script; - newscript->Name = "boss_azshir_the_sleepless"; - newscript->GetAI = &GetAI_boss_azshir_the_sleepless; - newscript->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 6fe0745ccd..0000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_bloodmage_thalnos"; - newscript->GetAI = &GetAI_boss_bloodmage_thalnos; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp index dbb941ed0a..db0bd1f7fa 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 +}; + +enum HorsemanPhase +{ + PHASE_HORSEMAN = 1, + PHASE_CONFLAGRATION = 2, + PHASE_PUMPKINS = 3, + PHASE_HEAD_TOSS = 4, }; struct MANGOS_DLL_DECL boss_headless_horsemanAI : public ScriptedAI { - boss_headless_horsemanAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_headless_horsemanAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->SetWalk(false); + m_creature->SetLevitate(true); + + m_bHorsemanLanded = false; + Reset(); + } + + bool m_bHorsemanLanded; + bool m_bHeadRequested; + + HorsemanPhase m_fightPhase; + + ObjectGuid m_headGuid; + + uint32 m_uiCleaveTimer; + uint32 m_uiConflagrationTimer; + uint32 m_uiPumpkinTimer; + + void Reset() override + { + 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 MoveInLineOfSight(Unit* pWho) override + { + if (m_bHorsemanLanded) + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + DoCastSpellIfCan(pVictim, SPELL_JACK_LANTERNED, CAST_TRIGGERED); + DoScriptText(SAY_SLAY, m_creature); + } + } - void Reset() + 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 Aggro(Unit* pWho) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { - m_creature->SetInCombatWithZone(); + if (m_fightPhase != PHASE_HEAD_TOSS && uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + DoTossHead(); + } } - void KilledUnit(Unit* pVictim) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - DoScriptText(SAY_SLAY, m_creature); + if (pSpell->Id == SPELL_HORSEMAN_SUMMON) + DoScriptText(SAY_SPROUTING_PUMPKINS, m_creature); } - void JustDied(Unit* pKiller) + 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,12 +347,138 @@ 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 MANGOS_DLL_DECL 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* NewScript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_headless_horseman"; + pNewScript->GetAI = GetAI_boss_headless_horseman; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_boss_headless_horseman; + pNewScript->RegisterSelf(); - NewScript = new Script; - NewScript->Name = "boss_headless_horseman"; - NewScript->GetAI = GetAI_boss_headless_horseman; - NewScript->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 fc13cb4c38..ce26dd7125 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -32,7 +32,7 @@ enum SAY_KILL = -1189003, EMOTE_GENERIC_ENRAGED = -1000003, - SAY_TRAINEE_SPAWN = -1189036, + SAY_TRAINEE_SPAWN = -1189035, SPELL_RUSHINGCHARGE = 8260, SPELL_CLEAVE = 15496, @@ -48,7 +48,7 @@ struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI bool m_bEnrage; bool m_bTraineeSay; - + uint32 m_uiCleaveTimer; uint32 m_uiWhirlwindTimer; @@ -56,12 +56,12 @@ struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI { 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 @@ -145,9 +144,9 @@ struct MANGOS_DLL_DECL mob_scarlet_traineeAI : public npc_escortAI uint32 m_uiStartTimer; void Reset() { } - void WaypointReached(uint32 /*uiPointId*/) {} + void WaypointReached(uint32 /*uiPointId*/) override {} - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_uiStartTimer) { @@ -175,6 +174,7 @@ CreatureAI* GetAI_mob_scarlet_trainee(Creature* pCreature) void AddSC_boss_herod() { Script* pNewScript; + pNewScript = new Script; pNewScript->Name = "boss_herod"; pNewScript->GetAI = &GetAI_boss_herod; 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 9725d6dbf3..0000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_high_inquisitor_fairbanks"; - newscript->GetAI = &GetAI_boss_high_inquisitor_fairbanks; - newscript->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 ce7f2ae373..0000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_houndmaster_loksey"; - newscript->GetAI = &GetAI_boss_houndmaster_loksey; - newscript->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 346dfe352a..0000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (C) 2006 - 2010 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, - SAY_TRIGGER_VORREL = -1189015, - - SPELL_SHADOWWORDPAIN = 2767, -}; - -struct MANGOS_DLL_DECL boss_interrogator_vishasAI : public ScriptedAI -{ - boss_interrogator_vishasAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - 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 JustDied(Unit* Killer) - { - if (!m_pInstance) - return; - - //Any other actions to do with vorrel? setStandState? - if (Creature *vorrel = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_VORREL))) - DoScriptText(SAY_TRIGGER_VORREL, vorrel); - } - - 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 *newscript; - newscript = new Script; - newscript->Name = "boss_interrogator_vishas"; - newscript->GetAI = &GetAI_boss_interrogator_vishas; - newscript->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 a036b9f733..251ab76525 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, @@ -70,42 +70,43 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI void Reset() { - 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->instance->GetCreature(m_pInstance->GetData64(DATA_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,8 +114,8 @@ 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 - if (Creature* pWhitemane = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_WHITEMANE))) + // 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,7 +130,7 @@ 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); @@ -142,9 +143,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 +156,46 @@ 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->instance->GetCreature(m_pInstance->GetData64(DATA_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->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; @@ -225,26 +224,25 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI void Reset() { - 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; - if (Creature* pMograine = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_MOGRAINE))) + if (Creature* pMograine = m_pInstance->GetSingleCreatureFromStorage(NPC_MOGRAINE)) { if (m_creature->isAlive() && !pMograine->isAlive()) pMograine->Respawn(); } } - - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -253,12 +251,12 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI } } - void MoveInLineOfSight() + 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; @@ -266,11 +264,11 @@ 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); } } - 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; @@ -278,92 +276,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->instance->GetCreature(m_pInstance->GetData64(DATA_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->instance->GetCreature(m_pInstance->GetData64(DATA_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; @@ -384,15 +364,15 @@ CreatureAI* GetAI_boss_high_inquisitor_whitemane(Creature* pCreature) void AddSC_boss_mograine_and_whitemane() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_scarlet_commander_mograine"; - newscript->GetAI = &GetAI_boss_scarlet_commander_mograine; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_scarlet_commander_mograine"; + pNewScript->GetAI = &GetAI_boss_scarlet_commander_mograine; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_high_inquisitor_whitemane"; - newscript->GetAI = &GetAI_boss_high_inquisitor_whitemane; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_high_inquisitor_whitemane"; + pNewScript->GetAI = &GetAI_boss_high_inquisitor_whitemane; + pNewScript->RegisterSelf(); } 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 ae35efc27e..0000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_scorn"; - newscript->GetAI = &GetAI_boss_scorn; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp b/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp index 38b1fe051d..b151187a80 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp +++ b/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,81 +25,75 @@ EndScriptData */ #include "precompiled.h" #include "scarlet_monastery.h" -struct MANGOS_DLL_DECL instance_scarlet_monastery : public ScriptedInstance +instance_scarlet_monastery::instance_scarlet_monastery(Map* pMap) : ScriptedInstance(pMap) { - instance_scarlet_monastery(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint64 m_uiMograineGUID; - uint64 m_uiWhitemaneGUID; - uint64 m_uiVorrelGUID; - uint64 m_uiDoorHighInquisitorGUID; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + Initialize(); +} - m_uiMograineGUID = 0; - m_uiWhitemaneGUID = 0; - m_uiVorrelGUID = 0; - m_uiDoorHighInquisitorGUID = 0; - } +void instance_scarlet_monastery::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void OnCreatureCreate(Creature* pCreature) +void instance_scarlet_monastery::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pCreature->GetEntry()) - { - case 3976: m_uiMograineGUID = pCreature->GetGUID(); break; - case 3977: m_uiWhitemaneGUID = pCreature->GetGUID(); break; - case 3981: m_uiVorrelGUID = pCreature->GetGUID(); break; - } + case NPC_HEAD: + case NPC_PUMPKIN_FIEND: + case NPC_HEADLESS_HORSEMAN: + case NPC_MOGRAINE: + case NPC_WHITEMANE: + case NPC_VORREL: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void OnObjectCreate(GameObject* pGo) +void instance_scarlet_monastery::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_INTERROGATOR_VISHAS) { - if (pGo->GetEntry() == 104600) - m_uiDoorHighInquisitorGUID = pGo->GetGUID(); + // Any other actions to do with Vorrel? setStandState? + if (Creature* pVorrel = GetSingleCreatureFromStorage(NPC_VORREL)) + DoScriptText(SAY_TRIGGER_VORREL, pVorrel); } +} - uint64 GetData64(uint32 data) - { - switch(data) - { - case DATA_MOGRAINE: - return m_uiMograineGUID; - case DATA_WHITEMANE: - return m_uiWhitemaneGUID; - case DATA_VORREL: - return m_uiVorrelGUID; - case DATA_DOOR_WHITEMANE: - return m_uiDoorHighInquisitorGUID; - } - - return 0; - } +void instance_scarlet_monastery::OnObjectCreate(GameObject* pGo) +{ + if (pGo->GetEntry() == GO_WHITEMANE_DOOR) + m_mGoEntryGuidStore[GO_WHITEMANE_DOOR] = pGo->GetObjectGuid(); +} - void SetData(uint32 uiType, uint32 uiData) +void instance_scarlet_monastery::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - if (uiType == TYPE_MOGRAINE_AND_WHITE_EVENT) - { + case TYPE_MOGRAINE_AND_WHITE_EVENT: if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiDoorHighInquisitorGUID); + DoUseDoorOrButton(GO_WHITEMANE_DOOR); if (uiData == FAIL) - DoUseDoorOrButton(m_uiDoorHighInquisitorGUID); - + DoUseDoorOrButton(GO_WHITEMANE_DOOR); m_auiEncounter[0] = uiData; - } + break; + case TYPE_HALLOWSEND_EVENT: + m_auiEncounter[1] = uiData; + break; } +} - uint32 GetData(uint32 uiData) +uint32 instance_scarlet_monastery::GetData(uint32 uiData) const +{ + switch(uiData) { - if (uiData == TYPE_MOGRAINE_AND_WHITE_EVENT) + case TYPE_MOGRAINE_AND_WHITE_EVENT: return m_auiEncounter[0]; - - return 0; + case TYPE_HALLOWSEND_EVENT: + return m_auiEncounter[1]; } -}; + return 0; +} InstanceData* GetInstanceData_instance_scarlet_monastery(Map* pMap) { @@ -107,9 +102,10 @@ InstanceData* GetInstanceData_instance_scarlet_monastery(Map* pMap) void AddSC_instance_scarlet_monastery() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_scarlet_monastery"; - newscript->GetInstanceData = &GetInstanceData_instance_scarlet_monastery; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_scarlet_monastery"; + pNewScript->GetInstanceData = &GetInstanceData_instance_scarlet_monastery; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h b/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h index 62e3443ce9..92f3366f42 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h +++ b/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,14 +8,41 @@ enum { - MAX_ENCOUNTER = 1, + MAX_ENCOUNTER = 2, TYPE_MOGRAINE_AND_WHITE_EVENT = 1, + TYPE_HALLOWSEND_EVENT = 6, - DATA_MOGRAINE = 2, - DATA_WHITEMANE = 3, - DATA_DOOR_WHITEMANE = 4, - DATA_VORREL = 5 + NPC_MOGRAINE = 3976, + NPC_WHITEMANE = 3977, + NPC_VORREL = 3981, + NPC_INTERROGATOR_VISHAS = 3983, + + NPC_HEAD = 23775, + NPC_PUMPKIN_FIEND = 23545, + NPC_HEADLESS_HORSEMAN = 23682, + + GO_WHITEMANE_DOOR = 104600, + + SAY_TRIGGER_VORREL = -1189015, +}; + +class MANGOS_DLL_DECL instance_scarlet_monastery : public ScriptedInstance +{ + public: + instance_scarlet_monastery(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiData) const override; + + private: + uint32 m_auiEncounter[MAX_ENCOUNTER]; }; #endif diff --git a/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp b/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp index 0355a2bbd9..57b69e0155 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,37 +16,21 @@ /* ScriptData SDName: Boss_Darkmaster_Gandling -SD%Complete: 75 -SDComment: Doors missing +SD%Complete: 100 +SDComment: SDCategory: Scholomance EndScriptData */ #include "precompiled.h" #include "scholomance.h" -#define SPELL_ARCANEMISSILES 22272 -#define SPELL_SHADOWSHIELD 22417 //Not right ID. But 12040 is wrong either. -#define SPELL_CURSE 18702 - -#define ADD_1X 170.205 -#define ADD_1Y 99.413 -#define ADD_1Z 104.733 -#define ADD_1O 3.16 - -#define ADD_2X 170.813 -#define ADD_2Y 97.857 -#define ADD_2Z 104.713 -#define ADD_2O 3.16 - -#define ADD_3X 170.720 -#define ADD_3Y 100.900 -#define ADD_3Z 104.739 -#define ADD_3O 3.16 - -#define ADD_4X 171.866 -#define ADD_4Y 99.373 -#define ADD_4Z 104.732 -#define ADD_4O 3.16 +enum +{ + SPELL_ARCANE_MISSILES = 15790, + SPELL_SHADOW_SHIELD = 12040, + SPELL_CURSE = 18702, + SPELL_SHADOW_PORTAL = 17950 +}; struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI { @@ -58,155 +42,77 @@ struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 ArcaneMissiles_Timer; - uint32 ShadowShield_Timer; - uint32 Curse_Timer; - uint32 Teleport_Timer; - - Creature *Summoned; + uint32 m_uiArcaneMissilesTimer; + uint32 m_uiShadowShieldTimer; + uint32 m_uiCurseTimer; + uint32 m_uiTeleportTimer; void Reset() { - ArcaneMissiles_Timer = 4500; - ShadowShield_Timer = 12000; - Curse_Timer = 2000; - Teleport_Timer = 16000; + m_uiArcaneMissilesTimer = 4500; + m_uiShadowShieldTimer = 12000; + m_uiCurseTimer = 2000; + m_uiTeleportTimer = 16000; } - void JustDied(Unit *killer) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_GANDLING, DONE); - } - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //ArcaneMissiles_Timer - if (ArcaneMissiles_Timer < diff) + // Arcane Missiles Timer + if (m_uiArcaneMissilesTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANEMISSILES); - ArcaneMissiles_Timer = 8000; - }else ArcaneMissiles_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_MISSILES) == CAST_OK) + m_uiArcaneMissilesTimer = 8000; + } + else + m_uiArcaneMissilesTimer -= uiDiff; - //ShadowShield_Timer - if (ShadowShield_Timer < diff) + // Shadow Shield Timer + if (m_uiShadowShieldTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_SHADOWSHIELD); - ShadowShield_Timer = urand(14000, 28000); - }else ShadowShield_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_SHIELD) == CAST_OK) + m_uiShadowShieldTimer = urand(14000, 28000); + } + else + m_uiShadowShieldTimer -= uiDiff; - //Curse_Timer - if (Curse_Timer < diff) + // Curse Timer + if (m_uiCurseTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSE); - Curse_Timer = urand(15000, 27000); - }else Curse_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CURSE) == CAST_OK) + m_uiCurseTimer = urand(15000, 27000); + } + else + m_uiCurseTimer -= uiDiff; - //Teleporting Random Target to one of the six pre boss rooms and spawn 3-4 skeletons near the gamer. - //We will only telport if gandling has more than 3% of hp so teleported gamers can always loot. + // Teleporting Random Target to one of the six pre boss rooms and spawn 3-4 skeletons near the gamer. + // We will only telport if gandling has more than 3% of hp so teleported gamers can always loot. if (m_creature->GetHealthPercent() > 3.0f) { - if (Teleport_Timer < diff) + if (m_uiTeleportTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SHADOW_PORTAL, SELECT_FLAG_PLAYER)) { - if (m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - switch(urand(0, 5)) + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_PORTAL) == CAST_OK) { - case 0: - DoTeleportPlayer(target, 250.0696f, 0.3921f, 84.8408f, 3.149f); - Summoned = m_creature->SummonCreature(16119, 254.2325f, 0.3417f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 257.7133f, 4.0226f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 258.6702f, -2.60656f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 1: - DoTeleportPlayer(target, 181.4220f, -91.9481f, 84.8410f, 1.608f); - Summoned = m_creature->SummonCreature(16119, 184.0519f, -73.5649f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 179.5951f, -73.7045f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 180.6452f, -78.2143f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 283.2274f, -78.1518f, 84.8407f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 2: - DoTeleportPlayer(target, 95.1547f, -1.8173f, 85.2289f, 0.043f); - Summoned = m_creature->SummonCreature(16119, 100.9404f, -1.8016f, 85.2289f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 101.3729f, 0.4882f, 85.2289f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 101.4596f, -4.4740f, 85.2289f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 3: - DoTeleportPlayer(target, 250.0696f, 0.3921f, 72.6722f, 3.149f); - Summoned = m_creature->SummonCreature(16119, 240.34481f, 0.7368f, 72.6722f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 240.3633f, -2.9520f, 72.6722f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 240.6702f, 3.34949f, 72.6722f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 4: - DoTeleportPlayer(target, 181.4220f, -91.9481f, 70.7734f, 1.608f); - Summoned = m_creature->SummonCreature(16119, 184.0519f, -73.5649f, 70.7734f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 179.5951f, -73.7045f, 70.7734f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 180.6452f, -78.2143f, 70.7734f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 283.2274f, -78.1518f, 70.7734f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 5: - DoTeleportPlayer(target, 106.1541f, -1.8994f, 75.3663f, 0.043f); - Summoned = m_creature->SummonCreature(16119, 115.3945f, -1.5555f, 75.3663f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 257.7133f, 1.8066f, 75.3663f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = m_creature->SummonCreature(16119, 258.6702f, -5.1001f, 75.3663f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; + // remove threat + if (m_creature->getThreatManager().getThreat(pTarget)) + m_creature->getThreatManager().modifyThreatPercent(pTarget, -100); + + m_uiTeleportTimer = urand(20000, 35000); } } - Teleport_Timer = urand(20000, 35000); - }else Teleport_Timer -= diff; + } + else + m_uiTeleportTimer -= uiDiff; } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_darkmaster_gandling(Creature* pCreature) { return new boss_darkmaster_gandlingAI(pCreature); @@ -214,9 +120,10 @@ CreatureAI* GetAI_boss_darkmaster_gandling(Creature* pCreature) void AddSC_boss_darkmaster_gandling() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_darkmaster_gandling"; - newscript->GetAI = &GetAI_boss_darkmaster_gandling; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_darkmaster_gandling"; + pNewScript->GetAI = &GetAI_boss_darkmaster_gandling; + pNewScript->RegisterSelf(); } 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 64a206839c..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_death_knight_darkreaver"; - newscript->GetAI = &GetAI_boss_death_knight_darkreaver; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_doctor_theolen_krastinov.cpp b/scripts/eastern_kingdoms/scholomance/boss_doctor_theolen_krastinov.cpp deleted file mode 100644 index 571ad0bd74..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_doctor_theolen_krastinov.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Doctor_Theolen_Krastinov -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "scholomance.h" - -enum -{ - EMOTE_GENERIC_FRENZY_KILL = -1000001, - - SPELL_REND = 16509, - SPELL_BACKHAND = 18103, - SPELL_FRENZY = 8269 -}; - -struct MANGOS_DLL_DECL boss_theolenkrastinovAI : public ScriptedAI -{ - boss_theolenkrastinovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiRend_Timer; - uint32 m_uiBackhand_Timer; - uint32 m_uiFrenzy_Timer; - - void Reset() - { - m_uiRend_Timer = 8000; - m_uiBackhand_Timer = 9000; - m_uiFrenzy_Timer = 1000; - } - - void JustDied(Unit *killer) - { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - pInstance->SetData(TYPE_THEOLEN, DONE); - - if (pInstance->GetData(TYPE_GANDLING) == SPECIAL) - m_creature->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Rend_Timer - if (m_uiRend_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_REND); - m_uiRend_Timer = 10000; - } - else - m_uiRend_Timer -= uiDiff; - - //m_uiBackhand_Timer - if (m_uiBackhand_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BACKHAND); - m_uiBackhand_Timer = 10000; - } - else - m_uiBackhand_Timer -= uiDiff; - - //Frenzy_Timer - if (m_creature->GetHealthPercent() < 26.0f) - { - if (m_uiFrenzy_Timer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - m_uiFrenzy_Timer = 120000; - } - } - else - m_uiFrenzy_Timer -= uiDiff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_theolenkrastinov(Creature* pCreature) -{ - return new boss_theolenkrastinovAI(pCreature); -} - -void AddSC_boss_theolenkrastinov() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_doctor_theolen_krastinov"; - newscript->GetAI = &GetAI_boss_theolenkrastinov; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_illucia_barov.cpp b/scripts/eastern_kingdoms/scholomance/boss_illucia_barov.cpp deleted file mode 100644 index d0e004c411..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_illucia_barov.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Illucia_Barov -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "scholomance.h" - -#define SPELL_CURSEOFAGONY 18671 -#define SPELL_SHADOWSHOCK 20603 -#define SPELL_SILENCE 15487 -#define SPELL_FEAR 6215 - -struct MANGOS_DLL_DECL boss_illuciabarovAI : public ScriptedAI -{ - boss_illuciabarovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 CurseOfAgony_Timer; - uint32 ShadowShock_Timer; - uint32 Silence_Timer; - uint32 Fear_Timer; - - void Reset() - { - CurseOfAgony_Timer = 18000; - ShadowShock_Timer = 9000; - Silence_Timer = 5000; - Fear_Timer = 30000; - } - - void JustDied(Unit *killer) - { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - pInstance->SetData(TYPE_ILLUCIABAROV, DONE); - - if (pInstance->GetData(TYPE_GANDLING) == SPECIAL) - m_creature->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //CurseOfAgony_Timer - if (CurseOfAgony_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFAGONY); - CurseOfAgony_Timer = 30000; - }else CurseOfAgony_Timer -= diff; - - //ShadowShock_Timer - if (ShadowShock_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_SHADOWSHOCK); - - ShadowShock_Timer = 12000; - }else ShadowShock_Timer -= diff; - - //Silence_Timer - if (Silence_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SILENCE); - Silence_Timer = 14000; - }else Silence_Timer -= diff; - - //Fear_Timer - if (Fear_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FEAR); - Fear_Timer = 30000; - }else Fear_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_illuciabarov(Creature* pCreature) -{ - return new boss_illuciabarovAI(pCreature); -} - -void AddSC_boss_illuciabarov() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_illucia_barov"; - newscript->GetAI = &GetAI_boss_illuciabarov; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_instructor_malicia.cpp b/scripts/eastern_kingdoms/scholomance/boss_instructor_malicia.cpp deleted file mode 100644 index c39ad59513..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_instructor_malicia.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_instructormalicia -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "scholomance.h" - -#define SPELL_CALLOFGRAVES 17831 -#define SPELL_CORRUPTION 11672 -#define SPELL_FLASHHEAL 10917 -#define SPELL_RENEW 10929 -#define SPELL_HEALINGTOUCH 9889 - -struct MANGOS_DLL_DECL boss_instructormaliciaAI : public ScriptedAI -{ - boss_instructormaliciaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 CallOfGraves_Timer; - uint32 Corruption_Timer; - uint32 FlashHeal_Timer; - uint32 Renew_Timer; - uint32 HealingTouch_Timer; - uint32 FlashCounter; - uint32 TouchCounter; - - void Reset() - { - CallOfGraves_Timer = 4000; - Corruption_Timer = 8000; - FlashHeal_Timer = 38000; - Renew_Timer = 32000; - HealingTouch_Timer = 45000; - FlashCounter = 0; - TouchCounter = 0; - } - - void JustDied(Unit *killer) - { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - pInstance->SetData(TYPE_MALICIA, DONE); - - if (pInstance->GetData(TYPE_GANDLING) == SPECIAL) - m_creature->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //CallOfGraves_Timer - if (CallOfGraves_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CALLOFGRAVES); - CallOfGraves_Timer = 65000; - }else CallOfGraves_Timer -= diff; - - //Corruption_Timer - if (Corruption_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_CORRUPTION); - - Corruption_Timer = 24000; - }else Corruption_Timer -= diff; - - //Renew_Timer - if (Renew_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_RENEW); - Renew_Timer = 10000; - }else Renew_Timer -= diff; - - //FlashHeal_Timer - if (FlashHeal_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_FLASHHEAL); - - //5 Flashheals will be casted - if (FlashCounter < 2) - { - FlashHeal_Timer = 5000; - ++FlashCounter; - } - else - { - FlashCounter=0; - FlashHeal_Timer = 30000; - } - }else FlashHeal_Timer -= diff; - - //HealingTouch_Timer - if (HealingTouch_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_HEALINGTOUCH); - - //3 Healingtouchs will be casted - if (HealingTouch_Timer < 2) - { - HealingTouch_Timer = 5500; - ++TouchCounter; - } - else - { - TouchCounter=0; - HealingTouch_Timer = 30000; - } - }else HealingTouch_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_instructormalicia(Creature* pCreature) -{ - return new boss_instructormaliciaAI(pCreature); -} - -void AddSC_boss_instructormalicia() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_instructor_malicia"; - newscript->GetAI = &GetAI_boss_instructormalicia; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp b/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp index e8fd9237fe..d8b7f5cbdc 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,154 +23,71 @@ EndScriptData */ #include "precompiled.h" -#define SPELL_CURSEOFBLOOD 24673 -//#define SPELL_ILLUSION 17773 - -//Spells of Illusion of Jandice Barov -#define SPELL_CLEAVE 15584 +enum +{ + SPELL_CURSE_OF_BLOOD = 16098, + SPELL_SUMMON_ILLUSIONS = 17773, + SPELL_BANISH = 8994, +}; struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI { boss_jandicebarovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 CurseOfBlood_Timer; - uint32 Illusion_Timer; - //uint32 Illusioncounter; - uint32 Invisible_Timer; - bool Invisible; - int Rand; - int RandX; - int RandY; - Creature* Summoned; + uint32 m_uiCurseOfBloodTimer; + uint32 m_uiIllusionTimer; + uint32 m_uiBanishTimer; void Reset() { - CurseOfBlood_Timer = 15000; - Illusion_Timer = 30000; - Invisible_Timer = 3000; //Too much too low? - Invisible = false; + m_uiCurseOfBloodTimer = 5000; + m_uiIllusionTimer = 15000; + m_uiBanishTimer = urand(9000, 13000); } - void SummonIllusions(Unit* victim) + void JustSummoned(Creature* pSummoned) override { - 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(11439, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - if (Summoned) - Summoned->AI()->AttackStart(victim); + pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (Invisible && Invisible_Timer < diff) - { - //Become visible again - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetDisplayId(11073); //Jandice Model - Invisible = false; - } else if (Invisible) - { - Invisible_Timer -= diff; - //Do nothing while invisible - return; - } - - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //CurseOfBlood_Timer - if (CurseOfBlood_Timer < diff) + // CurseOfBlood_Timer + if (m_uiCurseOfBloodTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFBLOOD); - CurseOfBlood_Timer = 30000; - }else CurseOfBlood_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_CURSE_OF_BLOOD) == CAST_OK) + m_uiCurseOfBloodTimer = urand(30000, 35000); + } + else + m_uiCurseOfBloodTimer -= uiDiff; - //Illusion_Timer - if (!Invisible && Illusion_Timer < diff) + // Banish + if (m_uiBanishTimer < uiDiff) { - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetDisplayId(11686); // Invisible Model - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-99); - - //Summon 10 Illusions attacking random gamers - Unit* target = NULL; - for(int i = 0; i < 10; ++i) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) { - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - SummonIllusions(target); + if (DoCastSpellIfCan(pTarget, SPELL_BANISH) == CAST_OK) + m_uiBanishTimer = urand(17000, 21000); } - Invisible = true; - Invisible_Timer = 3000; - - //25 seconds until we should cast this agian - Illusion_Timer = 25000; - }else Illusion_Timer -= diff; - - // //Illusion_Timer - // if (Illusion_Timer < diff) - // { - // //Cast - // DoCastSpellIfCan(m_creature->getVictim(),SPELL_ILLUSION); - // //3 Illusion will be summoned - // if (Illusioncounter < 3) - // { - // Illusion_Timer = 500; - // ++Illusioncounter; - // } - // else { - // //15 seconds until we should cast this again - // Illusion_Timer = 15000; - // Illusioncounter=0; - // } - // }else Illusion_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -// Illusion of Jandice Barov Script - -struct MANGOS_DLL_DECL mob_illusionofjandicebarovAI : public ScriptedAI -{ - mob_illusionofjandicebarovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Cleave_Timer; - - void Reset() - { - Cleave_Timer = urand(2000, 8000); - m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + } + else + m_uiBanishTimer -= uiDiff; - //Cleave_Timer - if (Cleave_Timer < diff) + // Illusion_Timer + if (m_uiIllusionTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = urand(5000, 8000); - }else Cleave_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ILLUSIONS) == CAST_OK) + m_uiIllusionTimer = 25000; + } + else + m_uiIllusionTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -181,21 +98,12 @@ 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 *newscript; - newscript = new Script; - newscript->Name = "boss_jandice_barov"; - newscript->GetAI = &GetAI_boss_jandicebarov; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_illusionofjandicebarov"; - newscript->GetAI = &GetAI_mob_illusionofjandicebarov; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_jandice_barov"; + pNewScript->GetAI = &GetAI_boss_jandicebarov; + 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 42601365ee..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_kormok.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" - -#define SPELL_SHADOWBOLTVOLLEY 20741 -#define SPELL_BONESHIELD 27688 - -struct MANGOS_DLL_DECL boss_kormokAI : public ScriptedAI -{ - boss_kormokAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowVolley_Timer; - uint32 BoneShield_Timer; - uint32 Minion_Timer; - uint32 Mage_Timer; - bool Mages; - int Rand1; - int Rand1X; - int Rand1Y; - int Rand2; - int Rand2X; - int Rand2Y; - Creature* SummonedMinions; - Creature* SummonedMages; - - void Reset() - { - ShadowVolley_Timer = 10000; - BoneShield_Timer = 2000; - Minion_Timer = 15000; - Mage_Timer = 0; - Mages = false; - } - - void SummonMinion(Unit* victim) - { - Rand1 = rand()%8; - switch(urand(0, 1)) - { - case 0: Rand1X = 0 - Rand1; break; - case 1: Rand1X = 0 + Rand1; break; - } - Rand1 = 0; - Rand1 = rand()%8; - switch(urand(0, 1)) - { - case 0: Rand1Y = 0 - Rand1; break; - case 1: Rand1Y = 0 + Rand1; break; - } - Rand1 = 0; - SummonedMinions = DoSpawnCreature(16119, Rand1X, Rand1Y, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); - if (SummonedMinions) - SummonedMinions->AI()->AttackStart(victim); - } - - void SummonMages(Unit* victim) - { - Rand2 = rand()%10; - switch(urand(0, 1)) - { - case 0: Rand2X = 0 - Rand2; break; - case 1: Rand2X = 0 + Rand2; break; - } - Rand2 = 0; - Rand2 = rand()%10; - switch(urand(0, 1)) - { - case 0: Rand2Y = 0 - Rand2; break; - case 1: Rand2Y = 0 + Rand2; break; - } - Rand2 = 0; - SummonedMages = DoSpawnCreature(16120, Rand2X, Rand2Y, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); - if (SummonedMages) - SummonedMages->AI()->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); - ShadowVolley_Timer = 15000; - }else ShadowVolley_Timer -= diff; - - //BoneShield_Timer - if (BoneShield_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BONESHIELD); - BoneShield_Timer = 45000; - }else BoneShield_Timer -= diff; - - //Minion_Timer - if (Minion_Timer < diff) - { - //Cast - SummonMinion(m_creature->getVictim()); - SummonMinion(m_creature->getVictim()); - SummonMinion(m_creature->getVictim()); - SummonMinion(m_creature->getVictim()); - - Minion_Timer = 12000; - }else Minion_Timer -= diff; - - //Summon 2 Bone Mages - if (!Mages && m_creature->GetHealthPercent() < 26.0f) - { - //Cast - SummonMages(m_creature->getVictim()); - SummonMages(m_creature->getVictim()); - Mages = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_kormok(Creature* pCreature) -{ - return new boss_kormokAI(pCreature); -} - -void AddSC_boss_kormok() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_kormok"; - newscript->GetAI = &GetAI_boss_kormok; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_lord_alexei_barov.cpp b/scripts/eastern_kingdoms/scholomance/boss_lord_alexei_barov.cpp deleted file mode 100644 index 9dfb790db5..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_lord_alexei_barov.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Lord_Alexei_Barov -SD%Complete: 100 -SDComment: aura applied/defined in database -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "scholomance.h" - -#define SPELL_IMMOLATE 20294 // Old ID was 15570 -#define SPELL_VEILOFSHADOW 17820 - -struct MANGOS_DLL_DECL boss_lordalexeibarovAI : public ScriptedAI -{ - boss_lordalexeibarovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Immolate_Timer; - uint32 VeilofShadow_Timer; - - void Reset() - { - Immolate_Timer = 7000; - VeilofShadow_Timer = 15000; - - m_creature->LoadCreatureAddon(); - } - - void JustDied(Unit *killer) - { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - pInstance->SetData(TYPE_ALEXEIBAROV, DONE); - - if (pInstance->GetData(TYPE_GANDLING) == SPECIAL) - m_creature->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Immolate_Timer - if (Immolate_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_IMMOLATE); - - Immolate_Timer = 12000; - }else Immolate_Timer -= diff; - - //VeilofShadow_Timer - if (VeilofShadow_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_VEILOFSHADOW); - VeilofShadow_Timer = 20000; - }else VeilofShadow_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lordalexeibarov(Creature* pCreature) -{ - return new boss_lordalexeibarovAI(pCreature); -} - -void AddSC_boss_lordalexeibarov() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_lord_alexei_barov"; - newscript->GetAI = &GetAI_boss_lordalexeibarov; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_lorekeeper_polkelt.cpp b/scripts/eastern_kingdoms/scholomance/boss_lorekeeper_polkelt.cpp deleted file mode 100644 index 2c11cae19b..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_lorekeeper_polkelt.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Lorekeeper_Polkelt -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "scholomance.h" - -#define SPELL_VOLATILEINFECTION 24928 -#define SPELL_DARKPLAGUE 18270 -#define SPELL_CORROSIVEACID 23313 -#define SPELL_NOXIOUSCATALYST 18151 - -struct MANGOS_DLL_DECL boss_lorekeeperpolkeltAI : public ScriptedAI -{ - boss_lorekeeperpolkeltAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 VolatileInfection_Timer; - uint32 Darkplague_Timer; - uint32 CorrosiveAcid_Timer; - uint32 NoxiousCatalyst_Timer; - - void Reset() - { - VolatileInfection_Timer = 38000; - Darkplague_Timer = 8000; - CorrosiveAcid_Timer = 45000; - NoxiousCatalyst_Timer = 35000; - } - - void JustDied(Unit *killer) - { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - pInstance->SetData(TYPE_POLKELT, DONE); - - if (pInstance->GetData(TYPE_GANDLING) == SPECIAL) - m_creature->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //VolatileInfection_Timer - if (VolatileInfection_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_VOLATILEINFECTION); - VolatileInfection_Timer = 32000; - }else VolatileInfection_Timer -= diff; - - //Darkplague_Timer - if (Darkplague_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DARKPLAGUE); - Darkplague_Timer = 8000; - }else Darkplague_Timer -= diff; - - //CorrosiveAcid_Timer - if (CorrosiveAcid_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CORROSIVEACID); - CorrosiveAcid_Timer = 25000; - }else CorrosiveAcid_Timer -= diff; - - //NoxiousCatalyst_Timer - if (NoxiousCatalyst_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_NOXIOUSCATALYST); - NoxiousCatalyst_Timer = 38000; - }else NoxiousCatalyst_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_lorekeeperpolkelt(Creature* pCreature) -{ - return new boss_lorekeeperpolkeltAI(pCreature); -} - -void AddSC_boss_lorekeeperpolkelt() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_lorekeeper_polkelt"; - newscript->GetAI = &GetAI_boss_lorekeeperpolkelt; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_ras_frostwhisper.cpp b/scripts/eastern_kingdoms/scholomance/boss_ras_frostwhisper.cpp deleted file mode 100644 index 3e8d123e94..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_ras_frostwhisper.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Ras_Frostwhisper -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FROSTBOLT 21369 -#define SPELL_ICEARMOR 18100 //This is actually a buff he gives himself -#define SPELL_FREEZE 18763 -#define SPELL_FEAR 26070 -#define SPELL_CHILLNOVA 18099 -#define SPELL_FROSTVOLLEY 8398 - -struct MANGOS_DLL_DECL boss_rasfrostAI : public ScriptedAI -{ - boss_rasfrostAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 IceArmor_Timer; - uint32 Frostbolt_Timer; - uint32 Freeze_Timer; - uint32 Fear_Timer; - uint32 ChillNova_Timer; - uint32 FrostVolley_Timer; - - void Reset() - { - IceArmor_Timer = 2000; - Frostbolt_Timer = 8000; - ChillNova_Timer = 12000; - Freeze_Timer = 18000; - FrostVolley_Timer = 24000; - Fear_Timer = 45000; - - m_creature->CastSpell(m_creature,SPELL_ICEARMOR,true); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //IceArmor_Timer - if (IceArmor_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_ICEARMOR); - IceArmor_Timer = 180000; - }else IceArmor_Timer -= diff; - - //Frostbolt_Timer - if (Frostbolt_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_FROSTBOLT); - - Frostbolt_Timer = 8000; - }else Frostbolt_Timer -= diff; - - //Freeze_Timer - if (Freeze_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FREEZE); - Freeze_Timer = 24000; - }else Freeze_Timer -= diff; - - //Fear_Timer - if (Fear_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FEAR); - Fear_Timer = 30000; - }else Fear_Timer -= diff; - - //ChillNova_Timer - if (ChillNova_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CHILLNOVA); - ChillNova_Timer = 14000; - }else ChillNova_Timer -= diff; - - //FrostVolley_Timer - if (FrostVolley_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTVOLLEY); - FrostVolley_Timer = 15000; - }else FrostVolley_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_rasfrost(Creature* pCreature) -{ - return new boss_rasfrostAI(pCreature); -} - -void AddSC_boss_rasfrost() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_boss_ras_frostwhisper"; - newscript->GetAI = &GetAI_boss_rasfrost; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_the_ravenian.cpp b/scripts/eastern_kingdoms/scholomance/boss_the_ravenian.cpp deleted file mode 100644 index 4a5ce54b61..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_the_ravenian.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_ravenian -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" -#include "scholomance.h" - -#define SPELL_TRAMPLE 15550 -#define SPELL_CLEAVE 20691 -#define SPELL_SUNDERINCLEAVE 25174 -#define SPELL_KNOCKAWAY 10101 - -struct MANGOS_DLL_DECL boss_theravenianAI : public ScriptedAI -{ - boss_theravenianAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Trample_Timer; - uint32 Cleave_Timer; - uint32 SunderingCleave_Timer; - uint32 KnockAway_Timer; - bool HasYelled; - - void Reset() - { - Trample_Timer = 24000; - Cleave_Timer = 15000; - SunderingCleave_Timer = 40000; - KnockAway_Timer = 32000; - HasYelled = false; - } - - void JustDied(Unit *killer) - { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - pInstance->SetData(TYPE_RAVENIAN, DONE); - - if (pInstance->GetData(TYPE_GANDLING) == SPECIAL) - m_creature->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Trample_Timer - if (Trample_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_TRAMPLE); - Trample_Timer = 10000; - }else Trample_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - //SunderingCleave_Timer - if (SunderingCleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SUNDERINCLEAVE); - SunderingCleave_Timer = 20000; - }else SunderingCleave_Timer -= diff; - - //KnockAway_Timer - if (KnockAway_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKAWAY); - KnockAway_Timer = 12000; - }else KnockAway_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_theravenian(Creature* pCreature) -{ - return new boss_theravenianAI(pCreature); -} - -void AddSC_boss_theravenian() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_the_ravenian"; - newscript->GetAI = &GetAI_boss_theravenian; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp b/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp deleted file mode 100644 index 2635260b5f..0000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_vectus"; - newscript->GetAI = &GetAI_boss_vectus; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp b/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp index 2a14e4d939..615cbbeea2 100644 --- a/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp +++ b/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,115 +16,372 @@ /* ScriptData SDName: Instance_Scholomance -SD%Complete: 100 -SDComment: +SD%Complete: 99 +SDComment: Possible some D2 or other exotic missing SDCategory: Scholomance EndScriptData */ #include "precompiled.h" #include "scholomance.h" -struct MANGOS_DLL_DECL instance_scholomance : public ScriptedInstance +instance_scholomance::instance_scholomance(Map* pMap) : ScriptedInstance(pMap), + m_uiGandlingEvent(0) { - instance_scholomance(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} + +void instance_scholomance::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + for (uint8 i = 0; i < MAX_EVENTS; ++i) + m_mGandlingData[aGandlingEvents[i]] = GandlingEventData(); +} + +void instance_scholomance::OnPlayerEnter(Player* /*pPlayer*/) +{ + // Summon Gandling if can + DoSpawnGandlingIfCan(true); +} + +void instance_scholomance::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_DARKMASTER_GANDLING: + m_mNpcEntryGuidStore[NPC_DARKMASTER_GANDLING] = pCreature->GetObjectGuid(); + break; + case NPC_BONE_MINION: + GandlingEventMap::iterator find = m_mGandlingData.find(m_uiGandlingEvent); + if (find != m_mGandlingData.end()) + find->second.m_sAddGuids.insert(pCreature->GetGUIDLow()); + break; + } +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; +void instance_scholomance::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_GATE_KIRTONOS: + case GO_GATE_RAS: + case GO_GATE_GANDLING: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; - uint64 m_uiGateKirtonosGUID; - uint64 m_uiGateGandlingGUID; - uint64 m_uiGateMiliciaGUID; - uint64 m_uiGateTheolenGUID; - uint64 m_uiGatePolkeltGUID; - uint64 m_uiGateRavenianGUID; - uint64 m_uiGateBarovGUID; - uint64 m_uiGateIlluciaGUID; + case GO_GATE_MALICIA: m_mGandlingData[EVENT_ID_MALICIA].m_doorGuid = pGo->GetObjectGuid(); break; + case GO_GATE_THEOLEN: m_mGandlingData[EVENT_ID_THEOLEN].m_doorGuid = pGo->GetObjectGuid(); break; + case GO_GATE_POLKELT: m_mGandlingData[EVENT_ID_POLKELT].m_doorGuid = pGo->GetObjectGuid(); break; + case GO_GATE_RAVENIAN: m_mGandlingData[EVENT_ID_RAVENIAN].m_doorGuid = pGo->GetObjectGuid(); break; + case GO_GATE_BAROV: m_mGandlingData[EVENT_ID_BAROV].m_doorGuid = pGo->GetObjectGuid(); break; + case GO_GATE_ILLUCIA: m_mGandlingData[EVENT_ID_ILLUCIA].m_doorGuid = pGo->GetObjectGuid(); break; - void Initialize() + case GO_VIEWING_ROOM_DOOR: + // In normal flow of the instance, this door is opened by a dropped key + if (m_auiEncounter[TYPE_RATTLEGORE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + } +} + +void instance_scholomance::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiGateKirtonosGUID = 0; - m_uiGateGandlingGUID = 0; - m_uiGateMiliciaGUID = 0; - m_uiGateTheolenGUID = 0; - m_uiGatePolkeltGUID = 0; - m_uiGateRavenianGUID = 0; - m_uiGateBarovGUID = 0; - m_uiGateIlluciaGUID = 0; + 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 + if (m_auiEncounter[uiType] != FAIL && uiData == IN_PROGRESS) + return; + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_GATE_KIRTONOS); + break; + case TYPE_RATTLEGORE: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_RAS_FROSTWHISPER: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_GATE_RAS); + break; + case TYPE_MALICIA: // TODO this code can be simplified, when it is known which event-ids correspond to which room + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(m_mGandlingData[EVENT_ID_MALICIA].m_doorGuid); + break; + case TYPE_THEOLEN: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(m_mGandlingData[EVENT_ID_THEOLEN].m_doorGuid); + break; + case TYPE_POLKELT: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(m_mGandlingData[EVENT_ID_POLKELT].m_doorGuid); + break; + case TYPE_RAVENIAN: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(m_mGandlingData[EVENT_ID_RAVENIAN].m_doorGuid); + break; + case TYPE_ALEXEI_BAROV: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(m_mGandlingData[EVENT_ID_BAROV].m_doorGuid); + break; + case TYPE_ILLUCIA_BAROV: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(m_mGandlingData[EVENT_ID_ILLUCIA].m_doorGuid); + break; + case TYPE_GANDLING: + m_auiEncounter[uiType] = uiData; + // Close the door to main room, because the encounter will take place only in the main hall and random around all the 6 rooms + DoUseDoorOrButton(GO_GATE_GANDLING); + break; } - void OnObjectCreate(GameObject* pGo) + // Summon Gandling + if (uiData == DONE) + DoSpawnGandlingIfCan(false); + + if (uiData == DONE) { - switch(pGo->GetEntry()) + 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +void instance_scholomance::DoSpawnGandlingIfCan(bool bByPlayerEnter) +{ + // Do not summon, if event finished + if (m_auiEncounter[TYPE_GANDLING] == DONE) + return; + + // Summon only once + if (GetSingleCreatureFromStorage(NPC_DARKMASTER_GANDLING)) + return; + + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + // 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) + { + 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)) { - case GO_GATE_KIRTONOS: m_uiGateKirtonosGUID = pGo->GetGUID(); break; - case GO_GATE_GANDLING: m_uiGateGandlingGUID = pGo->GetGUID(); break; - case GO_GATE_MALICIA: m_uiGateMiliciaGUID = pGo->GetGUID(); break; - case GO_GATE_THEOLEN: m_uiGateTheolenGUID = pGo->GetGUID(); break; - case GO_GATE_POLKELT: m_uiGatePolkeltGUID = pGo->GetGUID(); break; - case GO_GATE_RAVENIAN: m_uiGateRavenianGUID = pGo->GetGUID(); break; - case GO_GATE_BAROV: m_uiGateBarovGUID = pGo->GetGUID(); break; - case GO_GATE_ILLUCIA: m_uiGateIlluciaGUID = pGo->GetGUID(); break; + if (!bByPlayerEnter) + DoScriptText(SAY_GANDLING_SPAWN, pGandling); } } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_scholomance::HandlePortalEvent(uint32 uiEventId, uint32 uiData) +{ + GandlingEventMap::iterator find = m_mGandlingData.find(uiEventId); + if (find == m_mGandlingData.end()) + return; + + if (uiData == SPECIAL) { - switch(uiType) + // Set current Event index + m_uiGandlingEvent = uiEventId; + + // Close door if needed + if (!find->second.m_bIsActive) { - case TYPE_GANDLING: - m_auiEncounter[0] = uiData; - break; - case TYPE_KIRTONOS: - m_auiEncounter[1] = uiData; - break; - case TYPE_ALEXEIBAROV: - m_auiEncounter[2] = uiData; - break; - case TYPE_THEOLEN: - m_auiEncounter[3] = uiData; - break; - case TYPE_RAVENIAN: - m_auiEncounter[4] = uiData; - break; - case TYPE_POLKELT: - m_auiEncounter[5] = uiData; - break; - case TYPE_MALICIA: - m_auiEncounter[6] = uiData; - break; - case TYPE_ILLUCIABAROV: - m_auiEncounter[7] = uiData; - break; + find->second.m_bIsActive = true; + DoUseDoorOrButton(find->second.m_doorGuid); } } - - uint32 GetData(uint32 uiType) + // Toggle door and event state in case of state-switch + else { - if (uiType == TYPE_GANDLING) + if ((uiData == IN_PROGRESS && !find->second.m_bIsActive) || + (uiData == FAIL && find->second.m_bIsActive) || + (uiData == DONE && find->second.m_bIsActive)) { - if (m_auiEncounter[2] == DONE && m_auiEncounter[3] == DONE && m_auiEncounter[4] == DONE && - m_auiEncounter[5] == DONE && m_auiEncounter[6] == DONE && m_auiEncounter[7] == DONE) + find->second.m_bIsActive = !find->second.m_bIsActive; + DoUseDoorOrButton(find->second.m_doorGuid); + } + } +} + +uint32 instance_scholomance::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_scholomance::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] + >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8] >> m_auiEncounter[9]; + + 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_scholomance::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_KIRTONOS: SetData(TYPE_KIRTONOS, IN_PROGRESS); break; + case NPC_RATTLEGORE: SetData(TYPE_RATTLEGORE, IN_PROGRESS); break; + case NPC_RAS_FROSTWHISPER: SetData(TYPE_RAS_FROSTWHISPER, IN_PROGRESS); break; + case NPC_THEOLEN_KRASTINOV: SetData(TYPE_THEOLEN, IN_PROGRESS); break; + case NPC_LOREKEEPER_POLKELT: SetData(TYPE_POLKELT, IN_PROGRESS); break; + case NPC_RAVENIAN: SetData(TYPE_RAVENIAN, IN_PROGRESS); break; + case NPC_ILLUCIA_BAROV: SetData(TYPE_ILLUCIA_BAROV, IN_PROGRESS); break; + case NPC_ALEXEI_BAROV: SetData(TYPE_ALEXEI_BAROV, IN_PROGRESS); break; + case NPC_INSTRUCTOR_MALICIA: SetData(TYPE_MALICIA, IN_PROGRESS); break; + case NPC_DARKMASTER_GANDLING: SetData(TYPE_GANDLING, IN_PROGRESS); break; + + case NPC_BONE_MINION: + for (GandlingEventMap::iterator itr = m_mGandlingData.begin(); itr != m_mGandlingData.end(); ++itr) { - m_auiEncounter[0] = SPECIAL; - return SPECIAL; + // if there are no minions for a room, skip it + if (!itr->second.m_sAddGuids.empty()) + { + // set data to fail in case of player death + if (itr->second.m_sAddGuids.find(pCreature->GetGUIDLow()) != itr->second.m_sAddGuids.end()) + { + HandlePortalEvent(itr->first, IN_PROGRESS); + break; + } + } } - } + break; + } +} + +void instance_scholomance::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_KIRTONOS: SetData(TYPE_KIRTONOS, FAIL); break; + case NPC_RATTLEGORE: SetData(TYPE_RATTLEGORE, FAIL); break; + case NPC_RAS_FROSTWHISPER: SetData(TYPE_RAS_FROSTWHISPER, FAIL); break; + case NPC_THEOLEN_KRASTINOV: SetData(TYPE_THEOLEN, FAIL); break; + case NPC_LOREKEEPER_POLKELT: SetData(TYPE_POLKELT, FAIL); break; + case NPC_RAVENIAN: SetData(TYPE_RAVENIAN, FAIL); break; + case NPC_ILLUCIA_BAROV: SetData(TYPE_ILLUCIA_BAROV, FAIL); break; + case NPC_ALEXEI_BAROV: SetData(TYPE_ALEXEI_BAROV, FAIL); break; + case NPC_INSTRUCTOR_MALICIA: SetData(TYPE_MALICIA, FAIL); break; + case NPC_DARKMASTER_GANDLING: SetData(TYPE_GANDLING, FAIL); break; + + case NPC_BONE_MINION: + for (GandlingEventMap::iterator itr = m_mGandlingData.begin(); itr != m_mGandlingData.end(); ++itr) + { + // if there are no minions for a room, skip it + if (!itr->second.m_sAddGuids.empty()) + { + // set data to fail in case of player death + if (itr->second.m_sAddGuids.find(pCreature->GetGUIDLow()) != itr->second.m_sAddGuids.end()) + { + HandlePortalEvent(itr->first, FAIL); + break; + } + } + } + break; + } +} + +void instance_scholomance::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_KIRTONOS: SetData(TYPE_KIRTONOS, DONE); break; + case NPC_RATTLEGORE: SetData(TYPE_RATTLEGORE, DONE); break; + case NPC_RAS_FROSTWHISPER: SetData(TYPE_RAS_FROSTWHISPER, DONE); break; + case NPC_THEOLEN_KRASTINOV: SetData(TYPE_THEOLEN, DONE); break; + case NPC_LOREKEEPER_POLKELT: SetData(TYPE_POLKELT, DONE); break; + case NPC_RAVENIAN: SetData(TYPE_RAVENIAN, DONE); break; + case NPC_ILLUCIA_BAROV: SetData(TYPE_ILLUCIA_BAROV, DONE); break; + case NPC_ALEXEI_BAROV: SetData(TYPE_ALEXEI_BAROV, DONE); break; + case NPC_INSTRUCTOR_MALICIA: SetData(TYPE_MALICIA, DONE); break; + case NPC_DARKMASTER_GANDLING: SetData(TYPE_GANDLING, DONE); break; - return 0; + case NPC_BONE_MINION: + for (GandlingEventMap::iterator itr = m_mGandlingData.begin(); itr != m_mGandlingData.end(); ++itr) + { + // if there are no minions for a room, skip it + if (!itr->second.m_sAddGuids.empty()) + { + // search for the dead minion and erase it + if (itr->second.m_sAddGuids.find(pCreature->GetGUIDLow()) != itr->second.m_sAddGuids.end()) + { + itr->second.m_sAddGuids.erase(pCreature->GetGUIDLow()); + + // if the current list is empty; set event id as done + if (itr->second.m_sAddGuids.empty()) + { + HandlePortalEvent(itr->first, DONE); + break; + } + } + } + } + break; } -}; +} 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*/) +{ + if (pSource->GetTypeId() == TYPEID_UNIT) + { + if (instance_scholomance* pInstance = (instance_scholomance*)((Creature*)pSource)->GetInstanceData()) + { + // Check if we are handling an event associated with the room events of gandling + for (uint8 i = 0; i < MAX_EVENTS; ++i) + { + if (uiEventId == aGandlingEvents[i]) + { + // Set data in progress for the current event and store current event + pInstance->HandlePortalEvent(uiEventId, SPECIAL); + // return false, to allow the DB-scripts to summon some NPCSs + return false; + } + } + } + } + return false; +} + void AddSC_instance_scholomance() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_scholomance"; - newscript->GetInstanceData = &GetInstanceData_instance_scholomance; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_scholomance"; + pNewScript->GetInstanceData = &GetInstanceData_instance_scholomance; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_gandling_shadow_portal"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_gandling_shadow_portal; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/scholomance/scholomance.h b/scripts/eastern_kingdoms/scholomance/scholomance.h index 34e759bf5a..5319942a18 100644 --- a/scripts/eastern_kingdoms/scholomance/scholomance.h +++ b/scripts/eastern_kingdoms/scholomance/scholomance.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,25 +7,104 @@ enum { - MAX_ENCOUNTER = 8, + MAX_ENCOUNTER = 10, + MAX_EVENTS = 6, + + TYPE_KIRTONOS = 0, + TYPE_RATTLEGORE = 1, + TYPE_RAS_FROSTWHISPER = 2, + TYPE_MALICIA = 3, + TYPE_THEOLEN = 4, + TYPE_POLKELT = 5, + TYPE_RAVENIAN = 6, + TYPE_ALEXEI_BAROV = 7, + TYPE_ILLUCIA_BAROV = 8, + TYPE_GANDLING = 9, + + NPC_KIRTONOS = 10506, + NPC_RATTLEGORE = 11622, + NPC_RAS_FROSTWHISPER = 10508, + NPC_THEOLEN_KRASTINOV = 11261, + NPC_LOREKEEPER_POLKELT = 10901, + NPC_RAVENIAN = 10507, + NPC_ILLUCIA_BAROV = 10502, + NPC_ALEXEI_BAROV = 10504, + NPC_INSTRUCTOR_MALICIA = 10505, + NPC_DARKMASTER_GANDLING = 1853, + NPC_BONE_MINION = 16119, // summoned in random rooms by gandling GO_GATE_KIRTONOS = 175570, - GO_GATE_GANDLING = 177374, + GO_VIEWING_ROOM_DOOR = 175167, // Must be opened in reload case + GO_GATE_RAS = 177370, GO_GATE_MALICIA = 177375, GO_GATE_THEOLEN = 177377, GO_GATE_POLKELT = 177376, GO_GATE_RAVENIAN = 177372, GO_GATE_BAROV = 177373, GO_GATE_ILLUCIA = 177371, + GO_GATE_GANDLING = 177374, - TYPE_GANDLING = 1, - TYPE_THEOLEN = 2, - TYPE_MALICIA = 3, - TYPE_ILLUCIABAROV = 4, - TYPE_ALEXEIBAROV = 5, - TYPE_POLKELT = 6, - TYPE_RAVENIAN = 7, - TYPE_KIRTONOS = 8 + // Because the shadow portal teleport coordinates are guesswork (taken from old script) these IDs might be randomized + // TODO Syncronise with correct DB coordinates when they will be known + EVENT_ID_POLKELT = 5618, + EVENT_ID_THEOLEN = 5619, + EVENT_ID_MALICIA = 5620, + EVENT_ID_ILLUCIA = 5621, + EVENT_ID_BAROV = 5622, + EVENT_ID_RAVENIAN = 5623, + + SAY_GANDLING_SPAWN = -1289000, +}; + +static const EVENTLOCATION aGandlingSpawnLocs[1] = +{ + {180.771f, -5.4286f, 75.5702f, 1.29154f} +}; + +struct GandlingEventData +{ + GandlingEventData() : m_bIsActive(false) {} + bool m_bIsActive; + ObjectGuid m_doorGuid; + std::set m_sAddGuids; +}; + +static const uint32 aGandlingEvents[MAX_EVENTS] = {EVENT_ID_POLKELT, EVENT_ID_THEOLEN, EVENT_ID_MALICIA, EVENT_ID_ILLUCIA, EVENT_ID_BAROV, EVENT_ID_RAVENIAN}; + +typedef std::map GandlingEventMap; + +class MANGOS_DLL_DECL instance_scholomance : public ScriptedInstance +{ + public: + instance_scholomance(Map* pMap); + ~instance_scholomance() {} + + void Initialize() override; + + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + + 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) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + private: + void DoSpawnGandlingIfCan(bool bByPlayerEnter); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiGandlingEvent; + GandlingEventMap m_mGandlingData; }; #endif diff --git a/scripts/eastern_kingdoms/searing_gorge.cpp b/scripts/eastern_kingdoms/searing_gorge.cpp index 8e0c3aa147..abdc983b30 100644 --- a/scripts/eastern_kingdoms/searing_gorge.cpp +++ b/scripts/eastern_kingdoms/searing_gorge.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,143 +17,114 @@ /* ScriptData SDName: Searing_Gorge SD%Complete: 80 -SDComment: Quest support: 3377, 3441 (More accurate info on Kalaran needed). Lothos Riftwaker teleport to Molten Core. +SDComment: Quest support: 3367. SDCategory: Searing Gorge EndScriptData */ /* ContentData -npc_kalaran_windblade -npc_lothos_riftwaker -npc_zamael_lunthistle +npc_dorius_stonetender EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### -## npc_kalaran_windblade +## npc_dorius_stonetender ######*/ -bool GossipHello_npc_kalaran_windblade(Player* pPlayer, Creature* pCreature) +enum { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + SAY_DORIUS_AGGRO_1 = -1000993, + SAY_DORIUS_AGGRO_2 = -1000994, - if (pPlayer->GetQuestStatus(3441) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Tell me what drives this vengance?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + NPC_DARK_IRON_STEELSHIFTER = 8337, + MAX_STEELSHIFTERS = 4, - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + QUEST_ID_SUNTARA_STONES = 3367, +}; - return true; -} - -bool GossipSelect_npc_kalaran_windblade(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +struct MANGOS_DLL_DECL npc_dorius_stonetenderAI : public npc_escortAI { - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Continue please", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(1954, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Let me confer with my colleagues", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(1955, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(3441); - break; - } - return true; -} + npc_dorius_stonetenderAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } -/*###### -## npc_lothos_riftwaker -######*/ + void Reset() override { } -bool GossipHello_npc_lothos_riftwaker(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestRewardStatus(7487) || pPlayer->GetQuestRewardStatus(7848)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport me to the Molten Core", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + void Aggro(Unit* pWho) override + { + DoScriptText(urand(0, 1) ? SAY_DORIUS_AGGRO_1 : SAY_DORIUS_AGGRO_2, m_creature, pWho); + } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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); + } + } - return 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; + } + } -bool GossipSelect_npc_lothos_riftwaker(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + void JustSummoned(Creature* pSummoned) override { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->TeleportTo(409, 1096.0f, -467.0f, -104.6f, 3.64f); + if (pSummoned->GetEntry() == NPC_DARK_IRON_STEELSHIFTER) + pSummoned->AI()->AttackStart(m_creature); } - return true; -} + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; -/*###### -## npc_zamael_lunthistle -######*/ + DoMeleeAttackIfReady(); + } +}; -bool GossipHello_npc_zamael_lunthistle(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_dorius_stonetender(Creature* pCreature) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(3377) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(1920, pCreature->GetGUID()); - - return true; + return new npc_dorius_stonetenderAI(pCreature); } -bool GossipSelect_npc_zamael_lunthistle(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestAccept_npc_dorius_stonetender(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - switch(uiAction) + if (pQuest->GetQuestId() == QUEST_ID_SUNTARA_STONES) { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Please continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(1921, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Goodbye", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(1922, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(3377); - break; + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; } - return true; -} -/*###### -## -######*/ + return false; +} void AddSC_searing_gorge() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_kalaran_windblade"; - newscript->pGossipHello = &GossipHello_npc_kalaran_windblade; - newscript->pGossipSelect = &GossipSelect_npc_kalaran_windblade; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_lothos_riftwaker"; - newscript->pGossipHello = &GossipHello_npc_lothos_riftwaker; - newscript->pGossipSelect = &GossipSelect_npc_lothos_riftwaker; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_zamael_lunthistle"; - newscript->pGossipHello = &GossipHello_npc_zamael_lunthistle; - newscript->pGossipSelect = &GossipSelect_npc_zamael_lunthistle; - newscript->RegisterSelf(); + 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 new file mode 100644 index 0000000000..247ccc0cd5 --- /dev/null +++ b/scripts/eastern_kingdoms/shadowfang_keep/boss_hummel.cpp @@ -0,0 +1,273 @@ +/* Copyright (C) 2006 - 2013 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_hummel +SD%Complete: 50 +SDComment: The bosses are handled in eventAI; The event needs more research; only the basics are implemented; Check crazed apothecary timer +SDCategory: Shadowfang Keep +EndScriptData */ + +#include "precompiled.h" +#include "shadowfang_keep.h" + +enum +{ + SAY_INTRO_1 = -1033020, + SAY_INTRO_2 = -1033021, + SAY_INTRO_3 = -1033022, + SAY_CALL_BAXTER = -1033023, + SAY_CALL_FRYE = -1033024, + + SPELL_SUMMON_VALENTINE_ADD = 68610, // summons the crazy apothecary + + // It's unk who is handling the summoning of the crazed apothecary. This may get the following npcs involved: 36212 + NCP_CRAZED_APOTHECARY = 36568, // casts spell 68957 on range check + + QUEST_BEEN_SERVED = 14488, + + FACTION_HOSTILE = 14, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {QUEST_BEEN_SERVED, 0, 1000}, + {SAY_INTRO_1, NPC_HUMMEL, 4000}, + {SAY_INTRO_2, NPC_HUMMEL, 4000}, + {SAY_INTRO_3, NPC_HUMMEL, 3000}, + {NPC_HUMMEL, 0, 8000}, + {NPC_BAXTER, 0, 8000}, + {NPC_FRYE, 0, 0}, + {0, 0, 0}, +}; + +struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private DialogueHelper +{ + npc_valentine_boss_managerAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (instance_shadowfang_keep*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_shadowfang_keep* m_pInstance; + + uint32 m_uiCrazedApothecaryTimer; + + ObjectGuid m_EventStarterGuid; + + void Reset() + { + m_uiCrazedApothecaryTimer = 30000; + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case NPC_HUMMEL: + { + if (Creature* pHummel = m_pInstance->GetSingleCreatureFromStorage(NPC_HUMMEL)) + { + // WARNING: workaround -> faction should be set on event start + pHummel->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + pHummel->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_NON_ATTACKABLE); + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_EventStarterGuid)) + pHummel->AI()->AttackStart(pPlayer); + } + + m_pInstance->SetData(TYPE_APOTHECARY, IN_PROGRESS); + break; + } + case NPC_BAXTER: + { + Creature* pHummel = m_pInstance->GetSingleCreatureFromStorage(NPC_HUMMEL); + if (!pHummel) + return; + + if (Creature* pBaxter = m_pInstance->GetSingleCreatureFromStorage(NPC_BAXTER)) + { + DoScriptText(SAY_CALL_BAXTER, pHummel); + + // WARNING: workaround -> faction should be set on event start + pBaxter->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + pBaxter->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_NON_ATTACKABLE); + if (pHummel->getVictim()) + pBaxter->AI()->AttackStart(pHummel->getVictim()); + } + break; + } + case NPC_FRYE: + { + Creature* pHummel = m_pInstance->GetSingleCreatureFromStorage(NPC_HUMMEL); + if (!pHummel) + return; + + if (Creature* pFrye = m_pInstance->GetSingleCreatureFromStorage(NPC_FRYE)) + { + DoScriptText(SAY_CALL_FRYE, pHummel); + + // WARNING: workaround -> faction should be set on event start + pFrye->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + pFrye->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_NON_ATTACKABLE); + if (pHummel->getVictim()) + pFrye->AI()->AttackStart(pHummel->getVictim()); + } + break; + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NCP_CRAZED_APOTHECARY) + { + if (!m_pInstance) + return; + + // Make it attack a random Target + Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(NPC_HUMMEL); + if (!pBoss || !pBoss->isAlive()) + pBoss = m_pInstance->GetSingleCreatureFromStorage(NPC_BAXTER); + if (!pBoss || !pBoss->isAlive()) + pBoss = m_pInstance->GetSingleCreatureFromStorage(NPC_FRYE); + if (!pBoss || !pBoss->isAlive()) + return; + + // Attack a random target + if (Unit* pTarget = pBoss->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + // Wrapper to get the event started + void DoStartValentineEvent(ObjectGuid starterGuid) + { + if (!m_pInstance) + return; + + m_EventStarterGuid = starterGuid; + + if (Creature* pHummel = m_pInstance->GetSingleCreatureFromStorage(NPC_HUMMEL)) + { + // 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); + } + + StartNextDialogueText(QUEST_BEEN_SERVED); + + // Move Baxter to position + if (Creature* pBaxter = m_pInstance->GetSingleCreatureFromStorage(NPC_BAXTER)) + { + 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); + + if (GameObject* pVials = m_pInstance->GetSingleGameObjectFromStorage(GO_APOTHECARE_VIALS)) + { + float fX, fY, fZ; + pVials->GetContactPoint(pBaxter, fX, fY, fZ, CONTACT_DISTANCE); + pBaxter->SetWalk(false); + pBaxter->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + else + script_error_log("Gameobject %u couldn't be found or something really bad happened.", GO_APOTHECARE_VIALS); + } + + // Move Frye to position + if (Creature* pFrye = m_pInstance->GetSingleCreatureFromStorage(NPC_FRYE)) + { + 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); + + if (GameObject* pChemistry = m_pInstance->GetSingleGameObjectFromStorage(GO_CHEMISTRY_SET)) + { + float fX, fY, fZ; + pChemistry->GetContactPoint(pFrye, fX, fY, fZ, CONTACT_DISTANCE); + pFrye->SetWalk(false); + pFrye->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + else + script_error_log("Gameobject %u couldn't be found or something really bad happened.", GO_CHEMISTRY_SET); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_APOTHECARY) != IN_PROGRESS) + return; + + if (m_uiCrazedApothecaryTimer < uiDiff) + { + if (Creature* pGenerator = m_pInstance->GetSingleCreatureFromStorage(NPC_APOTHECARY_GENERATOR)) + pGenerator->CastSpell(pGenerator, SPELL_SUMMON_VALENTINE_ADD, true, NULL, NULL, m_creature->GetObjectGuid()); + + m_uiCrazedApothecaryTimer = 30000; + } + else + m_uiCrazedApothecaryTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_valentine_boss_manager(Creature* pCreature) +{ + return new npc_valentine_boss_managerAI(pCreature); +} + +bool QuestRewarded_npc_apothecary_hummel(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_BEEN_SERVED) + { + if (instance_shadowfang_keep* pInstance = (instance_shadowfang_keep*)pCreature->GetInstanceData()) + { + if (Creature* pValentineMgr = pInstance->GetSingleCreatureFromStorage(NPC_VALENTINE_BOSS_MGR)) + { + if (npc_valentine_boss_managerAI* pManagerAI = dynamic_cast(pValentineMgr->AI())) + pManagerAI->DoStartValentineEvent(pPlayer->GetObjectGuid()); + } + } + } + + return true; +} + +void AddSC_boss_hummel() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_valentine_boss_manager"; + pNewScript->GetAI = GetAI_npc_valentine_boss_manager; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_apothecary_hummel"; + pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_apothecary_hummel; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp b/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp index 440efa0b51..dd7da92b83 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,226 +24,226 @@ EndScriptData */ #include "precompiled.h" #include "shadowfang_keep.h" -enum +instance_shadowfang_keep::instance_shadowfang_keep(Map* pMap) : ScriptedInstance(pMap), + m_uiApothecaryDead(0) { - MAX_ENCOUNTER = 6, - - SAY_BOSS_DIE_AD = -1033007, - SAY_BOSS_DIE_AS = -1033008, - - NPC_ASH = 3850, - NPC_ADA = 3849, -// 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 - - 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 -}; + Initialize(); +} -struct MANGOS_DLL_DECL instance_shadowfang_keep : public ScriptedInstance +void instance_shadowfang_keep::Initialize() { - instance_shadowfang_keep(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiAshGUID; - uint64 m_uiAdaGUID; - - uint64 m_uiDoorCourtyardGUID; - uint64 m_uiDoorSorcererGUID; - uint64 m_uiDoorArugalGUID; - - uint64 m_uiFenrusGUID; - uint64 m_uiVincentGUID; - - uint64 m_uiArugalFocusGUID; + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_shadowfang_keep::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiAshGUID = 0; - m_uiAdaGUID = 0; - - m_uiDoorCourtyardGUID = 0; - m_uiDoorSorcererGUID = 0; - m_uiDoorArugalGUID = 0; - - m_uiFenrusGUID = 0; - m_uiVincentGUID = 0; - - m_uiArugalFocusGUID = 0; + case NPC_ASH: + case NPC_ADA: + case NPC_FENRUS: + case NPC_HUMMEL: + case NPC_FRYE: + case NPC_BAXTER: + case NPC_APOTHECARY_GENERATOR: + case NPC_VALENTINE_BOSS_MGR: + break; + case NPC_VINCENT: + // If Arugal has done the intro, make Vincent dead! + if (m_auiEncounter[4] == DONE) + pCreature->SetStandState(UNIT_STAND_STATE_DEAD); + break; + + default: + return; } + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); +} - void OnCreatureCreate(Creature* pCreature) +void instance_shadowfang_keep::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case NPC_ASH: m_uiAshGUID = pCreature->GetGUID(); break; - case NPC_ADA: m_uiAdaGUID = pCreature->GetGUID(); break; - case NPC_FENRUS: m_uiFenrusGUID = pCreature->GetGUID(); break; - case NPC_VINCENT: - m_uiVincentGUID = pCreature->GetGUID(); - //if Arugal has done the intro, make Vincent dead! - if (m_auiEncounter[4] == DONE) - pCreature->SetStandState(UNIT_STAND_STATE_DEAD); - break; - } + 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! + case GO_SORCERER_DOOR: + if (m_auiEncounter[2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ARUGAL_DOOR: + if (m_auiEncounter[3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ARUGAL_FOCUS: + case GO_APOTHECARE_VIALS: + case GO_CHEMISTRY_SET: + break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) +void instance_shadowfang_keep::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pGo->GetEntry()) - { - case GO_COURTYARD_DOOR: - m_uiDoorCourtyardGUID = pGo->GetGUID(); - 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! - case GO_SORCERER_DOOR: - m_uiDoorSorcererGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_ARUGAL_DOOR: - m_uiDoorArugalGUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_ARUGAL_FOCUS: - m_uiArugalFocusGUID = pGo->GetGUID(); - break; - } + // 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); + // no break; + case NPC_FRYE: + case NPC_BAXTER: + SetData(TYPE_APOTHECARY, SPECIAL); + break; } +} - void DoSpeech() +void instance_shadowfang_keep::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - Creature* pAda = instance->GetCreature(m_uiAdaGUID); - Creature* pAsh = instance->GetCreature(m_uiAshGUID); + case NPC_HUMMEL: + case NPC_FRYE: + case NPC_BAXTER: + SetData(TYPE_APOTHECARY, FAIL); + break; + } +} + +void instance_shadowfang_keep::DoSpeech() +{ + Creature* pAda = GetSingleCreatureFromStorage(NPC_ADA); + Creature* pAsh = GetSingleCreatureFromStorage(NPC_ASH); - if (pAda && pAda->isAlive() && pAsh && pAsh->isAlive()) - { - DoScriptText(SAY_BOSS_DIE_AD,pAda); - DoScriptText(SAY_BOSS_DIE_AS,pAsh); - } + if (pAda && pAda->isAlive() && pAsh && pAsh->isAlive()) + { + DoScriptText(SAY_BOSS_DIE_AD, pAda); + DoScriptText(SAY_BOSS_DIE_AS, pAsh); } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_shadowfang_keep::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(uiType) - { - case TYPE_FREE_NPC: - if (uiData == DONE) - DoUseDoorOrButton(m_uiDoorCourtyardGUID); - m_auiEncounter[0] = uiData; - break; - case TYPE_RETHILGORE: - if (uiData == DONE) - DoSpeech(); - m_auiEncounter[1] = uiData; - break; - case TYPE_FENRUS: - if (uiData == DONE) - if (Creature* pFenrus = instance->GetCreature(m_uiFenrusGUID)) - pFenrus->SummonCreature(NPC_ARCHMAGE_ARUGAL,-136.89f,2169.17f,136.58f,2.794f,TEMPSUMMON_TIMED_DESPAWN,30000); - m_auiEncounter[2] = uiData; - break; - case TYPE_NANDOS: - if (uiData == DONE) - DoUseDoorOrButton(m_uiDoorArugalGUID); - m_auiEncounter[3] = uiData; - break; - case TYPE_INTRO: - m_auiEncounter[4] = uiData; - break; - case TYPE_VOIDWALKER: - if (uiData == DONE) + case TYPE_FREE_NPC: + if (uiData == DONE) + DoUseDoorOrButton(GO_COURTYARD_DOOR); + m_auiEncounter[0] = uiData; + break; + case TYPE_RETHILGORE: + if (uiData == DONE) + DoSpeech(); + m_auiEncounter[1] = uiData; + break; + case TYPE_FENRUS: + if (uiData == DONE) + { + if (Creature* pFenrus = GetSingleCreatureFromStorage(NPC_FENRUS)) + pFenrus->SummonCreature(NPC_ARCHMAGE_ARUGAL, -136.89f, 2169.17f, 136.58f, 2.794f, TEMPSUMMON_TIMED_DESPAWN, 30000); + } + m_auiEncounter[2] = uiData; + break; + case TYPE_NANDOS: + if (uiData == DONE) + DoUseDoorOrButton(GO_ARUGAL_DOOR); + m_auiEncounter[3] = uiData; + break; + case TYPE_INTRO: + m_auiEncounter[4] = uiData; + break; + case TYPE_VOIDWALKER: + if (uiData == DONE) + { + m_auiEncounter[5]++; + if (m_auiEncounter[5] > 3) + DoUseDoorOrButton(GO_SORCERER_DOOR); + } + break; + case TYPE_APOTHECARY: + // Reset apothecary counter on fail + if (uiData == IN_PROGRESS) + m_uiApothecaryDead = 0; + if (uiData == SPECIAL) + { + ++m_uiApothecaryDead; + + // Set Hummel as lootable only when the others are dead + if (m_uiApothecaryDead == MAX_APOTHECARY) { - m_auiEncounter[5]++; - if (m_auiEncounter[5] > 3) - DoUseDoorOrButton(m_uiDoorSorcererGUID); - } - break; - } + if (Creature* pHummel = GetSingleCreatureFromStorage(NPC_HUMMEL)) + pHummel->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; + SetData(TYPE_APOTHECARY, DONE); + } + } + // We don't want to store the SPECIAL data + else + m_auiEncounter[6] = uiData; + break; + } - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] - << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; - strInstData = saveStream.str(); + 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]; - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } + m_strInstData = saveStream.str(); - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_FREE_NPC: - return m_auiEncounter[0]; - case TYPE_RETHILGORE: - return m_auiEncounter[1]; - case TYPE_FENRUS: - return m_auiEncounter[2]; - case TYPE_NANDOS: - return m_auiEncounter[3]; - case TYPE_INTRO: - return m_auiEncounter[4]; - } - return 0; + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint64 GetData64(uint32 uiType) +uint32 instance_shadowfang_keep::GetData(uint32 uiType) const +{ + switch (uiType) { - switch(uiType) - { - case DATA_LIGHTNING: - return m_uiArugalFocusGUID; - } - return 0; + case TYPE_FREE_NPC: return m_auiEncounter[0]; + case TYPE_RETHILGORE: return m_auiEncounter[1]; + case TYPE_FENRUS: return m_auiEncounter[2]; + case TYPE_NANDOS: return m_auiEncounter[3]; + case TYPE_INTRO: return m_auiEncounter[4]; + case TYPE_APOTHECARY: return m_auiEncounter[6]; + + default: + return 0; } +} - const char* Save() +void instance_shadowfang_keep::Load(const char* chrIn) +{ + if (!chrIn) { - return strInstData.c_str(); + OUT_LOAD_INST_DATA_FAIL; + return; } - void 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] >> m_auiEncounter[5]; + OUT_LOAD_INST_DATA(chrIn); - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + 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]; - OUT_LOAD_INST_DATA_COMPLETE; + 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_shadowfang_keep(Map* pMap) { @@ -252,9 +252,10 @@ InstanceData* GetInstanceData_instance_shadowfang_keep(Map* pMap) void AddSC_instance_shadowfang_keep() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_shadowfang_keep"; - newscript->GetInstanceData = &GetInstanceData_instance_shadowfang_keep; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_shadowfang_keep"; + pNewScript->GetInstanceData = &GetInstanceData_instance_shadowfang_keep; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp b/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp index 3300cb3252..8de60722ff 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -51,11 +51,9 @@ enum SPELL_UNLOCK = 6421, SPELL_FIRE = 6422, - NPC_ASH = 3850, - NPC_ADA = 3849 -}; -#define GOSSIP_ITEM_DOOR "Please unlock the courtyard door." + GOSSIP_ITEM_DOOR = -3033000 +}; struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI { @@ -69,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) @@ -122,9 +120,9 @@ struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI void Reset() {} - //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) + // 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) override { if (pWho) { @@ -146,15 +144,15 @@ 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(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->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } 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(); @@ -173,23 +171,22 @@ struct Waypoint float fX, fY, fZ; }; -//Cordinates for voidwalker spawns -static const Waypoint VWWaypoints[]= +// Cordinates for voidwalker spawns +static const Waypoint VWWaypoints[] = { - //fX fY fZ - {-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 @@ -203,31 +200,30 @@ enum struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI { - mob_arugal_voidwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_arugal_voidwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsLeader = false; - m_uiLeaderGUID = 0; m_uiCurrentPoint = 0; m_bReverse = false; } uint32 m_uiResetTimer, m_uiDarkOffering; - uint8 m_uiCurrentPoint, m_uiPosition; //0 - leader, 1 - behind-right, 2 - behind, 3 - behind-left - uint64 m_uiLeaderGUID; + uint8 m_uiCurrentPoint, m_uiPosition; // 0 - leader, 1 - behind-right, 2 - behind, 3 - behind-left + ObjectGuid m_leaderGuid; ScriptedInstance* m_pInstance; bool m_bIsLeader, m_bReverse, m_bWPDone; void Reset() { - m_creature->AddSplineFlag(SPLINEFLAG_WALKMODE); - m_uiDarkOffering = urand(4400,12500); + m_creature->SetWalk(true); + m_uiDarkOffering = urand(4400, 12500); m_bWPDone = true; - Creature* pLeader = m_creature->GetMap()->GetCreature(m_uiLeaderGUID); + 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 { @@ -235,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()) { @@ -253,14 +249,14 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI if (pNewLeader) { - m_uiLeaderGUID = pNewLeader->GetGUID(); + m_leaderGuid = pNewLeader->GetObjectGuid(); if (pNewLeader == m_creature) { m_bIsLeader = true; 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 { @@ -271,14 +267,12 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI } } - //this is the ACID script converted into C++ - //unfortunately, we can't have both AIs at the same time :( - 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; } @@ -287,7 +281,7 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI if (m_uiDarkOffering < uiDiff) { - m_uiDarkOffering = urand(4400,12500); + m_uiDarkOffering = urand(4400, 12500); if (Unit* pUnit = DoSelectLowestHpFriendly(10.0f, 290)) DoCastSpellIfCan(pUnit, SPELL_DARK_OFFERING); @@ -295,19 +289,19 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI else m_uiDarkOffering -= uiDiff; - //Check if we have a current target + // Check if we have a current target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; 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) @@ -329,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) @@ -342,8 +336,13 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI if (!uiPosition) m_bIsLeader = true; else - pLeader ? m_uiLeaderGUID = pLeader->GetGUID() : m_uiLeaderGUID = 0; - + { + if (pLeader) + m_leaderGuid = pLeader->GetObjectGuid(); + else + m_leaderGuid.Clear(); + } + Reset(); } @@ -356,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())) @@ -370,12 +369,12 @@ 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(); + m_creature->LoadCreatureAddon(true); m_creature->SetLootRecipient(NULL); @@ -409,9 +408,9 @@ enum enum ArugalPosition { - POSITION_SPAWN_LEDGE = 1, - POSITION_UPPER_LEDGE, - POSITION_STAIRS + POSITION_SPAWN_LEDGE = 0, + POSITION_UPPER_LEDGE = 1, + POSITION_STAIRS = 2 }; struct SpawnPoint @@ -419,23 +418,23 @@ struct SpawnPoint float fX, fY, fZ, fO; }; -//Cordinates for voidwalker spawns -static const SpawnPoint VWSpawns[]= +// Cordinates for voidwalker spawns +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 +// 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 { - boss_arugalAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_arugalAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); @@ -468,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) { @@ -489,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); @@ -502,7 +501,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI break; case 3: if (m_pInstance) - if (GameObject* pLightning = m_creature->GetMap()->GetGameObject(m_pInstance->GetData64(DATA_LIGHTNING))) + if (GameObject* pLightning = m_pInstance->GetSingleGameObjectFromStorage(GO_ARUGAL_FOCUS)) pLightning->Use(m_creature); m_uiSpeechTimer = 5000; @@ -512,13 +511,14 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI m_uiSpeechTimer = 500; break; case 5: - Creature *pVoidwalker, *pLeader; - pVoidwalker = pLeader = NULL; + { + Creature* pVoidwalker = NULL; + Creature* pLeader = NULL; - for(uint8 i = 0; i < 4; i++) + 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); + pVoidwalker = m_creature->SummonCreature(NPC_VOIDWALKER, VWSpawns[i].fX, + VWSpawns[i].fY, VWSpawns[i].fZ, VWSpawns[i].fO, TEMPSUMMON_DEAD_DESPAWN, 1); if (!pVoidwalker) continue; @@ -527,12 +527,13 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI pLeader = pVoidwalker; if (mob_arugal_voidwalkerAI* pVoidwalkerAI = dynamic_cast(pVoidwalker->AI())) - pVoidwalkerAI->SetPosition(i,pLeader); + pVoidwalkerAI->SetPosition(i, pLeader); pVoidwalker = NULL; } m_uiSpeechStep = 0; return; + } default: m_uiSpeechStep = 0; return; @@ -545,7 +546,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI return; } - //Check if we have a current target + // Check if we have a current target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -609,10 +610,10 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI ArugalPosition posNewPosition; if (m_posPosition == POSITION_SPAWN_LEDGE) - posNewPosition = (ArugalPosition)urand(2, 3); + posNewPosition = (ArugalPosition)urand(1, 2); else { - posNewPosition = (ArugalPosition)urand(1, 2); + posNewPosition = (ArugalPosition)urand(0, 1); if (m_posPosition == posNewPosition) posNewPosition = POSITION_STAIRS; @@ -621,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); @@ -659,14 +660,14 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI DoMeleeAttackIfReady(); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!m_bEventMode) ScriptedAI::AttackStart(pWho); } - //make the code nice and pleasing to the eye - inline float GetManaPercent() + // Make the code nice and pleasing to the eye + inline float GetManaPercent() { return (((float)m_creature->GetPower(POWER_MANA) / (float)m_creature->GetMaxPower(POWER_MANA)) * 100); } @@ -719,13 +720,11 @@ enum SAY_INTRO_4 = -1033012, SPELL_SPAWN = 7741, - - NPC_VINCENT = 4444 }; struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI { - npc_arugalAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_arugalAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -741,19 +740,19 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI m_uiSpeechStep = 0; m_creature->SetVisibility(VISIBILITY_OFF); - + if (m_pInstance && m_pInstance->GetData(TYPE_INTRO) == NOT_STARTED) 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,15 +763,15 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI m_uiSpeechTimer = 2000; break; case 3: - //make him die - if (Creature* pVincent = GetClosestCreatureWithEntry(m_creature,NPC_VINCENT,20.0f)) + // Make him die + if (Creature* pVincent = GetClosestCreatureWithEntry(m_creature, NPC_VINCENT, 20.0f)) pVincent->SetStandState(UNIT_STAND_STATE_DEAD); m_uiSpeechTimer = 10000; break; case 4: DoScriptText(SAY_INTRO_1, m_creature); - //m_creature->HandleEmote(EMOTE_ONESHOT_TALK); + // m_creature->HandleEmote(EMOTE_ONESHOT_TALK); m_uiSpeechTimer = 1750; break; case 5: @@ -788,7 +787,7 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI m_uiSpeechTimer = 1750; break; case 8: - //m_creature->HandleEmote(EMOTE_ONESHOT_TALK); + // m_creature->HandleEmote(EMOTE_ONESHOT_TALK); DoScriptText(SAY_INTRO_3, m_creature); m_uiSpeechTimer = 1750; break; @@ -806,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; @@ -821,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) @@ -842,7 +841,7 @@ enum struct MANGOS_DLL_DECL npc_deathstalker_vincentAI : public ScriptedAI { - npc_deathstalker_vincentAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_deathstalker_vincentAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -856,7 +855,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_vincentAI : public ScriptedAI m_creature->SetStandState(UNIT_STAND_STATE_DEAD); } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { if (pDoneBy) { @@ -870,29 +869,27 @@ 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(); - + ScriptedAI::UpdateAI(uiDiff); } - void EnterEvadeMode() + void EnterEvadeMode() override { m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); - m_creature->LoadCreatureAddon(); - + m_creature->LoadCreatureAddon(true); m_creature->SetLootRecipient(NULL); - Reset(); } }; @@ -904,32 +901,32 @@ CreatureAI* GetAI_npc_deathstalker_vincent(Creature* pCreature) void AddSC_shadowfang_keep() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_shadowfang_prisoner"; - newscript->pGossipHello = &GossipHello_npc_shadowfang_prisoner; - newscript->pGossipSelect = &GossipSelect_npc_shadowfang_prisoner; - newscript->GetAI = &GetAI_npc_shadowfang_prisoner; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_arugal_voidwalker"; - newscript->GetAI = &GetAI_mob_arugal_voidwalker; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_arugal"; - newscript->GetAI = &GetAI_npc_arugal; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_arugal"; - newscript->GetAI = &GetAI_boss_arugal; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_deathstalker_vincent"; - newscript->GetAI = &GetAI_npc_deathstalker_vincent; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_shadowfang_prisoner"; + pNewScript->pGossipHello = &GossipHello_npc_shadowfang_prisoner; + pNewScript->pGossipSelect = &GossipSelect_npc_shadowfang_prisoner; + pNewScript->GetAI = &GetAI_npc_shadowfang_prisoner; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_arugal_voidwalker"; + pNewScript->GetAI = &GetAI_mob_arugal_voidwalker; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_arugal"; + pNewScript->GetAI = &GetAI_npc_arugal; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_arugal"; + pNewScript->GetAI = &GetAI_boss_arugal; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_deathstalker_vincent"; + pNewScript->GetAI = &GetAI_npc_deathstalker_vincent; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h b/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h index ed8c45c6d3..e7af0fcfcb 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,13 +7,70 @@ enum { - TYPE_FREE_NPC = 1, - TYPE_RETHILGORE = 2, - TYPE_FENRUS = 3, - TYPE_NANDOS = 4, - TYPE_INTRO = 5, - TYPE_VOIDWALKER = 6, - DATA_LIGHTNING = 7 + MAX_ENCOUNTER = 7, + + TYPE_FREE_NPC = 1, + TYPE_RETHILGORE = 2, + TYPE_FENRUS = 3, + TYPE_NANDOS = 4, + TYPE_INTRO = 5, + TYPE_VOIDWALKER = 6, + TYPE_APOTHECARY = 7, + + SAY_BOSS_DIE_AD = -1033007, + SAY_BOSS_DIE_AS = -1033008, + + NPC_ASH = 3850, + NPC_ADA = 3849, + // 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_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 + + 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 + + SAY_HUMMEL_DEATH = -1033025, + + MAX_APOTHECARY = 3, +}; + +class MANGOS_DLL_DECL instance_shadowfang_keep : public ScriptedInstance +{ + public: + instance_shadowfang_keep(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void DoSpeech(); + + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(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; + + private: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint8 m_uiApothecaryDead; }; #endif diff --git a/scripts/eastern_kingdoms/silvermoon_city.cpp b/scripts/eastern_kingdoms/silvermoon_city.cpp index 03b2e3beeb..f25820400b 100644 --- a/scripts/eastern_kingdoms/silvermoon_city.cpp +++ b/scripts/eastern_kingdoms/silvermoon_city.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,81 +16,100 @@ /* 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 +Lor'themar Theron EndContentData */ #include "precompiled.h" /*####### -# npc_blood_knight_stillblade +# boss_lorthemar_theron #######*/ -#define SAY_HEAL -1000193 - -#define QUEST_REDEEMING_THE_DEAD 9685 -#define SPELL_SHIMMERING_VESSEL 31225 -#define SPELL_REVIVE_SELF 32343 +enum +{ + SPELL_ARCANE_SHOCK = 59715, + SPELL_CLEAVE_LORTHEMAR = 15284, + SPELL_MANA_BURN = 33385, + SPELL_MASS_CHARM = 33384, +}; -struct MANGOS_DLL_DECL npc_blood_knight_stillbladeAI : public ScriptedAI +struct MANGOS_DLL_DECL boss_lorthemar_theronAI : public ScriptedAI { - npc_blood_knight_stillbladeAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_lorthemar_theronAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 lifeTimer; - bool spellHit; + uint32 m_uiArcaneShockTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiManaBurnTimer; + uint32 m_uiMassCharmTimer; void Reset() { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - spellHit = false; + m_uiArcaneShockTimer = 9000; + m_uiCleaveTimer = 5000; + m_uiManaBurnTimer = 12000; + m_uiMassCharmTimer = 16000; } - void MoveInLineOfSight(Unit *who) { } - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (m_creature->IsStandState()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiArcaneShockTimer < uiDiff) { - if (lifeTimer < diff) - m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_ARCANE_SHOCK); + m_uiArcaneShockTimer = urand(9000, 11000); } - } + else + m_uiArcaneShockTimer -= uiDiff; - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - if ((Spellkind->Id == SPELL_SHIMMERING_VESSEL) && !spellHit && - (Hitter->GetTypeId() == TYPEID_PLAYER) && (((Player*)Hitter)->IsActiveQuest(QUEST_REDEEMING_THE_DEAD))) + if (m_uiCleaveTimer < uiDiff) { - ((Player*)Hitter)->AreaExploredOrEventHappens(QUEST_REDEEMING_THE_DEAD); - 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, Hitter); - spellHit = true; + DoCast(m_creature->getVictim(), SPELL_CLEAVE_LORTHEMAR); + m_uiCleaveTimer = urand(5000, 7000); } + else + m_uiCleaveTimer -= uiDiff; + + if (m_uiManaBurnTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_MANA_BURN); + m_uiManaBurnTimer = urand(12000, 15000); + } + else + m_uiManaBurnTimer -= uiDiff; + + if (m_uiMassCharmTimer < uiDiff) + { + DoCast(m_creature, SPELL_MASS_CHARM); + m_uiMassCharmTimer = urand(16000, 20000); + } + else + m_uiMassCharmTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_npc_blood_knight_stillblade(Creature* pCreature) +CreatureAI* GetAI_boss_lorthemar_theron(Creature* pCreature) { - return new npc_blood_knight_stillbladeAI(pCreature); + return new boss_lorthemar_theronAI(pCreature); } void AddSC_silvermoon_city() { - Script *newscript; - newscript = new Script; - newscript->Name = "npc_blood_knight_stillblade"; - newscript->GetAI = &GetAI_npc_blood_knight_stillblade; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lorthemar_theron"; + pNewScript->GetAI = &GetAI_boss_lorthemar_theron; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/silverpine_forest.cpp b/scripts/eastern_kingdoms/silverpine_forest.cpp index 39e8fb38af..f6880b3200 100644 --- a/scripts/eastern_kingdoms/silverpine_forest.cpp +++ b/scripts/eastern_kingdoms/silverpine_forest.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,12 +17,11 @@ /* ScriptData SDName: Silverpine_Forest SD%Complete: 100 -SDComment: Quest support: 435, 452, 1886 +SDComment: Quest support: 435, 452 SDCategory: Silverpine Forest EndScriptData */ /* ContentData -npc_astor_hadren npc_deathstalker_erland npc_deathstalker_faerleia EndContentData */ @@ -30,57 +29,6 @@ EndContentData */ #include "precompiled.h" #include "escort_ai.h" -/*###### -## npc_astor_hadren -######*/ - -struct MANGOS_DLL_DECL npc_astor_hadrenAI : public ScriptedAI -{ - npc_astor_hadrenAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - m_creature->setFaction(68); - } - - void JustDied(Unit *who) - { - m_creature->setFaction(68); - } -}; - -CreatureAI* GetAI_npc_astor_hadren(Creature *_creature) -{ - return new npc_astor_hadrenAI(_creature); -} - -bool GossipHello_npc_astor_hadren(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(1886) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "You're Astor Hadren, right?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - pPlayer->SEND_GOSSIP_MENU(623, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_astor_hadren(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "You've got something I need, Astor. And I'll be taking it now.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(624, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->setFaction(21); - pCreature->AI()->AttackStart(pPlayer); - break; - } - return true; -} - /*##### ## npc_deathstalker_erland #####*/ @@ -108,43 +56,16 @@ enum struct MANGOS_DLL_DECL npc_deathstalker_erlandAI : public npc_escortAI { - npc_deathstalker_erlandAI(Creature* pCreature) : npc_escortAI(pCreature) - { - uiRaneGUID = 0; - uiQuinnGUID = 0; - Reset(); - } - - uint64 uiRaneGUID; - uint64 uiQuinnGUID; - - void MoveInLineOfSight(Unit* pUnit) - { - if (HasEscortState(STATE_ESCORT_ESCORTING)) - { - if (!uiRaneGUID && pUnit->GetEntry() == NPC_RANE) - { - if (m_creature->IsWithinDistInMap(pUnit, 30.0f)) - uiRaneGUID = pUnit->GetGUID(); - } - if (!uiQuinnGUID && pUnit->GetEntry() == NPC_QUINN) - { - if (m_creature->IsWithinDistInMap(pUnit, 30.0f)) - uiQuinnGUID = pUnit->GetGUID(); - } - } + npc_deathstalker_erlandAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - 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: DoScriptText(SAY_START_2, m_creature, pPlayer); @@ -154,7 +75,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_erlandAI : public npc_escortAI pPlayer->GroupEventHappens(QUEST_ERLAND, m_creature); break; case 14: - if (Creature* pRane = m_creature->GetMap()->GetCreature(uiRaneGUID)) + if (Creature* pRane = GetClosestCreatureWithEntry(m_creature, NPC_RANE, 45.0f)) DoScriptText(SAY_RANE, pRane, m_creature); break; case 15: @@ -167,7 +88,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_erlandAI : public npc_escortAI DoScriptText(SAY_QUINN, m_creature); break; case 25: - if (Creature* pQuinn = m_creature->GetMap()->GetCreature(uiQuinnGUID)) + if (Creature* pQuinn = GetClosestCreatureWithEntry(m_creature, NPC_QUINN, 45.0f)) DoScriptText(SAY_QUINN_REPLY, pQuinn, m_creature); break; case 26: @@ -176,18 +97,11 @@ struct MANGOS_DLL_DECL npc_deathstalker_erlandAI : public npc_escortAI } } - void Reset() - { - if (!HasEscortState(STATE_ESCORT_ESCORTING)) - { - uiRaneGUID = 0; - uiQuinnGUID = 0; - } - } + void Reset() {} - 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; @@ -203,7 +117,7 @@ bool QuestAccept_npc_deathstalker_erland(Player* pPlayer, Creature* pCreature, c DoScriptText(SAY_START_1, pCreature); if (npc_deathstalker_erlandAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -252,32 +166,30 @@ 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 { - npc_deathstalker_faerleiaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_deathstalker_faerleiaAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() - { - } + void Reset() {} - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; uint32 m_uiWaveTimer; uint32 m_uiSummonCount; uint8 m_uiWaveCount; bool m_bEventStarted; - void StartEvent(uint64 uiPlayerGUID) + void StartEvent(Player* pPlayer) { m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - m_uiPlayerGUID = uiPlayerGUID; + m_playerGuid = pPlayer->GetObjectGuid(); m_bEventStarted = true; m_uiWaveTimer = 10000; m_uiSummonCount = 0; @@ -286,20 +198,20 @@ struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI void FinishEvent() { - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_bEventStarted = false; 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_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) pPlayer->SendQuestFailed(QUEST_PYREWOOD_AMBUSH); FinishEvent(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { ++m_uiSummonCount; @@ -309,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; @@ -322,7 +234,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI { DoScriptText(SAY_COMPLETED, m_creature); - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) pPlayer->GroupEventHappens(QUEST_PYREWOOD_AMBUSH, m_creature); FinishEvent(); @@ -330,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); @@ -380,7 +292,7 @@ bool QuestAccept_npc_deathstalker_faerleia(Player* pPlayer, Creature* pCreature, DoScriptText(SAY_START, pCreature, pPlayer); if (npc_deathstalker_faerleiaAI* pFaerleiaAI = dynamic_cast(pCreature->AI())) - pFaerleiaAI->StartEvent(pPlayer->GetGUID()); + pFaerleiaAI->StartEvent(pPlayer); } return true; } @@ -392,24 +304,17 @@ CreatureAI* GetAI_npc_deathstalker_faerleia(Creature* pCreature) void AddSC_silverpine_forest() { - Script* newscript; - - newscript = new Script; - newscript->Name = "npc_astor_hadren"; - newscript->pGossipHello = &GossipHello_npc_astor_hadren; - newscript->pGossipSelect = &GossipSelect_npc_astor_hadren; - newscript->GetAI = &GetAI_npc_astor_hadren; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_deathstalker_erland"; - newscript->GetAI = &GetAI_npc_deathstalker_erland; - newscript->pQuestAccept = &QuestAccept_npc_deathstalker_erland; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_deathstalker_faerleia"; - newscript->GetAI = &GetAI_npc_deathstalker_faerleia; - newscript->pQuestAccept = &QuestAccept_npc_deathstalker_faerleia; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_deathstalker_erland"; + pNewScript->GetAI = &GetAI_npc_deathstalker_erland; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_deathstalker_erland; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_deathstalker_faerleia"; + pNewScript->GetAI = &GetAI_npc_deathstalker_faerleia; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_deathstalker_faerleia; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/stormwind_city.cpp b/scripts/eastern_kingdoms/stormwind_city.cpp index c65a78d750..c72b181608 100644 --- a/scripts/eastern_kingdoms/stormwind_city.cpp +++ b/scripts/eastern_kingdoms/stormwind_city.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,48 +17,22 @@ /* ScriptData SDName: Stormwind_City SD%Complete: 100 -SDComment: Quest support: 1640, 1447, 4185, 11223 (DB support required for spell 42711) +SDComment: Quest support: 1640, 1447, 4185, 6402, 6403. SDCategory: Stormwind City EndScriptData */ /* ContentData -npc_archmage_malin npc_bartleby npc_dashel_stonefist npc_lady_katrana_prestor +King Varian +npc_squire_rowe +npc_reginald_windsor EndContentData */ #include "precompiled.h" - -/*###### -## npc_archmage_malin -######*/ - -#define GOSSIP_ITEM_MALIN "Can you send me to Theramore? I have an urgent message for Lady Jaina from Highlord Bolvar." - -bool GossipHello_npc_archmage_malin(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(11223) == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(11223)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MALIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_archmage_malin(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, 42711, true); - } - - return true; -} +#include "../world/world_map_scripts.h" +#include "escort_ai.h" /*###### ## npc_bartleby @@ -74,19 +48,12 @@ struct MANGOS_DLL_DECL 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; @@ -97,9 +64,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; @@ -115,7 +82,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; @@ -140,19 +107,12 @@ struct MANGOS_DLL_DECL npc_dashel_stonefistAI : public ScriptedAI { npc_dashel_stonefistAI(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; @@ -163,9 +123,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; @@ -181,7 +141,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; @@ -204,31 +164,31 @@ CreatureAI* GetAI_npc_dashel_stonefist(Creature* pCreature) bool GossipHello_npc_lady_katrana_prestor(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(4185) == QUEST_STATUS_INCOMPLETE) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(2693, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2693, pCreature->GetObjectGuid()); 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); - pPlayer->SEND_GOSSIP_MENU(2694, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2694, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+1: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(2695, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2695, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(2696, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(2696, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: pPlayer->CLOSE_GOSSIP_MENU(); @@ -238,31 +198,918 @@ bool GossipSelect_npc_lady_katrana_prestor(Player* pPlayer, Creature* pCreature, return true; } +/*###### +## King Varian +######*/ + +enum +{ + SPELL_HEROIC_LEAP = 59688, + SPELL_WHIRLWIND = 41056, + SPELL_WHIRLWIND_TRIG = 41057, +}; + +struct MANGOS_DLL_DECL boss_king_varian_wrynnAI : public ScriptedAI +{ + boss_king_varian_wrynnAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiHeroicLeapTimer; + uint32 m_uiWhirlwind; + + void Reset() + { + m_uiHeroicLeapTimer = 6000; + m_uiWhirlwind = 15000; + } + + void UpdateAI(const uint32 uiDiff) override + { + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiWhirlwind < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_WHIRLWIND); + m_uiWhirlwind = urand(15000, 18000); + } + else + m_uiWhirlwind -= uiDiff; + + if (m_uiHeroicLeapTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_HEROIC_LEAP); + m_uiHeroicLeapTimer = urand(6000, 9000); + } + else + m_uiHeroicLeapTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_king_varian_wrynn(Creature* pCreature) +{ + return new boss_king_varian_wrynnAI(pCreature); +} + + +/*###### +## 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 MANGOS_DLL_DECL 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, + + 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 MANGOS_DLL_DECL 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; + + 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; + } + + 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; + } + } +}; + +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 *newscript; - - newscript = new Script; - newscript->Name = "npc_archmage_malin"; - newscript->pGossipHello = &GossipHello_npc_archmage_malin; - newscript->pGossipSelect = &GossipSelect_npc_archmage_malin; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_bartleby"; - newscript->GetAI = &GetAI_npc_bartleby; - newscript->pQuestAccept = &QuestAccept_npc_bartleby; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_dashel_stonefist"; - newscript->GetAI = &GetAI_npc_dashel_stonefist; - newscript->pQuestAccept = &QuestAccept_npc_dashel_stonefist; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_lady_katrana_prestor"; - newscript->pGossipHello = &GossipHello_npc_lady_katrana_prestor; - newscript->pGossipSelect = &GossipSelect_npc_lady_katrana_prestor; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_bartleby"; + pNewScript->GetAI = &GetAI_npc_bartleby; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_bartleby; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dashel_stonefist"; + pNewScript->GetAI = &GetAI_npc_dashel_stonefist; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_dashel_stonefist; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_lady_katrana_prestor"; + pNewScript->pGossipHello = &GossipHello_npc_lady_katrana_prestor; + pNewScript->pGossipSelect = &GossipSelect_npc_lady_katrana_prestor; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_king_varian_wrynn"; + pNewScript->GetAI = &GetAI_boss_king_varian_wrynn; + 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 bcc31573b4..b18451edfc 100644 --- a/scripts/eastern_kingdoms/stranglethorn_vale.cpp +++ b/scripts/eastern_kingdoms/stranglethorn_vale.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,91 +17,222 @@ /* ScriptData SDName: Stranglethorn_Vale SD%Complete: 100 -SDComment: Quest support: 592 +SDComment: Quest support: 592, 8193 SDCategory: Stranglethorn Vale EndScriptData */ /* ContentData mob_yenniku +npc_riggle_bassbait EndContentData */ #include "precompiled.h" +#include "GameEventMgr.h" + +enum +{ + SAY_START = -1510356, + SAY_WINNER = -1510357, + SAY_END = -1510358, + QUEST_MASTER_ANGLER = 8193, +}; /*###### ## mob_yenniku ######*/ +enum +{ + SPELL_YENNIKUS_RELEASE = 3607, + + QUEST_ID_SAVING_YENNIKU = 592, + + FACTION_ID_HORDE_GENERIC = 83, // Note: faction may not be correct! +}; + struct MANGOS_DLL_DECL mob_yennikuAI : public ScriptedAI { - mob_yennikuAI(Creature *c) : ScriptedAI(c) + mob_yennikuAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiResetTimer; + + void Reset() override { m_uiResetTimer = 0; } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - bReset = false; - Reset(); + if (pSpell->Id == SPELL_YENNIKUS_RELEASE && pCaster->GetTypeId() == TYPEID_PLAYER) + { + if (!m_uiResetTimer && ((Player*)pCaster)->GetQuestStatus(QUEST_ID_SAVING_YENNIKU) == QUEST_STATUS_INCOMPLETE) + { + m_uiResetTimer = 60000; + EnterEvadeMode(); + } + } } - uint32 Reset_Timer; - bool bReset; - - void Reset() + void EnterEvadeMode() override { - Reset_Timer = 0; - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + if (m_uiResetTimer) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + m_creature->HandleEmote(EMOTE_STATE_STUN); + m_creature->SetFactionTemporary(FACTION_ID_HORDE_GENERIC, TEMPFACTION_RESTORE_REACH_HOME); + } + else + ScriptedAI::EnterEvadeMode(); } - void SpellHit(Unit *caster, const SpellEntry *spell) + void UpdateAI(const uint32 uiDiff) override { - if (caster->GetTypeId() == TYPEID_PLAYER) + if (m_uiResetTimer) { - //Yenniku's Release - if (!bReset && ((Player*)caster)->GetQuestStatus(592) == QUEST_STATUS_INCOMPLETE && spell->Id == 3607) + if (m_uiResetTimer <= uiDiff) { - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, 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_creature->HandleEmote(EMOTE_STATE_NONE); + m_uiResetTimer = 0; + EnterEvadeMode(); } + else + m_uiResetTimer -= uiDiff; } - return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_yenniku(Creature* _Creature) +{ + return new mob_yennikuAI(_Creature); +} + +/*###### +##npc_riggle_bassbait +######*/ +/** + * AI for Riggle Bassbait. + * This is the AI for Riggle Bassbait, see http://www.wowhead.com/?npc=15077 + * @see ScriptedAI + * @author burned, gotisch + */ +struct MANGOS_DLL_DECL npc_riggle_bassbaitAI : public ScriptedAI +{ + /** + * Constructor of the Creature. + * This is called when the creature is spawned. + * @param c The Creature that this AI is for + */ + npc_riggle_bassbaitAI(Creature *c) : ScriptedAI(c) + { + // This will keep the NPC active even if there are no players around! + c->SetActiveObjectState(true); + bEventAnnounced = bEventIsOver = bEventWinnerFound = false; + Reset(); } + /** + * Flag to check if event was announced. True if event was announced. + */ + bool bEventAnnounced; + /** + * Flag to check if event is over. True if event is over. + */ + bool bEventIsOver; + /** + * Flag to check if someone won the event. True if someone has won. + */ + bool bEventWinnerFound; + + void Reset() { } void Aggro(Unit *who) {} void UpdateAI(const uint32 diff) { - if (bReset) - if (Reset_Timer < diff) + // Announce the event max 1 minute after being spawned. But only if Fishing extravaganza is running. + if (!bEventAnnounced && time(NULL) % 60 == 0 && IsHolidayActive(HOLIDAY_FISHING_EXTRAVAGANZA)) { - EnterEvadeMode(); - bReset = false; - m_creature->setFaction(28); //troll, bloodscalp + debug_log("SD2: npc_riggle_bassbait announce HOLIDAY_FISHING_EXTRAVAGANZA contest"); + DoScriptText(SAY_START, m_creature); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); //Quest&Gossip are now active + bEventAnnounced = true; } - else Reset_Timer -= diff; - - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() ) + // The Event was started (announced) & It was not yet ended & One minute passed & the Fish are gone + if ( bEventAnnounced && !bEventIsOver && time(NULL) % 60 == 0 && !IsHolidayActive(HOLIDAY_FISHING_EXTRAVAGANZA)) + { + debug_log("SD2: npc_riggle_bassbait end HOLIDAY_FISHING_EXTRAVAGANZA contest"); + DoScriptText(SAY_END, m_creature); + bEventIsOver = true; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_mob_yenniku(Creature *_Creature) +/** + * GossipHello for NPC Riggle Bassbait. + * This is called each time a Player tries to talk with the NPC. + */ +bool GossipHello_npc_riggle_bassbait(Player* pPlayer, Creature* pCreature) { - return new mob_yennikuAI (_Creature); + if (pCreature->isQuestGiver()) // If the quest is still running. + { + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(7614, pCreature->GetObjectGuid()); + return true; + } + // The Quest is not there anymore + // There is a winner! + pPlayer->SEND_GOSSIP_MENU(7714, pCreature->GetObjectGuid()); + return true; } -/*###### -## -######*/ +bool ChooseReward_npc_riggle_bassbait(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + // TODO: check if this can only be called if NPC has QUESTGIVER flag. + if (pQuest->GetQuestId() == QUEST_MASTER_ANGLER && ((npc_riggle_bassbaitAI*)(pCreature->AI()))->bEventWinnerFound == false) + { + DoScriptText(SAY_WINNER, pCreature,pPlayer); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + ((npc_riggle_bassbaitAI*)(pCreature->AI()))->bEventWinnerFound = true; + Creature* creature2 = GetClosestCreatureWithEntry(pCreature,15087,60.0f); + if (creature2) + { + creature2->SetFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_QUESTGIVER); + } else { + debug_log("Could not change flag of Jang"); + } + return true; + } + return true; +} -void AddSC_stranglethorn_vale() +CreatureAI* GetAI_npc_riggle_bassbait(Creature* pCreature) { - Script *newscript; + return new npc_riggle_bassbaitAI(pCreature); +} - newscript = new Script; - newscript->Name = "mob_yenniku"; - newscript->GetAI = &GetAI_mob_yenniku; - newscript->RegisterSelf(); +void AddSC_stranglethorn_vale() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_yenniku"; + pNewScript->GetAI = &GetAI_mob_yenniku; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_riggle_bassbait"; + pNewScript->GetAI = &GetAI_npc_riggle_bassbait; + pNewScript->pGossipHello = &GossipHello_npc_riggle_bassbait; + pNewScript->pQuestRewardedNPC = &ChooseReward_npc_riggle_bassbait; + pNewScript->RegisterSelf(); } 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 9762e5dc42..0000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" - -#define SAY_0 "Intruders! More pawns of the Argent Dawn, no doubt. I already count one of their number among my prisoners. Withdraw from my domain before she is executed!" -#define SAY_1 "You're still here? Your foolishness is amusing! The Argent Dawn wench needn't suffer in vain. Leave at once and she shall be spared!" -#define SAY_2 "I shall take great pleasure in taking this poor wretch's life! It's not too late, she needn't suffer in vain. Turn back and her death shall be merciful!" -#define SAY_3 "May this prisoner's death serve as a warning. None shall defy the Scourge and live!" -#define SAY_4 "So you see fit to toy with the Lich King's creations? Ramstein, be sure to give the intruders a proper greeting." -#define SAY_5 "Time to take matters into my own hands. Come. Enter my domain and challenge the might of the Scourge!" - -#define ADD_1X 4017.403809f -#define ADD_1Y -3339.703369f -#define ADD_1Z 115.057655f -#define ADD_1O 5.487860f - -#define ADD_2X 4013.189209f -#define ADD_2Y -3351.808350f -#define ADD_2Z 115.052254f -#define ADD_2O 0.134280f - -#define ADD_3X 4017.738037f -#define ADD_3Y -3363.478016f -#define ADD_3Z 115.057274f -#define ADD_3O 0.723313f - -#define ADD_4X 4048.877197f -#define ADD_4Y -3363.223633f -#define ADD_4Z 115.054253f -#define ADD_4O 3.627735f - -#define ADD_5X 4051.777588f -#define ADD_5Y -3350.893311f -#define ADD_5Z 115.055351f -#define ADD_5O 3.066176f - -#define ADD_6X 4048.375977f -#define ADD_6Y -3339.966309f -#define ADD_6Z 115.055222f -#define ADD_6O 2.457497f - -#define SPELL_SHADOWBOLT 17393 -#define SPELL_CLEAVE 15284 -#define SPELL_MORTALSTRIKE 15708 - -#define SPELL_UNHOLY_AURA 17467 -#define SPELL_RAISEDEAD 17473 //triggers death pact (17471) - -#define SPELL_RAISE_DEAD1 17475 -#define SPELL_RAISE_DEAD2 17476 -#define SPELL_RAISE_DEAD3 17477 -#define SPELL_RAISE_DEAD4 17478 -#define SPELL_RAISE_DEAD5 17479 -#define SPELL_RAISE_DEAD6 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 ShadowBolt_Timer; - uint32 Cleave_Timer; - uint32 MortalStrike_Timer; - //uint32 RaiseDead_Timer; - uint32 SummonSkeletons_Timer; - Creature *Summoned; - - void Reset() - { - ShadowBolt_Timer = 5000; - Cleave_Timer = 8000; - MortalStrike_Timer = 12000; - //RaiseDead_Timer = 30000; - SummonSkeletons_Timer = 34000; - } - - void Aggro(Unit *who) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_BARON,IN_PROGRESS); - } - - void JustSummoned(Creature* summoned) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - summoned->AI()->AttackStart(target); - } - - void JustDied(Unit* Killer) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_BARON,DONE); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowBolt - if (ShadowBolt_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWBOLT); - ShadowBolt_Timer = 10000; - }else ShadowBolt_Timer -= diff; - - //Cleave - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = urand(7000, 17000); - }else Cleave_Timer -= diff; - - //MortalStrike - if (MortalStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = urand(10000, 25000); - }else MortalStrike_Timer -= diff; - - //RaiseDead - //if (RaiseDead_Timer < diff) - //{ - // DoCastSpellIfCan(m_creature,SPELL_RAISEDEAD); - // RaiseDead_Timer = 45000; - //}else RaiseDead_Timer -= diff; - - //SummonSkeletons - if (SummonSkeletons_Timer < diff) - { - m_creature->SummonCreature(11197,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,29000); - m_creature->SummonCreature(11197,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,29000); - m_creature->SummonCreature(11197,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,29000); - m_creature->SummonCreature(11197,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,29000); - m_creature->SummonCreature(11197,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,29000); - m_creature->SummonCreature(11197,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,29000); - - SummonSkeletons_Timer = 40000; - }else SummonSkeletons_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_baron_rivendare(Creature* pCreature) -{ - return new boss_baron_rivendareAI(pCreature); -} - -void AddSC_boss_baron_rivendare() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_baron_rivendare"; - newscript->GetAI = &GetAI_boss_baron_rivendare; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp b/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp index c0590a94b2..d24d7a6928 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,93 +16,151 @@ /* ScriptData SDName: Boss_Baroness_Anastari -SD%Complete: 90 -SDComment: MC disabled +SD%Complete: 100 +SDComment: SDCategory: Stratholme EndScriptData */ #include "precompiled.h" -#include "stratholme.h" -#define SPELL_BANSHEEWAIL 16565 -#define SPELL_BANSHEECURSE 16867 -#define SPELL_SILENCE 18327 -//#define SPELL_POSSESS 17244 +enum +{ + SPELL_BANSHEE_WAIL = 16565, + 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 { - boss_baroness_anastariAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + boss_baroness_anastariAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - ScriptedInstance* m_pInstance; + uint32 m_uiBansheeWailTimer; + uint32 m_uiBansheeCurseTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiPossessTimer; + uint32 m_uiPossessEndTimer; - uint32 BansheeWail_Timer; - uint32 BansheeCurse_Timer; - uint32 Silence_Timer; - //uint32 Possess_Timer; + ObjectGuid m_possessedPlayer; void Reset() { - BansheeWail_Timer = 1000; - BansheeCurse_Timer = 11000; - Silence_Timer = 13000; - //Possess_Timer = 35000; + m_uiBansheeWailTimer = 0; + m_uiBansheeCurseTimer = 10000; + m_uiSilenceTimer = 25000; + m_uiPossessTimer = 15000; + m_uiPossessEndTimer = 0; } - void JustDied(Unit* Killer) + void EnterEvadeMode() override { - if (m_pInstance) - m_pInstance->SetData(TYPE_BARONESS, DONE); + // If it's invisible don't evade + if (m_uiPossessEndTimer) + return; + + ScriptedAI::EnterEvadeMode(); } - void UpdateAI(const uint32 diff) + 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; - //BansheeWail - if (BansheeWail_Timer < diff) + // BansheeWail + if (m_uiBansheeWailTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BANSHEEWAIL); - BansheeWail_Timer = 4000; - }else BansheeWail_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BANSHEE_WAIL) == CAST_OK) + m_uiBansheeWailTimer = urand(2000, 3000); + } + } + else + m_uiBansheeWailTimer -= uiDiff; - //BansheeCurse - if (BansheeCurse_Timer < diff) + // BansheeCurse + if (m_uiBansheeCurseTimer < uiDiff) { - if (!urand(0, 3)) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BANSHEECURSE); - - BansheeCurse_Timer = 18000; - }else BansheeCurse_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_BANSHEE_CURSE) == CAST_OK) + m_uiBansheeCurseTimer = 20000; + } + else + m_uiBansheeCurseTimer -= uiDiff; - //Silence - if (Silence_Timer < diff) + // Silence + if (m_uiSilenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SILENCE); - Silence_Timer = 13000; - }else Silence_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = 25000; + } + } + else + m_uiSilenceTimer -= uiDiff; - //Possess - /* if (Possess_Timer < diff) - { - //Cast - if (rand()%100 < 65) + // Possess + if (m_uiPossessTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target)DoCastSpellIfCan(target,SPELL_POSSESS); + 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; + } + } } - Possess_Timer = 50000; - }else Possess_Timer -= diff; - */ + else + m_uiPossessTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_baroness_anastari(Creature* pCreature) { return new boss_baroness_anastariAI(pCreature); @@ -110,9 +168,10 @@ CreatureAI* GetAI_boss_baroness_anastari(Creature* pCreature) void AddSC_boss_baroness_anastari() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_baroness_anastari"; - newscript->GetAI = &GetAI_boss_baroness_anastari; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_baroness_anastari"; + pNewScript->GetAI = &GetAI_boss_baroness_anastari; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp b/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp index 6852a7d153..938c482624 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,183 +23,86 @@ EndScriptData */ #include "precompiled.h" -//front, left -#define ADD_1X 3553.851807f -#define ADD_1Y -2945.885986f -#define ADD_1Z 125.001015f -#define ADD_1O 0.592007f -//front, right -#define ADD_2X 3559.206299f -#define ADD_2Y -2952.929932f -#define ADD_2Z 125.001015f -#define ADD_2O 0.592007f -//mid, left -#define ADD_3X 3552.417480f -#define ADD_3Y -2948.667236f -#define ADD_3Z 125.001015f -#define ADD_3O 0.592007f -//mid, right -#define ADD_4X 3555.651855f -#define ADD_4Y -2953.519043f -#define ADD_4Z 125.001015f -#define ADD_4O 0.592007f -//back, left -#define ADD_5X 3547.927246f -#define ADD_5Y -2950.977295f -#define ADD_5Z 125.001015f -#define ADD_5O 0.592007f -//back, mid -#define ADD_6X 3553.094697f -#define ADD_6Y -2952.123291f -#define ADD_6Z 125.001015f -#define ADD_6O 0.592007f -//back, right -#define ADD_7X 3552.727539f -#define ADD_7Y -2957.776123f -#define ADD_7Z 125.001015f -#define ADD_7O 0.592007f -//behind, left -#define ADD_8X 3547.156250f -#define ADD_8Y -2953.162354f -#define ADD_8Z 125.001015f -#define ADD_8O 0.592007f -//behind, right -#define ADD_9X 3550.202148f -#define ADD_9Y -2957.437744f -#define ADD_9Z 125.001015f -#define ADD_9O 0.592007f - -#define SPELL_KNOCKAWAY 10101 -#define SPELL_PUMMEL 15615 -#define SPELL_SHOOT 20463 -//#define SPELL_SUMMONCRIMSONRIFLEMAN 17279 +enum +{ + SPELL_KNOCK_AWAY = 10101, + SPELL_PUMMEL = 15615, + SPELL_SHOOT = 16496, + SPELL_SUMMON_RIFLEMAN = 17279, // spell needs script target +}; struct MANGOS_DLL_DECL boss_cannon_master_willeyAI : public ScriptedAI { - boss_cannon_master_willeyAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_cannon_master_willeyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 KnockAway_Timer; - uint32 Pummel_Timer; - uint32 Shoot_Timer; - uint32 SummonRifleman_Timer; + uint32 m_uiKnockAwayTimer; + uint32 m_uiPummelTimer; + uint32 m_uiShootTimer; + uint32 m_uiSummonRiflemanTimer; void Reset() { - Shoot_Timer = 1000; - Pummel_Timer = 7000; - KnockAway_Timer = 11000; - SummonRifleman_Timer = 15000; + m_uiShootTimer = 1000; + m_uiPummelTimer = 7000; + m_uiKnockAwayTimer = 11000; + m_uiSummonRiflemanTimer = 15000; } - void JustDied(Unit* Victim) + void JustSummoned(Creature* pSummoned) override { - m_creature->SummonCreature(11054,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_7X,ADD_7Y,ADD_7Z,ADD_7O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_9X,ADD_9Y,ADD_9Z,ADD_9O,TEMPSUMMON_TIMED_DESPAWN,240000); + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - 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; - //Pummel - if (Pummel_Timer < diff) + // Pummel + if (m_uiPummelTimer < uiDiff) { - //Cast - if (rand()%100 < 90) //90% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_PUMMEL); - } - //12 seconds until we should cast this again - Pummel_Timer = 12000; - }else Pummel_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PUMMEL) == CAST_OK) + m_uiPummelTimer = 12000; + } + else + m_uiPummelTimer -= uiDiff; - //KnockAway - if (KnockAway_Timer < diff) + // KnockAway + if (m_uiKnockAwayTimer < uiDiff) { - //Cast - if (rand()%100 < 80) //80% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKAWAY); - } - //14 seconds until we should cast this again - KnockAway_Timer = 14000; - }else KnockAway_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KNOCK_AWAY) == CAST_OK) + m_uiKnockAwayTimer = 14000; + } + else + m_uiKnockAwayTimer -= uiDiff; - //Shoot - if (Shoot_Timer < diff) + // Shoot + if (m_uiShootTimer < uiDiff) { - //Cast - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHOOT); - //1 seconds until we should cast this again - Shoot_Timer = 1000; - }else Shoot_Timer -= diff; - - //SummonRifleman - if (SummonRifleman_Timer < diff) - { - //Cast - switch(urand(0, 8)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SHOOT, SELECT_FLAG_NOT_IN_MELEE_RANGE)) { - case 0: - m_creature->SummonCreature(11054,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 1: - m_creature->SummonCreature(11054,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 2: - m_creature->SummonCreature(11054,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 3: - m_creature->SummonCreature(11054,ADD_4X,ADD_4Y,ADD_4Z,ADD_4O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_7X,ADD_7Y,ADD_7Z,ADD_7O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 4: - m_creature->SummonCreature(11054,ADD_5X,ADD_5Y,ADD_5Z,ADD_5O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_8X,ADD_8Y,ADD_8Z,ADD_8O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 5: - m_creature->SummonCreature(11054,ADD_6X,ADD_6Y,ADD_6Z,ADD_6O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_7X,ADD_7Y,ADD_7Z,ADD_7O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_9X,ADD_9Y,ADD_9Z,ADD_9O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 6: - m_creature->SummonCreature(11054,ADD_7X,ADD_7Y,ADD_7Z,ADD_7O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_8X,ADD_8Y,ADD_8Z,ADD_8O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 7: - m_creature->SummonCreature(11054,ADD_8X,ADD_8Y,ADD_8Z,ADD_8O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_9X,ADD_9Y,ADD_9Z,ADD_9O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_2X,ADD_2Y,ADD_2Z,ADD_2O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; - case 8: - m_creature->SummonCreature(11054,ADD_9X,ADD_9Y,ADD_9Z,ADD_9O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,240000); - m_creature->SummonCreature(11054,ADD_3X,ADD_3Y,ADD_3Z,ADD_3O,TEMPSUMMON_TIMED_DESPAWN,240000); - break; + if (DoCastSpellIfCan(pTarget, SPELL_SHOOT) == CAST_OK) + m_uiShootTimer = urand(3000, 4000); } - //30 seconds until we should cast this again - SummonRifleman_Timer = 30000; - }else SummonRifleman_Timer -= diff; + } + else + m_uiShootTimer -= uiDiff; + + // SummonRifleman + if (m_uiSummonRiflemanTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_RIFLEMAN) == CAST_OK) + m_uiSummonRiflemanTimer = 30000; + } + else + m_uiSummonRiflemanTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_cannon_master_willey(Creature* pCreature) { return new boss_cannon_master_willeyAI(pCreature); @@ -207,9 +110,10 @@ CreatureAI* GetAI_boss_cannon_master_willey(Creature* pCreature) void AddSC_boss_cannon_master_willey() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_cannon_master_willey"; - newscript->GetAI = &GetAI_boss_cannon_master_willey; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_cannon_master_willey"; + pNewScript->GetAI = &GetAI_boss_cannon_master_willey; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp b/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp index a09c55da7b..e97bd73a31 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -25,15 +25,19 @@ EndScriptData */ enum { - //Dathrohan spells - SPELL_CRUSADERSHAMMER = 17286, //AOE stun + SAY_AGGRO = -1329016, + SAY_TRANSFORM = -1329017, + SAY_DEATH = -1329018, + + // 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, @@ -42,25 +46,31 @@ enum NPC_DATHROHAN = 10812, NPC_BALNAZZAR = 10813, - NPC_ZOMBIE = 10698 //probably incorrect + NPC_SKELETAL_GUARDIAN = 10390, + NPC_SKELETAL_BERSERKER = 10391 }; struct SummonDef { + uint32 m_uiEntry; float m_fX, m_fY, m_fZ, m_fOrient; }; -SummonDef m_aSummonPoint[]= +SummonDef m_aSummonPoint[] = { - {3444.156f, -3090.626f, 135.002f, 2.240f}, //G1 front, left - {3449.123f, -3087.009f, 135.002f, 2.240f}, //G1 front, right - {3446.246f, -3093.466f, 135.002f, 2.240f}, //G1 back left - {3451.160f, -3089.904f, 135.002f, 2.240f}, //G1 back, right - - {3457.995f, -3080.916f, 135.002f, 3.784f}, //G2 front, left - {3454.302f, -3076.330f, 135.002f, 3.784f}, //G2 front, right - {3460.975f, -3078.901f, 135.002f, 3.784f}, //G2 back left - {3457.338f, -3073.979f, 135.002f, 3.784f} //G2 back, right + {NPC_SKELETAL_BERSERKER, 3460.356f, -3070.572f, 135.086f, 0.332f}, + {NPC_SKELETAL_BERSERKER, 3465.289f, -3069.987f, 135.086f, 5.480f}, + {NPC_SKELETAL_BERSERKER, 3463.616f, -3074.912f, 135.086f, 5.009f}, + + {NPC_SKELETAL_GUARDIAN, 3460.012f, -3076.041f, 135.086f, 1.187f}, + {NPC_SKELETAL_GUARDIAN, 3467.909f, -3076.401f, 135.086f, 3.770f}, + + {NPC_SKELETAL_BERSERKER, 3509.269f, -3066.474f, 135.080f, 4.817f}, + {NPC_SKELETAL_BERSERKER, 3510.966f, -3069.011f, 135.080f, 3.491f}, + + {NPC_SKELETAL_GUARDIAN, 3516.042f, -3066.873f, 135.080f, 3.997f}, + {NPC_SKELETAL_GUARDIAN, 3513.561f, -3063.027f, 135.080f, 2.356f}, + {NPC_SKELETAL_GUARDIAN, 3518.825f, -3060.926f, 135.080f, 3.944f} }; struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI @@ -91,107 +101,120 @@ struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI if (m_creature->GetEntry() == NPC_BALNAZZAR) m_creature->UpdateEntry(NPC_DATHROHAN); + } + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* Victim) + void JustDied(Unit* /*Victim*/) override { - static uint32 uiCount = sizeof(m_aSummonPoint)/sizeof(SummonDef); + DoScriptText(SAY_DEATH, m_creature); - for (uint8 i=0; iSummonCreature(NPC_ZOMBIE, - 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); + 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); } - 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) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - //restore hp, mana and stun - DoCastSpellIfCan(m_creature,SPELL_BALNAZZARTRANSFORM); - m_creature->UpdateEntry(NPC_BALNAZZAR); - m_bTransformed = true; + // restore hp, mana and stun + if (DoCastSpellIfCan(m_creature, SPELL_BALNAZZARTRANSFORM) == CAST_OK) + { + m_creature->UpdateEntry(NPC_BALNAZZAR); + DoScriptText(SAY_TRANSFORM, m_creature); + m_bTransformed = true; + } } } 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(); @@ -205,9 +228,10 @@ CreatureAI* GetAI_boss_dathrohan_balnazzar(Creature* pCreature) void AddSC_boss_dathrohan_balnazzar() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_dathrohan_balnazzar"; - newscript->GetAI = &GetAI_boss_dathrohan_balnazzar; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_dathrohan_balnazzar"; + pNewScript->GetAI = &GetAI_boss_dathrohan_balnazzar; + pNewScript->RegisterSelf(); } 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 d121bd9dc1..0000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" -#include "stratholme.h" - -#define SPELL_DRAININGBLOW 16793 -#define SPELL_CROWDPUMMEL 10887 -#define SPELL_MIGHTYBLOW 14099 -#define SPELL_FURIOUS_ANGER 16791 - -#define MODEL_NORMAL 10433 -#define MODEL_HUMAN 3637 - -struct MANGOS_DLL_DECL boss_magistrate_barthilasAI : public ScriptedAI -{ - boss_magistrate_barthilasAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 DrainingBlow_Timer; - uint32 CrowdPummel_Timer; - uint32 MightyBlow_Timer; - uint32 FuriousAnger_Timer; - uint32 AngerCount; - - void Reset() - { - DrainingBlow_Timer = 20000; - CrowdPummel_Timer = 15000; - MightyBlow_Timer = 10000; - FuriousAnger_Timer = 5000; - AngerCount = 0; - - if (m_creature->isAlive()) - m_creature->SetDisplayId(MODEL_NORMAL); - else - m_creature->SetDisplayId(MODEL_HUMAN); - } - - void MoveInLineOfSight(Unit *who) - { - //nothing to see here yet - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustDied(Unit* Killer) - { - m_creature->SetDisplayId(MODEL_HUMAN); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (FuriousAnger_Timer < diff) - { - FuriousAnger_Timer = 4000; - if (AngerCount > 25) - return; - - ++AngerCount; - m_creature->CastSpell(m_creature,SPELL_FURIOUS_ANGER,false); - }else FuriousAnger_Timer -= diff; - - //DrainingBlow - if (DrainingBlow_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DRAININGBLOW); - DrainingBlow_Timer = 15000; - }else DrainingBlow_Timer -= diff; - - //CrowdPummel - if (CrowdPummel_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CROWDPUMMEL); - CrowdPummel_Timer = 15000; - }else CrowdPummel_Timer -= diff; - - //MightyBlow - if (MightyBlow_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MIGHTYBLOW); - MightyBlow_Timer = 20000; - }else MightyBlow_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_magistrate_barthilas(Creature* pCreature) -{ - return new boss_magistrate_barthilasAI(pCreature); -} - -void AddSC_boss_magistrate_barthilas() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_magistrate_barthilas"; - newscript->GetAI = &GetAI_boss_magistrate_barthilas; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp b/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp index 171a642869..11d19b5ab1 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,83 +16,95 @@ /* ScriptData SDName: Boss_Maleki_the_Pallid -SD%Complete: 70 +SD%Complete: 100 SDComment: SDCategory: Stratholme EndScriptData */ #include "precompiled.h" -#include "stratholme.h" -#define SPELL_FROSTBOLT 17503 -#define SPELL_DRAIN_LIFE 17238 -#define SPELL_DRAIN_MANA 17243 -#define SPELL_ICETOMB 16869 +enum +{ + SPELL_FROSTBOLT = 17503, + SPELL_DRAIN_LIFE = 17238, + SPELL_DRAIN_MANA = 17243, + SPELL_ICE_TOMB = 16869 +}; struct MANGOS_DLL_DECL boss_maleki_the_pallidAI : public ScriptedAI { - boss_maleki_the_pallidAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + boss_maleki_the_pallidAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - ScriptedInstance* m_pInstance; - - uint32 FrostNova_Timer; - uint32 Frostbolt_Timer; - uint32 IceTomb_Timer; - uint32 DrainLife_Timer; + uint32 m_uiDrainManaTimer; + uint32 m_uiFrostboltTimer; + uint32 m_uiIceTombTimer; + uint32 m_uiDrainLifeTimer; void Reset() { - FrostNova_Timer = 11000; - Frostbolt_Timer = 1000; - IceTomb_Timer = 16000; - DrainLife_Timer = 31000; - } - - void JustDied(Unit* Killer) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_PALLID, DONE); + m_uiDrainManaTimer = 30000; + m_uiFrostboltTimer = 0; + m_uiIceTombTimer = 15000; + m_uiDrainLifeTimer = 20000; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Frostbolt - if (Frostbolt_Timer < diff) + // Frostbolt + if (m_uiFrostboltTimer < uiDiff) { - if (rand()%100 < 90) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLT); - - Frostbolt_Timer = 3500; - }else Frostbolt_Timer -= diff; - - //IceTomb - if (IceTomb_Timer < diff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FROSTBOLT) == CAST_OK) + m_uiFrostboltTimer = urand(3000, 4000); + } + } + else + m_uiFrostboltTimer -= uiDiff; + + // IceTomb + if (m_uiIceTombTimer < uiDiff) { - if (rand()%100 < 65) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ICETOMB); - - IceTomb_Timer = 28000; - }else IceTomb_Timer -= diff; - - //DrainLife - if (DrainLife_Timer < diff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ICE_TOMB) == CAST_OK) + m_uiIceTombTimer = urand(15000, 20000); + } + } + else + m_uiIceTombTimer -= uiDiff; + + // Drain Life + if (m_uiDrainLifeTimer < uiDiff) { - if (rand()%100 < 55) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DRAIN_LIFE); - - DrainLife_Timer = 31000; - }else DrainLife_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DRAIN_LIFE) == CAST_OK) + m_uiDrainLifeTimer = urand(15000, 20000); + } + } + else + m_uiDrainLifeTimer -= uiDiff; + + // Drain mana + if (m_uiDrainManaTimer < uiDiff) + { + 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 = urand(20000, 30000); + } + } + else + m_uiDrainManaTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_maleki_the_pallid(Creature* pCreature) { return new boss_maleki_the_pallidAI(pCreature); @@ -100,9 +112,10 @@ CreatureAI* GetAI_boss_maleki_the_pallid(Creature* pCreature) void AddSC_boss_maleki_the_pallid() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_maleki_the_pallid"; - newscript->GetAI = &GetAI_boss_maleki_the_pallid; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_maleki_the_pallid"; + pNewScript->GetAI = &GetAI_boss_maleki_the_pallid; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp b/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp deleted file mode 100644 index 60a39e0a66..0000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (C) 2006 - 2010 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" -#include "stratholme.h" - -#define SPELL_ENCASINGWEBS 4962 -#define SPELL_PIERCEARMOR 6016 -#define SPELL_CRYPT_SCARABS 31602 -#define SPELL_RAISEUNDEADSCARAB 17235 - -struct MANGOS_DLL_DECL boss_nerubenkanAI : public ScriptedAI -{ - boss_nerubenkanAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 EncasingWebs_Timer; - uint32 PierceArmor_Timer; - uint32 CryptScarabs_Timer; - uint32 RaiseUndeadScarab_Timer; - - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - CryptScarabs_Timer = 3000; - EncasingWebs_Timer = 7000; - PierceArmor_Timer = 19000; - RaiseUndeadScarab_Timer = 3000; - } - - void RaiseUndeadScarab(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(10876, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 180000); - if (Summoned) - Summoned->AI()->AttackStart(victim); - } - - void JustDied(Unit* Killer) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_NERUB, DONE); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //EncasingWebs - if (EncasingWebs_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ENCASINGWEBS); - EncasingWebs_Timer = 30000; - }else EncasingWebs_Timer -= diff; - - //PierceArmor - if (PierceArmor_Timer < diff) - { - if (rand()%100 < 75) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_PIERCEARMOR); - - PierceArmor_Timer = 35000; - }else PierceArmor_Timer -= diff; - - //CryptScarabs - if (CryptScarabs_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CRYPT_SCARABS); - CryptScarabs_Timer = 16000; - }else CryptScarabs_Timer -= diff; - - //RaiseUndeadScarab - if (RaiseUndeadScarab_Timer < diff) - { - RaiseUndeadScarab(m_creature->getVictim()); - RaiseUndeadScarab_Timer = 18000; - }else RaiseUndeadScarab_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_nerubenkan(Creature* pCreature) -{ - return new boss_nerubenkanAI(pCreature); -} - -void AddSC_boss_nerubenkan() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_nerubenkan"; - newscript->GetAI = &GetAI_boss_nerubenkan; - newscript->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 b918560462..b1ac538738 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Silver_Hand_Bosses -SD%Complete: 40 -SDComment: Basic script to have support for Horde paladin epic mount (quest 9737). All 5 members of Order of the Silver Hand running this script (least for now) +SD%Complete: 80 +SDComment: Timers; Not sure if we need to respawn dead npcs on evade; May need additional adjustments / research SDCategory: Stratholme EndScriptData */ @@ -31,124 +31,151 @@ EndScriptData */ # Once Aurius is defeated, he should be the one summoning the ghosts. #####*/ -#define SH_GREGOR 17910 -#define SH_CATHELA 17911 -#define SH_NEMAS 17912 -#define SH_AELMAR 17913 -#define SH_VICAR 17914 -#define SH_QUEST_CREDIT 17915 +enum +{ + // Gregor + SPELL_HAMMER_JUSTICE = 13005, + SPELL_HAMMER_WRATH = 32772, + SPELL_HOLY_SHOCK = 32771, + // Cathela + SPELL_HOLY_SHIELD = 32777, + SPELL_REDOUBT = 32776, + // Aelmar + SPELL_JUDGEMENT = 32778, + // Vicar + SPELL_BLESSING = 32770, + SPELL_HOLY_LIGHT = 32769, + + TARGET_TYPE_RANDOM = 0, + TARGET_TYPE_VICTIM = 1, + TARGET_TYPE_SELF = 2, + TARGET_TYPE_FRIENDLY = 3, +}; -#define SPELL_HOLY_LIGHT 25263 -#define SPELL_DIVINE_SHIELD 13874 +struct SilverHandAbilityStruct +{ + uint32 m_uiCreatureEntry, m_uiSpellId; + uint8 m_uiTargetType; + uint32 m_uiInitialTimer, m_uiCooldown; +}; +static SilverHandAbilityStruct m_aSilverHandAbility[8] = +{ + {NPC_GREGOR_THE_JUSTICIAR, SPELL_HAMMER_JUSTICE, TARGET_TYPE_RANDOM, 2000, 15000}, + {NPC_GREGOR_THE_JUSTICIAR, SPELL_HAMMER_WRATH, TARGET_TYPE_RANDOM, 10000, 15000}, + {NPC_GREGOR_THE_JUSTICIAR, SPELL_HOLY_SHOCK, TARGET_TYPE_RANDOM, 4000, 7000}, + {NPC_CATHELA_THE_SEEKER, SPELL_HOLY_SHIELD, TARGET_TYPE_SELF, 1000, 60000}, + {NPC_CATHELA_THE_SEEKER, SPELL_REDOUBT, TARGET_TYPE_SELF, 5000, 15000}, + {NPC_AELMAR_THE_VANQUISHER, SPELL_JUDGEMENT, TARGET_TYPE_VICTIM, 4000, 9000}, + {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 { boss_silver_hand_bossesAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_stratholme*)pCreature->GetInstanceData(); + 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; + } Reset(); } - ScriptedInstance* m_pInstance; + instance_stratholme* m_pInstance; - uint32 HolyLight_Timer; - uint32 DivineShield_Timer; + UNORDERED_MAP m_mSpellTimers; void Reset() { - HolyLight_Timer = 20000; - DivineShield_Timer = 20000; + 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) override + { if (m_pInstance) { - switch(m_creature->GetEntry()) + // Set data to special when each paladin dies + m_pInstance->SetData(TYPE_TRUE_MASTERS, SPECIAL); + + // For the last one which dies, give the quest credit + if (m_pInstance->GetData(TYPE_TRUE_MASTERS) == DONE) { - case SH_AELMAR: - m_pInstance->SetData(TYPE_SH_AELMAR, 0); - break; - case SH_CATHELA: - m_pInstance->SetData(TYPE_SH_CATHELA, 0); - break; - case SH_GREGOR: - m_pInstance->SetData(TYPE_SH_GREGOR, 0); - break; - case SH_NEMAS: - m_pInstance->SetData(TYPE_SH_NEMAS, 0); - break; - case SH_VICAR: - m_pInstance->SetData(TYPE_SH_VICAR, 0); - break; + if (pKiller->GetTypeId() == TYPEID_PLAYER) + { + if (Creature* pCredit = m_pInstance->GetSingleCreatureFromStorage(NPC_PALADIN_QUEST_CREDIT)) + ((Player*)pKiller)->KilledMonsterCredit(NPC_PALADIN_QUEST_CREDIT, pCredit->GetObjectGuid()); + } } } } - void JustDied(Unit* Killer) + bool CanUseSpecialAbility(uint32 uiIndex) { - if (m_pInstance) + Unit* pTarget = NULL; + + switch (m_aSilverHandAbility[uiIndex].m_uiTargetType) { - switch(m_creature->GetEntry()) - { - case SH_AELMAR: - m_pInstance->SetData(TYPE_SH_AELMAR, 2); - break; - case SH_CATHELA: - m_pInstance->SetData(TYPE_SH_CATHELA, 2); - break; - case SH_GREGOR: - m_pInstance->SetData(TYPE_SH_GREGOR, 2); - break; - case SH_NEMAS: - m_pInstance->SetData(TYPE_SH_NEMAS, 2); - break; - case SH_VICAR: - m_pInstance->SetData(TYPE_SH_VICAR, 2); - break; - } - if (m_pInstance->GetData(TYPE_SH_QUEST) && Killer->GetTypeId() == TYPEID_PLAYER) - ((Player*)Killer)->KilledMonsterCredit(SH_QUEST_CREDIT,m_creature->GetGUID()); + 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, m_aSilverHandAbility[uiIndex].m_uiSpellId, SELECT_FLAG_IN_LOS); + break; + case TARGET_TYPE_FRIENDLY: + pTarget = DoSelectLowestHpFriendly(10.0f); + break; } + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, m_aSilverHandAbility[uiIndex].m_uiSpellId) == CAST_OK) + return true; + } + + return false; } - 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; - if (HolyLight_Timer < diff) + for (UNORDERED_MAP::iterator itr = m_mSpellTimers.begin(); itr != m_mSpellTimers.end(); ++itr) { - if (m_creature->GetHealthPercent() < 20.0f) + if (itr->second < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_HOLY_LIGHT); - HolyLight_Timer = 20000; - } - }else HolyLight_Timer -= diff; - - if (DivineShield_Timer < diff) - { - if (m_creature->GetHealthPercent() < 5.0f) - { - DoCastSpellIfCan(m_creature, SPELL_DIVINE_SHIELD); - DivineShield_Timer = 40000; + if (CanUseSpecialAbility(itr->first)) + { + itr->second = m_aSilverHandAbility[itr->first].m_uiCooldown; + break; + } } - }else DivineShield_Timer -= diff; + else + itr->second -= uiDiff; + } DoMeleeAttackIfReady(); } - }; + CreatureAI* GetAI_boss_silver_hand_bossesAI(Creature* pCreature) { return new boss_silver_hand_bossesAI(pCreature); } - void AddSC_boss_order_of_silver_hand() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_silver_hand_bosses"; - newscript->GetAI = &GetAI_boss_silver_hand_bossesAI; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_silver_hand_bosses"; + pNewScript->GetAI = &GetAI_boss_silver_hand_bossesAI; + pNewScript->RegisterSelf(); } 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 79364af44b..0000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_postmaster_malown"; - newscript->GetAI = &GetAI_boss_postmaster_malown; - newscript->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 450b70846c..0000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 - -#define C_MINDLESS_UNDEAD 11030 - -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 JustDied(Unit* Killer) - { - for(uint8 i = 0; i < 30; ++i) - m_creature->SummonCreature(C_MINDLESS_UNDEAD, 3969.35f, -3391.87f, 119.11f, 5.91f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,1800000); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RAMSTEIN,DONE); - } - - 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 *newscript; - newscript = new Script; - newscript->Name = "boss_ramstein_the_gorger"; - newscript->GetAI = &GetAI_boss_ramstein_the_gorger; - newscript->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 25e63df53c..0000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_timmy_the_cruel"; - newscript->GetAI = &GetAI_boss_timmy_the_cruel; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp b/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp index 60101f4e67..9a2cc16e04 100644 --- a/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp +++ b/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Instance_Stratholme -SD%Complete: 50 -SDComment: In progress. Undead side 80% implemented, wipe support for doors at slaughterhouse needed, event needs better implementation +SD%Complete: 70 +SDComment: Undead side 90% implemented, event needs better implementation, Barthildas relocation for reload case is missing, Baron Combat handling is buggy. SDCategory: Stratholme EndScriptData */ @@ -26,259 +26,366 @@ EndScriptData */ instance_stratholme::instance_stratholme(Map* pMap) : ScriptedInstance(pMap), m_uiBaronRunTimer(0), + m_uiBarthilasRunTimer(0), + m_uiMindlessSummonTimer(0), m_uiSlaugtherSquareTimer(0), - - m_uiServiceEntranceGUID(0), - m_uiGauntletGate1GUID(0), - m_uiPortGauntletGUID(0), - m_uiPortSlaugtherGUID(0), - m_uiPortElderGUID(0), - m_auiRamsteinDoorGUID(0), - m_auiRivendareDoorGUID(0), - - m_uiBaronGUID(0), - m_uiYsidaTriggerGUID(0), - - m_uiAcolyteAnnouncerGUID(0) + m_uiYellCounter(0), + m_uiMindlessCount(0), + m_uiPostboxesUsed(0), + m_uiSilverHandKilled(0) { Initialize(); } - void instance_stratholme::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_bIsSilverHandDead, false, sizeof(m_bIsSilverHandDead)); - memset(&m_auiZigguratGUID, 0, sizeof(m_auiZigguratGUID)); - memset(&m_auiCrystalSortedGUID, 0, sizeof(m_auiCrystalSortedGUID)); - - m_luiCrystalGUIDs.clear(); - m_sAbomnationGUID.clear(); - m_luiAcolyteGUIDs.clear(); } bool instance_stratholme::StartSlaugtherSquare() { - if (m_auiEncounter[1] == SPECIAL && m_auiEncounter[2] == SPECIAL && m_auiEncounter[3] == SPECIAL) + if (m_auiEncounter[TYPE_BARONESS] == SPECIAL && m_auiEncounter[TYPE_NERUB] == SPECIAL && m_auiEncounter[TYPE_PALLID] == SPECIAL) { - if (Creature* pBaron = instance->GetCreature(m_uiBaronGUID)) - DoScriptText(SAY_ANNOUNCE_RIVENDARE, pBaron); + DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RIVENDARE, NPC_BARON); + + DoUseDoorOrButton(GO_PORT_GAUNTLET); + DoUseDoorOrButton(GO_PORT_SLAUGTHER); + + debug_log("SD2: Instance Stratholme: Open slaugther square."); - DoUseDoorOrButton(m_uiPortGauntletGUID); - DoUseDoorOrButton(m_uiPortSlaugtherGUID); return true; } - debug_log("SD2: Instance Stratholme: Cannot open slaugther square yet."); return false; } void instance_stratholme::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - case NPC_BARON: m_uiBaronGUID = pCreature->GetGUID(); break; - case NPC_YSIDA_TRIGGER: m_uiYsidaTriggerGUID = pCreature->GetGUID(); break; - case NPC_CRYSTAL: m_luiCrystalGUIDs.push_back(pCreature->GetGUID()); break; + case NPC_BARON: + case NPC_YSIDA_TRIGGER: + case NPC_BARTHILAS: + case NPC_PALADIN_QUEST_CREDIT: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + case NPC_CRYSTAL: + m_luiCrystalGUIDs.push_back(pCreature->GetObjectGuid()); + break; case NPC_ABOM_BILE: - case NPC_ABOM_VENOM: m_sAbomnationGUID.insert(pCreature->GetGUID()); break; - case NPC_THUZADIN_ACOLYTE: m_luiAcolyteGUIDs.push_back(pCreature->GetGUID()); break; + case NPC_ABOM_VENOM: + m_sAbomnationGUID.insert(pCreature->GetObjectGuid()); + break; + case NPC_THUZADIN_ACOLYTE: + m_luiAcolyteGUIDs.push_back(pCreature->GetObjectGuid()); + break; + case NPC_CRIMSON_INITIATE: + case NPC_CRIMSON_GALLANT: + case NPC_CRIMSON_GUARDSMAN: + case NPC_CRIMSON_CONJURER: + // Only store those in the yard + if (pCreature->IsWithinDist2d(aTimmyLocation[1].m_fX, aTimmyLocation[1].m_fY, 40.0f)) + m_suiCrimsonLowGuids.insert(pCreature->GetGUIDLow()); + break; } } void instance_stratholme::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_SERVICE_ENTRANCE: - m_uiServiceEntranceGUID = pGo->GetGUID(); 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); - m_uiGauntletGate1GUID = pGo->GetGUID(); break; + case GO_ZIGGURAT_DOOR_1: - m_auiZigguratGUID[0] = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE || m_auiEncounter[1] == SPECIAL) + m_zigguratStorage[0].m_doorGuid = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_BARONESS] == DONE || m_auiEncounter[TYPE_BARONESS] == SPECIAL) pGo->SetGoState(GO_STATE_ACTIVE); - break; + return; case GO_ZIGGURAT_DOOR_2: - m_auiZigguratGUID[1] = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE || m_auiEncounter[2] == SPECIAL) + m_zigguratStorage[1].m_doorGuid = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_NERUB] == DONE || m_auiEncounter[TYPE_NERUB] == SPECIAL) pGo->SetGoState(GO_STATE_ACTIVE); - break; + return; case GO_ZIGGURAT_DOOR_3: - m_auiZigguratGUID[2] = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE || m_auiEncounter[3] == SPECIAL) + m_zigguratStorage[2].m_doorGuid = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_PALLID] == DONE || m_auiEncounter[TYPE_PALLID] == SPECIAL) pGo->SetGoState(GO_STATE_ACTIVE); - break; + return; + case GO_ZIGGURAT_DOOR_4: - m_auiRamsteinDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) + if (m_auiEncounter[TYPE_RAMSTEIN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ZIGGURAT_DOOR_5: - m_auiRivendareDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) + if (m_auiEncounter[TYPE_RAMSTEIN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PORT_GAUNTLET: - m_uiPortGauntletGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == SPECIAL && m_auiEncounter[2] == SPECIAL && m_auiEncounter[3] == SPECIAL) + if (m_auiEncounter[TYPE_BARONESS] == SPECIAL && m_auiEncounter[TYPE_NERUB] == SPECIAL && m_auiEncounter[TYPE_PALLID] == SPECIAL) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PORT_SLAUGTHER: - m_uiPortSlaugtherGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == SPECIAL && m_auiEncounter[2] == SPECIAL && m_auiEncounter[3] == SPECIAL) + if (m_auiEncounter[TYPE_BARONESS] == SPECIAL && m_auiEncounter[TYPE_NERUB] == SPECIAL && m_auiEncounter[TYPE_PALLID] == SPECIAL) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_PORT_SLAUGHTER_GATE: + if (m_auiEncounter[TYPE_RAMSTEIN] == DONE) // Might actually be uneeded pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PORT_ELDERS: - m_uiPortElderGUID = pGo->GetGUID(); + case GO_YSIDA_CAGE: break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } void instance_stratholme::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + // TODO: Remove the hard-coded indexes from array accessing + switch (uiType) { case TYPE_BARON_RUN: - switch(uiData) + switch (uiData) { case IN_PROGRESS: - if (m_auiEncounter[0] == IN_PROGRESS || m_auiEncounter[0] == FAIL) + if (m_auiEncounter[uiType] == IN_PROGRESS || m_auiEncounter[uiType] == FAIL) break; - m_uiBaronRunTimer = 45*MINUTE*IN_MILLISECONDS; + + DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_START, NPC_BARON); + + 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: - if (Creature* pYsidaT = instance->GetCreature(m_uiYsidaTriggerGUID)) - pYsidaT->SummonCreature(NPC_YSIDA, pYsidaT->GetPositionX(), pYsidaT->GetPositionY(), pYsidaT->GetPositionZ(), pYsidaT->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 1800000); - m_uiBaronRunTimer = 0; break; } - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_BARONESS: - m_auiEncounter[1] = uiData; - if (uiData == DONE) - { - DoSortZiggurats(); - DoUseDoorOrButton(m_auiZigguratGUID[0]); - } - if (uiData == SPECIAL) - StartSlaugtherSquare(); - break; case TYPE_NERUB: - m_auiEncounter[2] = uiData; - if (uiData == DONE) - { - DoSortZiggurats(); - DoUseDoorOrButton(m_auiZigguratGUID[1]); - } - if (uiData == SPECIAL) - StartSlaugtherSquare(); - break; case TYPE_PALLID: - m_auiEncounter[3] = uiData; + m_auiEncounter[uiType] = uiData; if (uiData == DONE) { DoSortZiggurats(); - DoUseDoorOrButton(m_auiZigguratGUID[2]); + DoUseDoorOrButton(m_zigguratStorage[uiType - TYPE_BARONESS].m_doorGuid); } if (uiData == SPECIAL) StartSlaugtherSquare(); break; case TYPE_RAMSTEIN: - if (uiData == IN_PROGRESS) + if (uiData == SPECIAL) { - if (m_auiEncounter[4] != IN_PROGRESS) - DoUseDoorOrButton(m_uiPortGauntletGUID); + if (m_auiEncounter[uiType] != SPECIAL && m_auiEncounter[uiType] != DONE) + { + m_uiSlaugtherSquareTimer = 20000; // TODO - unknown, also possible that this is not the very correct place.. + DoUseDoorOrButton(GO_PORT_GAUNTLET); + } uint32 uiCount = m_sAbomnationGUID.size(); - for(std::set::iterator i = m_sAbomnationGUID.begin(); i != m_sAbomnationGUID.end(); ++i) + for (GuidSet::iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end();) { - if (Creature* pAbom = instance->GetCreature(*i)) + if (Creature* pAbom = instance->GetCreature(*itr)) { + ++itr; if (!pAbom->isAlive()) --uiCount; } + else + { + // Remove obsolete guid from set and decrement count + m_sAbomnationGUID.erase(itr++); + --uiCount; + } } if (!uiCount) { - //a bit itchy, it should close the door after 10 secs, but it doesn't. skipping it for now. - // TODO - not working correctly! - //DoUseDoorOrButton(m_auiRamsteinDoorGUID, 10); + // Old Comment: a bit itchy, it should close GO_ZIGGURAT_DOOR_4 door after 10 secs, but it doesn't. skipping it for now. + // However looks like that this door is no more closed + DoUseDoorOrButton(GO_ZIGGURAT_DOOR_4); + + // No more handlng of Abomnations + m_uiSlaugtherSquareTimer = 0; - if (Creature* pBaron = instance->GetCreature(m_uiBaronGUID)) - pBaron->SummonCreature(NPC_RAMSTEIN, 4032.84f, -3390.24f, 119.73f, 4.71f, TEMPSUMMON_DEAD_DESPAWN, 0); + if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON)) + { + DoScriptText(SAY_ANNOUNCE_RAMSTEIN, pBaron); + if (Creature* pRamstein = pBaron->SummonCreature(NPC_RAMSTEIN, aStratholmeLocation[2].m_fX, aStratholmeLocation[2].m_fY, aStratholmeLocation[2].m_fZ, aStratholmeLocation[2].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + pRamstein->GetMotionMaster()->MovePoint(0, aStratholmeLocation[3].m_fX, aStratholmeLocation[3].m_fY, aStratholmeLocation[3].m_fZ); - debug_log("SD2: Instance Stratholme: Ramstein spawned."); + debug_log("SD2: Instance Stratholme - Slaugther event: Ramstein spawned."); + } } else - debug_log("SD2: Instance Stratholme: %u Abomnation left to kill.", uiCount); + debug_log("SD2: Instance Stratholme - Slaugther event: %u Abomnation left to kill.", uiCount); } + // After fail aggroing Ramstein means wipe on Ramstein, so close door again + if (uiData == IN_PROGRESS && m_auiEncounter[uiType] == FAIL) + DoUseDoorOrButton(GO_PORT_GAUNTLET); if (uiData == DONE) { - m_uiSlaugtherSquareTimer = 5*MINUTE*IN_MILLISECONDS; - debug_log("SD2: Instance Stratholme: Slaugther event will continue in 5 minutes."); + // Open side gate and start summoning skeletons + DoUseDoorOrButton(GO_PORT_SLAUGHTER_GATE); + // use this timer as a bool just to start summoning + m_uiMindlessSummonTimer = 500; + m_uiMindlessCount = 0; + m_luiUndeadGUIDs.clear(); + + // Summon 5 guards + if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON)) + { + 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); + if (Creature* pTemp = pBaron->SummonCreature(NPC_BLACK_GUARD, aStratholmeLocation[6].m_fX, aStratholmeLocation[6].m_fY, aStratholmeLocation[6].m_fZ, aStratholmeLocation[6].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + m_luiGuardGUIDs.push_back(pTemp->GetObjectGuid()); + } + + debug_log("SD2: Instance Stratholme - Slaugther event: Summoned 5 guards."); + } } - m_auiEncounter[4] = uiData; + // Open Door again and stop Abomnation + if (uiData == FAIL && m_auiEncounter[uiType] != FAIL) + { + DoUseDoorOrButton(GO_PORT_GAUNTLET); + m_uiSlaugtherSquareTimer = 0; + + // Let already moving Abomnations stop + 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) + pAbom->GetMotionMaster()->MovementExpired(); + } + } + + m_auiEncounter[uiType] = uiData; break; case TYPE_BARON: if (uiData == IN_PROGRESS) { - if (GetData(TYPE_BARON_RUN) == IN_PROGRESS) + // Reached the Baron within time-limit + if (m_auiEncounter[TYPE_BARON_RUN] == IN_PROGRESS) + SetData(TYPE_BARON_RUN, DONE); + + // Close Slaughterhouse door if needed + if (m_auiEncounter[uiType] == FAIL) + DoUseDoorOrButton(GO_PORT_GAUNTLET); + } + if (uiData == DONE) + { + if (m_auiEncounter[TYPE_BARON_RUN] == DONE) { Map::PlayerList const& players = instance->GetPlayers(); - 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()) { - if (Player* pPlayer = itr->getSource()) - { - if (pPlayer->HasAura(SPELL_BARON_ULTIMATUM)) - pPlayer->RemoveAurasDueToSpell(SPELL_BARON_ULTIMATUM); - - if (pPlayer->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(QUEST_DEAD_MAN_PLEA); - } + if (pPlayer->HasAura(SPELL_BARON_ULTIMATUM)) + pPlayer->RemoveAurasDueToSpell(SPELL_BARON_ULTIMATUM); + + if (pPlayer->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE) + pPlayer->AreaExploredOrEventHappens(QUEST_DEAD_MAN_PLEA); } } - SetData(TYPE_BARON_RUN,DONE); + // Open cage and finish rescue event + if (Creature* pYsidaT = GetSingleCreatureFromStorage(NPC_YSIDA_TRIGGER)) + { + if (Creature* pYsida = pYsidaT->SummonCreature(NPC_YSIDA, pYsidaT->GetPositionX(), pYsidaT->GetPositionY(), pYsidaT->GetPositionZ(), pYsidaT->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 1800000)) + { + DoScriptText(SAY_EPILOGUE, pYsida); + pYsida->GetMotionMaster()->MovePoint(0, aStratholmeLocation[7].m_fX, aStratholmeLocation[7].m_fY, aStratholmeLocation[7].m_fZ); + } + DoUseDoorOrButton(GO_YSIDA_CAGE); + } } + + // Open Slaughterhouse door again + DoUseDoorOrButton(GO_PORT_GAUNTLET); } - if (uiData == DONE) - // Open a few doors again // TODO: needs research, how to handle wipes in this area! - DoUseDoorOrButton(m_uiPortGauntletGUID); + if (uiData == FAIL) + DoUseDoorOrButton(GO_PORT_GAUNTLET); - m_auiEncounter[5] = uiData; + m_auiEncounter[uiType] = uiData; break; + case TYPE_BARTHILAS_RUN: + if (uiData == IN_PROGRESS) + { + Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS); + if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat()) + { + DoScriptText(SAY_WARN_BARON, pBarthilas); + pBarthilas->SetWalk(false); + pBarthilas->GetMotionMaster()->MovePoint(0, aStratholmeLocation[0].m_fX, aStratholmeLocation[0].m_fY, aStratholmeLocation[0].m_fZ); - case TYPE_SH_AELMAR: - m_bIsSilverHandDead[0] = (uiData) ? true : false; - break; - case TYPE_SH_CATHELA: - m_bIsSilverHandDead[1] = (uiData) ? true : false; - break; - case TYPE_SH_GREGOR: - m_bIsSilverHandDead[2] = (uiData) ? true : false; - break; - case TYPE_SH_NEMAS: - m_bIsSilverHandDead[3] = (uiData) ? true : false; - break; - case TYPE_SH_VICAR: - m_bIsSilverHandDead[4] = (uiData) ? true : false; + m_uiBarthilasRunTimer = 8000; + } + } + m_auiEncounter[uiType] = uiData; break; + case TYPE_BLACK_GUARDS: + // Prevent double action + if (m_auiEncounter[uiType] == uiData) + return; + + // Restart after failure, close Gauntlet + if (uiData == IN_PROGRESS && m_auiEncounter[uiType] == FAIL) + DoUseDoorOrButton(GO_PORT_GAUNTLET); + // Wipe case - open gauntlet + if (uiData == FAIL) + DoUseDoorOrButton(GO_PORT_GAUNTLET); + if (uiData == DONE) + { + if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON)) + DoScriptText(SAY_UNDEAD_DEFEAT, pBaron); + DoUseDoorOrButton(GO_ZIGGURAT_DOOR_5); + } + m_auiEncounter[uiType] = uiData; + + // No need to save anything here, so return + return; + case TYPE_POSTMASTER: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + { + ++m_uiPostboxesUsed; + + // After the second post box prepare to spawn the Post Master + if (m_uiPostboxesUsed == 2) + SetData(TYPE_POSTMASTER, SPECIAL); + } + // No need to save anything here, so return + return; + case TYPE_TRUE_MASTERS: + m_auiEncounter[uiType] = uiData; + if (uiData == SPECIAL) + { + ++m_uiSilverHandKilled; + + // When the 5th paladin is killed set data to DONE in order to give the quest credit for the last paladin + if (m_uiSilverHandKilled == MAX_SILVERHAND) + SetData(TYPE_TRUE_MASTERS, DONE); + } + // No need to save anything here, so return + return; } if (uiData == DONE) @@ -287,9 +394,9 @@ 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[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -308,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[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { @@ -317,49 +424,30 @@ void instance_stratholme::Load(const char* chrIn) } // Special Treatment for the Ziggurat-Bosses, as otherwise the event couldn't reload - if (m_auiEncounter[1] == DONE) - m_auiEncounter[1] = SPECIAL; - if (m_auiEncounter[2] == DONE) - m_auiEncounter[2] = SPECIAL; - if (m_auiEncounter[3] == DONE) - m_auiEncounter[3] = SPECIAL; + if (m_auiEncounter[TYPE_BARONESS] == DONE) + m_auiEncounter[TYPE_BARONESS] = SPECIAL; + if (m_auiEncounter[TYPE_NERUB] == DONE) + m_auiEncounter[TYPE_NERUB] = SPECIAL; + if (m_auiEncounter[TYPE_PALLID] == DONE) + m_auiEncounter[TYPE_PALLID] = SPECIAL; OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_stratholme::GetData(uint32 uiType) +uint32 instance_stratholme::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { - case TYPE_SH_QUEST: - if (m_bIsSilverHandDead[0] && m_bIsSilverHandDead[1] && m_bIsSilverHandDead[2] && m_bIsSilverHandDead[3] && m_bIsSilverHandDead[4]) - return 1; - return 0; case TYPE_BARON_RUN: - return m_auiEncounter[0]; case TYPE_BARONESS: - return m_auiEncounter[1]; case TYPE_NERUB: - return m_auiEncounter[2]; case TYPE_PALLID: - return m_auiEncounter[3]; case TYPE_RAMSTEIN: - return m_auiEncounter[4]; case TYPE_BARON: - return m_auiEncounter[5]; - default: - return 0; - } -} - -uint64 instance_stratholme::GetData64(uint32 uiData) -{ - switch(uiData) - { - case NPC_BARON: - return m_uiBaronGUID; - case NPC_YSIDA_TRIGGER: - return m_uiYsidaTriggerGUID; + case TYPE_BARTHILAS_RUN: + case TYPE_POSTMASTER: + case TYPE_TRUE_MASTERS: + return m_auiEncounter[uiType]; default: return 0; } @@ -376,7 +464,7 @@ void instance_stratholme::DoSortZiggurats() return; std::list lAcolytes; // Valid pointers, only used locally - for (std::list::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); @@ -386,25 +474,25 @@ void instance_stratholme::DoSortZiggurats() if (lAcolytes.empty()) return; - if (!m_uiAcolyteAnnouncerGUID) + if (!GetSingleCreatureFromStorage(NPC_THUZADIN_ACOLYTE, true)) { // Sort the acolytes by height, and the one with the biggest height is the announcer (a bit outside the map) lAcolytes.sort(sortByHeight); - m_uiAcolyteAnnouncerGUID = (*lAcolytes.begin())->GetGUID(); + m_mNpcEntryGuidStore[NPC_THUZADIN_ACOLYTE] = (*lAcolytes.begin())->GetObjectGuid(); lAcolytes.erase(lAcolytes.begin()); } // 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) { - if (GameObject* pZigguratDoor = instance->GetGameObject(m_auiZigguratGUID[i])) + if (GameObject* pZigguratDoor = instance->GetGameObject(m_zigguratStorage[i].m_doorGuid)) { - if ((*itr)->isAlive() && (*itr)->IsWithinDistInMap(pZigguratDoor, 30.0f, false)) + if ((*itr)->isAlive() && (*itr)->IsWithinDistInMap(pZigguratDoor, 35.0f, false)) { - m_alZigguratAcolyteGUID[i].push_back((*itr)->GetGUID()); + m_zigguratStorage[i].m_lZigguratAcolyteGuid.push_back((*itr)->GetObjectGuid()); itr = lAcolytes.erase(itr); bAlreadyIterated = true; break; @@ -417,28 +505,28 @@ void instance_stratholme::DoSortZiggurats() } // In case some mobs have not been able to be sorted, store their GUIDs again - for (std::list::const_iterator itr = lAcolytes.begin(); itr != lAcolytes.end(); itr++) - m_luiAcolyteGUIDs.push_back((*itr)->GetGUID()); + for (std::list::const_iterator itr = lAcolytes.begin(); itr != lAcolytes.end(); ++itr) + m_luiAcolyteGUIDs.push_back((*itr)->GetObjectGuid()); // Sort Crystal - for (std::list::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) { - itr = m_luiCrystalGUIDs.erase(itr); + m_luiCrystalGUIDs.erase(itr++); continue; } bool bAlreadyIterated = false; for (uint8 i = 0; i < MAX_ZIGGURATS; ++i) { - if (GameObject* pZigguratDoor = instance->GetGameObject(m_auiZigguratGUID[i])) + if (GameObject* pZigguratDoor = instance->GetGameObject(m_zigguratStorage[i].m_doorGuid)) { if (pCrystal->IsWithinDistInMap(pZigguratDoor, 50.0f, false)) { - m_auiCrystalSortedGUID[i] = *itr; - itr = m_luiCrystalGUIDs.erase(itr); + m_zigguratStorage[i].m_crystalGuid = pCrystal->GetObjectGuid(); + m_luiCrystalGUIDs.erase(itr); bAlreadyIterated = true; break; } @@ -450,69 +538,239 @@ void instance_stratholme::DoSortZiggurats() } } -void instance_stratholme::OnCreatureDeath(Creature* pCreature) +void instance_stratholme::OnCreatureEnterCombat(Creature* pCreature) { - if (pCreature->GetEntry() == NPC_THUZADIN_ACOLYTE) + switch (pCreature->GetEntry()) { - for (uint8 i = 0; i < MAX_ZIGGURATS; ++i) - { - if (m_alZigguratAcolyteGUID[i].empty()) - continue; // nothing to do anymore for this ziggurat + case NPC_BARONESS_ANASTARI: SetData(TYPE_BARONESS, IN_PROGRESS); break; + 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; - m_alZigguratAcolyteGUID[i].remove(pCreature->GetGUID()); - if (m_alZigguratAcolyteGUID[i].empty()) - { - // A random zone yell after one is cleared - int32 aAnnounceSay[MAX_ZIGGURATS] = {SAY_ANNOUNCE_ZIGGURAT_1, SAY_ANNOUNCE_ZIGGURAT_2, SAY_ANNOUNCE_ZIGGURAT_3}; - if (Creature* pAnnouncer = instance->GetCreature(m_uiAcolyteAnnouncerGUID)) - DoScriptText(aAnnounceSay[i], pAnnouncer); + case NPC_ABOM_BILE: + case NPC_ABOM_VENOM: + // Start Slaughterhouse Event + SetData(TYPE_RAMSTEIN, SPECIAL); + break; + + case NPC_MINDLESS_UNDEAD: + case NPC_BLACK_GUARD: + // Aggro in Slaughterhouse after Ramstein + SetData(TYPE_BLACK_GUARDS, IN_PROGRESS); + break; + } +} + +void instance_stratholme::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_BARONESS_ANASTARI: SetData(TYPE_BARONESS, FAIL); break; + 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; + + case NPC_ABOM_BILE: + case NPC_ABOM_VENOM: + // Fail in Slaughterhouse Event before Ramstein + SetData(TYPE_RAMSTEIN, FAIL); + break; + case NPC_MINDLESS_UNDEAD: + case NPC_BLACK_GUARD: + // Fail in Slaughterhouse after Ramstein + SetData(TYPE_BLACK_GUARDS, FAIL); + break; + } +} - // Kill Crystal - if (Creature* pCrystal = instance->GetCreature(m_auiCrystalSortedGUID[i])) - pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); +void instance_stratholme::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_BARONESS_ANASTARI: SetData(TYPE_BARONESS, DONE); break; + case NPC_MALEKI_THE_PALLID: SetData(TYPE_PALLID, DONE); break; + case NPC_NERUBENKAN: SetData(TYPE_NERUB, DONE); break; + case NPC_RAMSTEIN: SetData(TYPE_RAMSTEIN, DONE); break; + case NPC_BARON: SetData(TYPE_BARON, DONE); break; + + case NPC_THUZADIN_ACOLYTE: + ThazudinAcolyteJustDied(pCreature); + break; - switch (i) + case NPC_ABOM_BILE: + case NPC_ABOM_VENOM: + // Start Slaughterhouse Event + SetData(TYPE_RAMSTEIN, SPECIAL); + break; + + case NPC_MINDLESS_UNDEAD: + m_luiUndeadGUIDs.remove(pCreature->GetObjectGuid()); + 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) { - case 0: SetData(TYPE_BARONESS, SPECIAL); break; - case 1: SetData(TYPE_NERUB, SPECIAL); break; - case 2: SetData(TYPE_PALLID, SPECIAL); break; + Creature* pGuard = instance->GetCreature(*itr); + if (pGuard && pGuard->isAlive() && !pGuard->isInCombat()) + { + float fX, fY, fZ; + pGuard->GetRandomPoint(aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ, 10.0f, fX, fY, fZ); + pGuard->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } } } + break; + case NPC_BLACK_GUARD: + m_luiGuardGUIDs.remove(pCreature->GetObjectGuid()); + if (m_luiGuardGUIDs.empty()) + SetData(TYPE_BLACK_GUARDS, DONE); + + break; + + // Timmy spawn support + case NPC_CRIMSON_INITIATE: + case NPC_CRIMSON_GALLANT: + case NPC_CRIMSON_GUARDSMAN: + case NPC_CRIMSON_CONJURER: + if (m_suiCrimsonLowGuids.find(pCreature->GetGUIDLow()) != m_suiCrimsonLowGuids.end()) + { + m_suiCrimsonLowGuids.erase(pCreature->GetGUIDLow()); + + // If all courtyard mobs are dead then summon Timmy + if (m_suiCrimsonLowGuids.empty()) + pCreature->SummonCreature(NPC_TIMMY_THE_CRUEL, aTimmyLocation[0].m_fX, aTimmyLocation[0].m_fY, aTimmyLocation[0].m_fZ, aTimmyLocation[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + } + break; + } +} + +void instance_stratholme::ThazudinAcolyteJustDied(Creature* pCreature) +{ + for (uint8 i = 0; i < MAX_ZIGGURATS; ++i) + { + if (m_zigguratStorage[i].m_lZigguratAcolyteGuid.empty()) + continue; // nothing to do anymore for this ziggurat + + m_zigguratStorage[i].m_lZigguratAcolyteGuid.remove(pCreature->GetObjectGuid()); + if (m_zigguratStorage[i].m_lZigguratAcolyteGuid.empty()) + { + // A random zone yell after one is cleared + int32 aAnnounceSay[MAX_ZIGGURATS] = {SAY_ANNOUNCE_ZIGGURAT_1, SAY_ANNOUNCE_ZIGGURAT_2, SAY_ANNOUNCE_ZIGGURAT_3}; + DoOrSimulateScriptTextForThisInstance(aAnnounceSay[i], NPC_THUZADIN_ACOLYTE); + + // Kill Crystal + if (Creature* pCrystal = instance->GetCreature(m_zigguratStorage[i].m_crystalGuid)) + pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + switch (i) + { + case 0: SetData(TYPE_BARONESS, SPECIAL); break; + case 1: SetData(TYPE_NERUB, SPECIAL); break; + case 2: SetData(TYPE_PALLID, SPECIAL); break; + } } } } void instance_stratholme::Update(uint32 uiDiff) { + if (m_uiBarthilasRunTimer) + { + if (m_uiBarthilasRunTimer <= uiDiff) + { + Creature* pBarthilas = GetSingleCreatureFromStorage(NPC_BARTHILAS); + if (pBarthilas && pBarthilas->isAlive() && !pBarthilas->isInCombat()) + pBarthilas->NearTeleportTo(aStratholmeLocation[1].m_fX, aStratholmeLocation[1].m_fY, aStratholmeLocation[1].m_fZ, aStratholmeLocation[1].m_fO); + + SetData(TYPE_BARTHILAS_RUN, DONE); + m_uiBarthilasRunTimer = 0; + } + else + m_uiBarthilasRunTimer -= uiDiff; + } + if (m_uiBaronRunTimer) { + 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) + { + DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_5_MIN, NPC_BARON); + ++m_uiYellCounter; + } + if (m_uiBaronRunTimer <= uiDiff) { - if (GetData(TYPE_BARON_RUN) != DONE) - SetData(TYPE_BARON_RUN, FAIL); + SetData(TYPE_BARON_RUN, FAIL); + + DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_FAIL, NPC_BARON); m_uiBaronRunTimer = 0; - debug_log("SD2: Instance Stratholme: Baron run event reached end. Event has state %u.",GetData(TYPE_BARON_RUN)); + debug_log("SD2: Instance Stratholme: Baron run event reached end. Event has state %u.", GetData(TYPE_BARON_RUN)); } else m_uiBaronRunTimer -= uiDiff; } + if (m_uiMindlessSummonTimer) + { + if (m_uiMindlessCount < 30) + { + if (m_uiMindlessSummonTimer <= uiDiff) + { + if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON)) + { + // Summon mindless skeletons and move them to random point in the center of the square + if (Creature* pTemp = pBaron->SummonCreature(NPC_MINDLESS_UNDEAD, aStratholmeLocation[4].m_fX, aStratholmeLocation[4].m_fY, aStratholmeLocation[4].m_fZ, aStratholmeLocation[4].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + float fX, fY, fZ; + pBaron->GetRandomPoint(aStratholmeLocation[5].m_fX, aStratholmeLocation[5].m_fY, aStratholmeLocation[5].m_fZ, 20.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + m_luiUndeadGUIDs.push_back(pTemp->GetObjectGuid()); + ++m_uiMindlessCount; + } + } + m_uiMindlessSummonTimer = 400; + } + else + m_uiMindlessSummonTimer -= uiDiff; + } + else + m_uiMindlessSummonTimer = 0; + } + if (m_uiSlaugtherSquareTimer) { if (m_uiSlaugtherSquareTimer <= uiDiff) { - if (Creature* pBaron = instance->GetCreature(m_uiBaronGUID)) + // Call next Abomnations + for (GuidSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr) { - for(uint8 i = 0; i < 4; ++i) - pBaron->SummonCreature(NPC_BLACK_GUARD, 4032.84f, -3390.24f, 119.73f, 4.71f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 1800000); - - DoUseDoorOrButton(m_auiRamsteinDoorGUID); - DoUseDoorOrButton(m_auiRivendareDoorGUID); + Creature* pAbom = instance->GetCreature(*itr); + // Skip killed and already walking Abomnations + if (!pAbom || !pAbom->isAlive() || pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) + continue; - debug_log("SD2: Instance Stratholme: Black guard sentries spawned. Opening gates to baron."); + // Let Move to somewhere in the middle + if (!pAbom->isInCombat()) + { + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_PORT_SLAUGTHER)) + { + float fX, fY, fZ; + pAbom->GetRandomPoint(pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ(), 10.0f, fX, fY, fZ); + pAbom->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + break; } - m_uiSlaugtherSquareTimer = 0; + + // TODO - how fast are they called? + m_uiSlaugtherSquareTimer = urand(15000, 30000); } else m_uiSlaugtherSquareTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/stratholme/stratholme.cpp b/scripts/eastern_kingdoms/stratholme/stratholme.cpp index 5b4b98d2b2..d41ce77049 100644 --- a/scripts/eastern_kingdoms/stratholme/stratholme.cpp +++ b/scripts/eastern_kingdoms/stratholme/stratholme.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,8 +22,9 @@ SDCategory: Stratholme EndScriptData */ /* ContentData +go_service_gate go_gauntlet_gate -mob_freed_soul +go_stratholme_postbox mob_restless_soul mobs_spectral_ghostly_citizen EndContentData */ @@ -31,11 +32,30 @@ EndContentData */ #include "precompiled.h" #include "stratholme.h" +/*###### +## go_service_gate +######*/ + +bool GOUse_go_service_gate(Player* /*pPlayer*/, GameObject* pGo) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + + if (!pInstance) + return false; + + if (pInstance->GetData(TYPE_BARTHILAS_RUN) != NOT_STARTED) + return false; + + // if the service gate is used make Barthilas flee + pInstance->SetData(TYPE_BARTHILAS_RUN, IN_PROGRESS); + return false; +} + /*###### ## go_gauntlet_gate (this is the _first_ of the gauntlet gates, two exist) ######*/ -bool GOHello_go_gauntlet_gate(Player* pPlayer, GameObject* pGo) +bool GOUse_go_gauntlet_gate(Player* pPlayer, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); @@ -45,122 +65,144 @@ bool GOHello_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) continue; - if (pGroupie->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE && - !pGroupie->HasAura(SPELL_BARON_ULTIMATUM, EFFECT_INDEX_0) && - pGroupie->GetMap() == pGo->GetMap()) - pGroupie->CastSpell(pGroupie,SPELL_BARON_ULTIMATUM,true); + if (!pGroupie->HasAura(SPELL_BARON_ULTIMATUM)) + pGroupie->CastSpell(pGroupie, SPELL_BARON_ULTIMATUM, true); } } else { - if (pPlayer->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE && - !pPlayer->HasAura(SPELL_BARON_ULTIMATUM, EFFECT_INDEX_0) && - pPlayer->GetMap() == pGo->GetMap()) + if (!pPlayer->HasAura(SPELL_BARON_ULTIMATUM)) pPlayer->CastSpell(pPlayer, SPELL_BARON_ULTIMATUM, true); } - pInstance->SetData(TYPE_BARON_RUN,IN_PROGRESS); + pInstance->SetData(TYPE_BARON_RUN, IN_PROGRESS); return false; } /*###### -## mob_freed_soul +## go_stratholme_postbox ######*/ -//Possibly more of these quotes around. -#define SAY_ZAPPED0 -1329000 -#define SAY_ZAPPED1 -1329001 -#define SAY_ZAPPED2 -1329002 -#define SAY_ZAPPED3 -1329003 - -struct MANGOS_DLL_DECL mob_freed_soulAI : public ScriptedAI +bool GOUse_go_stratholme_postbox(Player* pPlayer, GameObject* pGo) { - mob_freed_soulAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); - void Reset() + if (!pInstance) + return false; + + if (pInstance->GetData(TYPE_POSTMASTER) == DONE) + return false; + + // When the data is Special, spawn the postmaster + if (pInstance->GetData(TYPE_POSTMASTER) == SPECIAL) { - 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; - } + pPlayer->CastSpell(pPlayer, SPELL_SUMMON_POSTMASTER, true); + pInstance->SetData(TYPE_POSTMASTER, DONE); } -}; + else + pInstance->SetData(TYPE_POSTMASTER, IN_PROGRESS); -CreatureAI* GetAI_mob_freed_soul(Creature* pCreature) -{ - return new mob_freed_soulAI(pCreature); + // Summon 3 postmen for each postbox + float fX, fY, fZ; + for (uint8 i = 0; i < 3; ++i) + { + pPlayer->GetRandomPoint(pPlayer->GetPositionX(), pPlayer->GetPositionY(), pPlayer->GetPositionZ(), 3.0f, fX, fY, fZ); + pPlayer->SummonCreature(NPC_UNDEAD_POSTMAN, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + return false; } /*###### ## mob_restless_soul ######*/ -#define SPELL_EGAN_BLASTER 17368 -#define SPELL_SOUL_FREED 17370 -#define QUEST_RESTLESS_SOUL 5282 -#define ENTRY_RESTLESS 11122 -#define ENTRY_FREED 11136 +enum +{ + // Possibly more of these quotes around. + SAY_ZAPPED0 = -1329000, + SAY_ZAPPED1 = -1329001, + SAY_ZAPPED2 = -1329002, + SAY_ZAPPED3 = -1329003, + + QUEST_RESTLESS_SOUL = 5282, + SPELL_EGAN_BLASTER = 17368, + SPELL_SOUL_FREED = 17370, + + NPC_RESTLESS_SOUL = 11122, + NPC_FREED_SOUL = 11136, +}; + +// TODO - likely entirely not needed workaround struct MANGOS_DLL_DECL mob_restless_soulAI : public ScriptedAI { - mob_restless_soulAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + mob_restless_soulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 Tagger; - uint32 Die_Timer; - bool Tagged; + ObjectGuid m_taggerGuid; + uint32 m_uiDieTimer; + bool m_bIsTagged; void Reset() { - Tagger = 0; - Die_Timer = 5000; - Tagged = false; + m_taggerGuid.Clear(); + m_uiDieTimer = 5000; + m_bIsTagged = false; } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (caster->GetTypeId() == TYPEID_PLAYER) + if (pCaster->GetTypeId() == TYPEID_PLAYER) { - if (!Tagged && spell->Id == SPELL_EGAN_BLASTER && ((Player*)caster)->GetQuestStatus(QUEST_RESTLESS_SOUL) == QUEST_STATUS_INCOMPLETE) + if (!m_bIsTagged && pSpell->Id == SPELL_EGAN_BLASTER && ((Player*)pCaster)->GetQuestStatus(QUEST_RESTLESS_SOUL) == QUEST_STATUS_INCOMPLETE) { - Tagged = true; - Tagger = caster->GetGUID(); + m_bIsTagged = true; + m_taggerGuid = pCaster->GetObjectGuid(); } } } - void JustSummoned(Creature *summoned) + void JustSummoned(Creature* pSummoned) override { - summoned->CastSpell(summoned,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 (Tagged) - m_creature->SummonCreature(ENTRY_FREED, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000); + 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 diff) + void UpdateAI(const uint32 uiDiff) override { - if (Tagged) + if (m_bIsTagged) { - if (Die_Timer < diff) + if (m_uiDieTimer < uiDiff) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(Tagger)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_taggerGuid)) pPlayer->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } else - Die_Timer -= diff; + m_uiDieTimer -= uiDiff; } } }; @@ -184,48 +226,48 @@ struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI { mobs_spectral_ghostly_citizenAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 Die_Timer; - bool Tagged; + uint32 m_uiDieTimer; + bool m_bIsTagged; void Reset() { - Die_Timer = 5000; - Tagged = false; + m_uiDieTimer = 5000; + m_bIsTagged = false; } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - if (!Tagged && spell->Id == SPELL_EGAN_BLASTER) - Tagged = true; + if (!m_bIsTagged && pSpell->Id == SPELL_EGAN_BLASTER) + m_bIsTagged = true; } - void JustDied(Unit* Killer) + void JustDied(Unit* /*Killer*/) override { - if (Tagged) + if (m_bIsTagged) { - for(uint32 i = 1; 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); + float x, y, z; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, x, y, z); - //100%, 50%, 33%, 25% chance to spawn - uint32 j = urand(1,i); - if (j==1) - m_creature->SummonCreature(ENTRY_RESTLESS,x,y,z,0,TEMPSUMMON_CORPSE_DESPAWN,600000); + // 100%, 50%, 33%, 25% chance to spawn + uint32 j = urand(0, i); + if (j == 0) + m_creature->SummonCreature(NPC_RESTLESS_SOUL, x, y, z, 0, TEMPSUMMON_DEAD_DESPAWN, 0); } } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (Tagged) + if (m_bIsTagged) { - if (Die_Timer < diff) + if (m_uiDieTimer < uiDiff) { m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } else - Die_Timer -= diff; + m_uiDieTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -234,16 +276,16 @@ struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI DoMeleeAttackIfReady(); } - void ReceiveEmote(Player* pPlayer, uint32 emote) + void ReceiveEmote(Player* pPlayer, uint32 uiEmote) override { - switch(emote) + switch (uiEmote) { case TEXTEMOTE_DANCE: EnterEvadeMode(); break; case TEXTEMOTE_RUDE: - if (m_creature->IsWithinDistInMap(pPlayer, ATTACK_DISTANCE)) - m_creature->CastSpell(pPlayer,SPELL_SLAP,false); + if (m_creature->IsWithinDistInMap(pPlayer, INTERACTION_DISTANCE)) + m_creature->CastSpell(pPlayer, SPELL_SLAP, false); else m_creature->HandleEmote(EMOTE_ONESHOT_RUDE); break; @@ -269,14 +311,19 @@ void AddSC_stratholme() { Script* pNewScript; + pNewScript = new Script; + pNewScript->Name = "go_service_gate"; + pNewScript->pGOUse = &GOUse_go_service_gate; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "go_gauntlet_gate"; - pNewScript->pGOHello = &GOHello_go_gauntlet_gate; + pNewScript->pGOUse = &GOUse_go_gauntlet_gate; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_freed_soul"; - pNewScript->GetAI = &GetAI_mob_freed_soul; + pNewScript->Name = "go_stratholme_postbox"; + pNewScript->pGOUse = &GOUse_go_stratholme_postbox; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/eastern_kingdoms/stratholme/stratholme.h b/scripts/eastern_kingdoms/stratholme/stratholme.h index b6d308974f..45c85a2905 100644 --- a/scripts/eastern_kingdoms/stratholme/stratholme.h +++ b/scripts/eastern_kingdoms/stratholme/stratholme.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,108 +7,154 @@ enum { - MAX_ENCOUNTER = 6, + MAX_ENCOUNTER = 10, MAX_SILVERHAND = 5, MAX_ZIGGURATS = 3, - TYPE_BARON_RUN = 1, - TYPE_BARONESS = 2, - TYPE_NERUB = 3, - TYPE_PALLID = 4, - TYPE_RAMSTEIN = 5, - TYPE_BARON = 6, - - //DATA_BARON = 10, // Wasn't used, verify that it really was never used! - //DATA_YSIDA_TRIGGER = 11, - - TYPE_SH_QUEST = 20, - TYPE_SH_CATHELA = 21, - TYPE_SH_GREGOR = 22, - TYPE_SH_NEMAS = 23, - TYPE_SH_VICAR = 24, - TYPE_SH_AELMAR = 25, - - NPC_CRYSTAL = 10415, //three ziggurat crystals - NPC_BARON = 10440, - NPC_YSIDA_TRIGGER = 16100, - NPC_THUZADIN_ACOLYTE = 10399, //acolytes in ziggurats + TYPE_BARON_RUN = 0, + TYPE_BARONESS = 1, + TYPE_NERUB = TYPE_BARONESS + 1, // Assert that these three TYPEs are in correct order. + TYPE_PALLID = TYPE_BARONESS + 2, + TYPE_RAMSTEIN = 4, + TYPE_BARON = 5, + TYPE_BARTHILAS_RUN = 6, + TYPE_BLACK_GUARDS = 7, + TYPE_POSTMASTER = 8, + TYPE_TRUE_MASTERS = 9, + + NPC_TIMMY_THE_CRUEL = 10808, + NPC_BARTHILAS = 10435, + NPC_BARONESS_ANASTARI = 10436, + NPC_NERUBENKAN = 10437, + NPC_MALEKI_THE_PALLID = 10438, NPC_RAMSTEIN = 10439, + NPC_BARON = 10440, + NPC_CRYSTAL = 10415, // Three ziggurat crystals + NPC_THUZADIN_ACOLYTE = 10399, // Acolytes in ziggurats NPC_ABOM_BILE = 10416, NPC_ABOM_VENOM = 10417, - NPC_BLACK_GUARD = 10394, + NPC_MINDLESS_UNDEAD = 11030, // Zombies summoned after Ramstein + NPC_BLACK_GUARD = 10394, // Zombies summoned after Ramstein NPC_YSIDA = 16031, + NPC_YSIDA_TRIGGER = 16100, + NPC_CRIMSON_INITIATE = 10420, // A couple of them related to spawn Timmy + NPC_CRIMSON_GALLANT = 10424, + NPC_CRIMSON_GUARDSMAN = 10418, + NPC_CRIMSON_CONJURER = 10419, + NPC_UNDEAD_POSTMAN = 11142, + NPC_GREGOR_THE_JUSTICIAR = 17910, // related to quest "True Masters of the Light" + NPC_CATHELA_THE_SEEKER = 17911, + NPC_NEMAS_THE_ARBITER = 17912, + NPC_AELMAR_THE_VANQUISHER = 17913, + NPC_VICAR_HYERONIMUS = 17914, + NPC_PALADIN_QUEST_CREDIT = 17915, GO_SERVICE_ENTRANCE = 175368, GO_GAUNTLET_GATE1 = 175357, - GO_ZIGGURAT_DOOR_1 = 175380, //baroness - GO_ZIGGURAT_DOOR_2 = 175379, //nerub'enkan - GO_ZIGGURAT_DOOR_3 = 175381, //maleki - GO_ZIGGURAT_DOOR_4 = 175405, //rammstein - GO_ZIGGURAT_DOOR_5 = 175796, //baron - GO_PORT_GAUNTLET = 175374, //port from gauntlet to slaugther - GO_PORT_SLAUGTHER = 175373, //port at slaugther - GO_PORT_ELDERS = 175377, //port at elders square + GO_PORT_SLAUGHTER_GATE = 175358, // Port used at the undeads event + GO_ZIGGURAT_DOOR_1 = 175380, // Baroness + GO_ZIGGURAT_DOOR_2 = 175379, // Nerub'enkan + GO_ZIGGURAT_DOOR_3 = 175381, // Maleki + GO_ZIGGURAT_DOOR_4 = 175405, // Ramstein + GO_ZIGGURAT_DOOR_5 = 175796, // Baron + GO_PORT_GAUNTLET = 175374, // Port from gauntlet to slaugther + GO_PORT_SLAUGTHER = 175373, // Port at slaugther + GO_PORT_ELDERS = 175377, // Port at elders square + GO_YSIDA_CAGE = 181071, // Cage to open after baron event is done QUEST_DEAD_MAN_PLEA = 8945, SPELL_BARON_ULTIMATUM = 27861, + SPELL_SUMMON_POSTMASTER = 24627, SAY_ANNOUNCE_ZIGGURAT_1 = -1329004, SAY_ANNOUNCE_ZIGGURAT_2 = -1329005, SAY_ANNOUNCE_ZIGGURAT_3 = -1329006, - SAY_ANNOUNCE_RIVENDARE = -1329007 + SAY_ANNOUNCE_RIVENDARE = -1329007, + + SAY_WARN_BARON = -1329008, + SAY_ANNOUNCE_RUN_START = -1329009, + SAY_ANNOUNCE_RUN_10_MIN = -1329010, + SAY_ANNOUNCE_RUN_5_MIN = -1329011, + SAY_ANNOUNCE_RUN_FAIL = -1329012, + SAY_ANNOUNCE_RAMSTEIN = -1329013, + SAY_UNDEAD_DEFEAT = -1329014, + SAY_EPILOGUE = -1329015, +}; + +static const EVENTLOCATION aStratholmeLocation[] = +{ + {3725.577f, -3599.484f, 142.367f}, // Barthilas door run + {4068.284f, -3535.678f, 122.771f, 2.50f}, // Barthilas tele + {4032.643f, -3378.546f, 119.752f, 4.74f}, // Ramstein summon loc + {4032.843f, -3390.246f, 119.732f}, // Ramstein move loc + {3969.357f, -3391.871f, 119.116f, 5.91f}, // Skeletons summon loc + {4033.044f, -3431.031f, 119.055f}, // Skeletons move loc + {4032.602f, -3378.506f, 119.752f, 4.74f}, // Guards summon loc + {4042.575f, -3337.929f, 115.059f} // Ysida move loc }; -struct MANGOS_DLL_DECL instance_stratholme : public ScriptedInstance +static const EVENTLOCATION aTimmyLocation[] = +{ + {3696.851f, -3152.736f, 127.661f, 4.024f}, // Timmy spawn loc + {3668.603f, -3183.314f, 126.215f} // Courtyard mobs sort point +}; + +struct ZigguratStore +{ + ObjectGuid m_doorGuid; + ObjectGuid m_crystalGuid; + GuidList m_lZigguratAcolyteGuid; +}; + +class MANGOS_DLL_DECL 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); - uint64 GetData64(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return 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 OnCreatureDeath(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; + protected: bool StartSlaugtherSquare(); void DoSortZiggurats(); + void ThazudinAcolyteJustDied(Creature* pCreature); - protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; - bool m_bIsSilverHandDead[MAX_SILVERHAND]; - std::string strInstData; + std::string m_strInstData; uint32 m_uiBaronRunTimer; + uint32 m_uiBarthilasRunTimer; + uint32 m_uiMindlessSummonTimer; uint32 m_uiSlaugtherSquareTimer; - uint64 m_uiServiceEntranceGUID; - uint64 m_uiGauntletGate1GUID; - uint64 m_auiZigguratGUID[MAX_ZIGGURATS]; - uint64 m_auiRamsteinDoorGUID; - uint64 m_auiRivendareDoorGUID; - uint64 m_uiPortGauntletGUID; - uint64 m_uiPortSlaugtherGUID; - uint64 m_uiPortElderGUID; - - uint64 m_uiBaronGUID; - uint64 m_uiYsidaTriggerGUID; - uint64 m_uiAcolyteAnnouncerGUID; - uint64 m_auiCrystalSortedGUID[MAX_ZIGGURATS]; - - std::list m_luiCrystalGUIDs; - std::set m_sAbomnationGUID; - std::list m_luiAcolyteGUIDs; - std::list m_alZigguratAcolyteGUID[MAX_ZIGGURATS]; + uint32 m_uiYellCounter; + uint32 m_uiMindlessCount; + uint8 m_uiPostboxesUsed; + uint8 m_uiSilverHandKilled; + + ZigguratStore m_zigguratStorage[MAX_ZIGGURATS]; + + std::set m_suiCrimsonLowGuids; + 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 715ec262fd..873c37dfb3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: instance_sunken_temple -SD%Complete: 30 -SDComment: +SD%Complete: 90 +SDComment: Hakkar Summon Event needs more sources to improve SDCategory: Sunken Temple EndScriptData */ @@ -25,8 +25,13 @@ EndScriptData */ #include "sunken_temple.h" instance_sunken_temple::instance_sunken_temple(Map* pMap) : ScriptedInstance(pMap), - m_uiJammalainBarrierGUID(0), - m_uiProtectorsRemaining(0) + m_uiProtectorsRemaining(0), + m_uiStatueCounter(0), + m_uiFlameCounter(0), + m_uiAvatarSummonTimer(0), + m_uiSupressorTimer(0), + m_bIsFirstHakkarWave(false), + m_bCanSummonBloodkeeper(false) { Initialize(); } @@ -38,20 +43,39 @@ void instance_sunken_temple::Initialize() void instance_sunken_temple::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - case GO_JAMMALAIN_BARRIER: - m_uiJammalainBarrierGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - DoUseDoorOrButton(m_uiJammalainBarrierGUID); + case GO_JAMMALAN_BARRIER: + if (m_auiEncounter[TYPE_PROTECTORS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_IDOL_OF_HAKKAR: + case GO_HAKKAR_DOOR_1: + case GO_HAKKAR_DOOR_2: break; - } + case GO_ATALAI_LIGHT_BIG: + m_luiBigLightGUIDs.push_back(pGo->GetObjectGuid()); + return; + case GO_EVIL_CIRCLE: + m_vuiCircleGUIDs.push_back(pGo->GetObjectGuid()); + return; + case GO_ETERNAL_FLAME_1: + case GO_ETERNAL_FLAME_2: + case GO_ETERNAL_FLAME_3: + case GO_ETERNAL_FLAME_4: + m_luiFlameGUIDs.push_back(pGo->GetObjectGuid()); + return; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } void instance_sunken_temple::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ZOLO: case NPC_GASHER: @@ -61,33 +85,156 @@ void instance_sunken_temple::OnCreatureCreate(Creature* pCreature) case NPC_MIJAN: ++m_uiProtectorsRemaining; break; + case NPC_JAMMALAN: + case NPC_ATALARION: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} + +void instance_sunken_temple::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + // 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; + } +} + +void instance_sunken_temple::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_ATALARION: SetData(TYPE_ATALARION, DONE); break; + case NPC_JAMMALAN: SetData(TYPE_JAMMALAN, DONE); break; + case NPC_AVATAR_OF_HAKKAR: SetData(TYPE_AVATAR, DONE); break; + + case NPC_SUPPRESSOR: + m_bCanSummonBloodkeeper = true; + break; + + // Jammalain mini-bosses + case NPC_ZOLO: + case NPC_GASHER: + case NPC_LORO: + case NPC_HUKKU: + case NPC_ZULLOR: + case NPC_MIJAN: + SetData(TYPE_PROTECTORS, DONE); + break; } } void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ATALARION: - m_auiEncounter[0] = uiData; + if (uiData == SPECIAL) + DoSpawnAtalarionIfCan(); + m_auiEncounter[uiType] = uiData; break; case TYPE_PROTECTORS: if (uiData == DONE) { - //Jammalain should yell here about barrier being destroyed --m_uiProtectorsRemaining; if (!m_uiProtectorsRemaining) { - m_auiEncounter[1] = uiData; - DoUseDoorOrButton(m_uiJammalainBarrierGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_JAMMALAN_BARRIER); + // Intro yell + DoOrSimulateScriptTextForThisInstance(SAY_JAMMALAN_INTRO, NPC_JAMMALAN); } } break; - case TYPE_JAMMALAIN: - m_auiEncounter[2] = uiData; + case TYPE_JAMMALAN: + m_auiEncounter[uiType] = uiData; break; - case TYPE_MALFURION: - m_auiEncounter[3] = uiData; + case TYPE_AVATAR: + if (uiData == SPECIAL) + { + ++m_uiFlameCounter; + + Creature* pShade = GetSingleCreatureFromStorage(NPC_SHADE_OF_HAKKAR); + if (!pShade) + return; + + 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 + 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 + case MAX_FLAMES: + DoScriptText(SAY_AVATAR_BRAZIER_4, pShade); + pShade->CastSpell(pShade, SPELL_SUMMON_AVATAR, true); + m_uiAvatarSummonTimer = 0; + m_uiSupressorTimer = 0; + break; + } + + // Summon the suppressors only after the flames are doused + // Summon timer is confusing random; timers were: 13, 39 and 52 secs; + if (m_uiFlameCounter != MAX_FLAMES) + m_uiSupressorTimer = urand(15000, 45000); + + return; + } + + // Prevent double processing + if (m_auiEncounter[uiType] == uiData) + return; + + if (uiData == IN_PROGRESS) + { + m_uiSupressorTimer = 0; + DoUpdateFlamesFlags(false); + + // Summon timer; use a small delay + m_uiAvatarSummonTimer = 3000; + m_bIsFirstHakkarWave = true; + + // Summon the shade + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + if (Creature* pShade = pPlayer->SummonCreature(NPC_SHADE_OF_HAKKAR, aSunkenTempleLocation[1].x, aSunkenTempleLocation[1].y, aSunkenTempleLocation[1].z, aSunkenTempleLocation[1].o, TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + m_mNpcEntryGuidStore[NPC_SHADE_OF_HAKKAR] = pShade->GetObjectGuid(); + pShade->SetRespawnDelay(DAY); + } + + // Respawn circles + for (GuidVector::const_iterator itr = m_vuiCircleGUIDs.begin(); itr != m_vuiCircleGUIDs.end(); ++itr) + DoRespawnGameObject(*itr, 30 * MINUTE); + } + else if (uiData == FAIL) + { + // In case of wipe during the summoning ritual the shade is despawned + // The trash mobs stay in place, they are not despawned; the avatar is not sure if it's despawned or not but most likely he'll stay in place + + // Despawn the shade and the avatar if needed -- TODO, avatar really? + if (Creature* pShade = GetSingleCreatureFromStorage(NPC_SHADE_OF_HAKKAR)) + pShade->ForcedDespawn(); + + // Reset flames + DoUpdateFlamesFlags(true); + } + + // Use combat doors + DoUseDoorOrButton(GO_HAKKAR_DOOR_1); + DoUseDoorOrButton(GO_HAKKAR_DOOR_2); + + m_auiEncounter[uiType] = uiData; + break; } @@ -97,14 +244,69 @@ void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; - strInstData = saveStream.str(); + 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; } } +void instance_sunken_temple::DoSpawnAtalarionIfCan() +{ + // Return if already summoned + if (GetSingleCreatureFromStorage(NPC_ATALARION)) + return; + + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + pPlayer->SummonCreature(NPC_ATALARION, aSunkenTempleLocation[0].x, aSunkenTempleLocation[0].y, aSunkenTempleLocation[0].z, aSunkenTempleLocation[0].o, TEMPSUMMON_DEAD_DESPAWN, 0); + + // Spawn the idol of Hakkar + 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); +} + +bool instance_sunken_temple::ProcessStatueEvent(uint32 uiEventId) +{ + bool bEventStatus = false; + + // Check if the statues are activated correctly + // Increase the counter when the correct statue is activated + for (uint8 i = 0; i < MAX_STATUES; ++i) + { + if (uiEventId == m_aAtalaiStatueEvents[i] && m_uiStatueCounter == i) + { + // Right Statue activated + ++m_uiStatueCounter; + bEventStatus = true; + break; + } + } + + if (!bEventStatus) + return false; + + // Check if all statues are active + if (m_uiStatueCounter == MAX_STATUES) + SetData(TYPE_ATALARION, SPECIAL); + + return true; +} + +void instance_sunken_temple::DoUpdateFlamesFlags(bool bRestore) +{ + for (GuidList::const_iterator itr = m_luiFlameGUIDs.begin(); itr != m_luiFlameGUIDs.end(); ++itr) + DoToggleGameObjectFlags(*itr, GO_FLAG_NO_INTERACT, bRestore); +} + void instance_sunken_temple::Load(const char* chrIn) { if (!chrIn) @@ -116,31 +318,110 @@ void instance_sunken_temple::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]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - if (m_auiEncounter[i] == IN_PROGRESS) + // Here a bit custom, to have proper mechanics for the statue events + if (m_auiEncounter[i] != DONE) m_auiEncounter[i] = NOT_STARTED; } OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_sunken_temple::GetData(uint32 uiType) +uint32 instance_sunken_temple::GetData(uint32 uiType) const { - switch(uiType) + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_sunken_temple::Update(uint32 uiDiff) +{ + if (m_auiEncounter[TYPE_AVATAR] != IN_PROGRESS) + return; + + // Summon random mobs around the circles + if (m_uiAvatarSummonTimer) { - case TYPE_ATALARION: - return m_auiEncounter[0]; - case TYPE_PROTECTORS: - return m_auiEncounter[1]; - case TYPE_JAMMALAIN: - return m_auiEncounter[2]; - case TYPE_MALFURION: - return m_auiEncounter[3]; + if (m_uiAvatarSummonTimer <= uiDiff) + { + Creature* pShade = GetSingleCreatureFromStorage(NPC_SHADE_OF_HAKKAR); + if (!pShade) + return; + + // If no summon circles are spawned then return + if (m_vuiCircleGUIDs.empty()) + return; + + if (m_bIsFirstHakkarWave) // First wave summoned + { + // Summon at all circles + 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); + } + + // Summon Bloodkeeper at random circle + if (GameObject* pCircle = instance->GetGameObject(m_vuiCircleGUIDs[urand(0, m_vuiCircleGUIDs.size() - 1)])) + pShade->SummonCreature(NPC_BLOODKEEPER, pCircle->GetPositionX(), pCircle->GetPositionY(), pCircle->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + m_bCanSummonBloodkeeper = false; + m_bIsFirstHakkarWave = false; + m_uiAvatarSummonTimer = 50000; + } + else // Later wave + { + uint32 uiRoll = urand(0, 99); + uint8 uiMaxSummons = uiRoll < 75 ? 1 : uiRoll < 95 ? 2 : 3; + + if (m_bCanSummonBloodkeeper && roll_chance_i(30)) + { + // Summon a Bloodkeeper + if (GameObject* pCircle = instance->GetGameObject(m_vuiCircleGUIDs[urand(0, m_vuiCircleGUIDs.size() - 1)])) + pShade->SummonCreature(NPC_BLOODKEEPER, pCircle->GetPositionX(), pCircle->GetPositionY(), pCircle->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + m_bCanSummonBloodkeeper = false; + --uiMaxSummons; + } + + for (uint8 i = 0; i < uiMaxSummons; ++i) + { + if (GameObject* pCircle = instance->GetGameObject(m_vuiCircleGUIDs[urand(0, m_vuiCircleGUIDs.size() - 1)])) + pShade->SummonCreature(NPC_HAKKARI_MINION, pCircle->GetPositionX(), pCircle->GetPositionY(), pCircle->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + m_uiAvatarSummonTimer = urand(3000, 15000); + } + } + else + m_uiAvatarSummonTimer -= uiDiff; + } + + // Summon nightmare suppressor after flame used + if (m_uiSupressorTimer) + { + if (m_uiSupressorTimer <= uiDiff) + { + Creature* pShade = GetSingleCreatureFromStorage(NPC_SHADE_OF_HAKKAR); + if (!pShade) + { + // Something went very wrong! + return; + } + + // Summon npc at random door; movement and script handled in DB + uint8 uiSummonLoc = urand(0, 1); + pShade->SummonCreature(NPC_SUPPRESSOR, aHakkariDoorLocations[uiSummonLoc].x, aHakkariDoorLocations[uiSummonLoc].y, aHakkariDoorLocations[uiSummonLoc].z, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + // This timer is finished now + m_uiSupressorTimer = 0; + } + else + m_uiSupressorTimer -= uiDiff; } - return 0; } InstanceData* GetInstanceData_instance_sunken_temple(Map* pMap) @@ -150,9 +431,10 @@ InstanceData* GetInstanceData_instance_sunken_temple(Map* pMap) void AddSC_instance_sunken_temple() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_sunken_temple"; - newscript->GetInstanceData = &GetInstanceData_instance_sunken_temple; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_sunken_temple"; + pNewScript->GetInstanceData = &GetInstanceData_instance_sunken_temple; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp b/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp index 2b4b70c5b9..4fc5f4bbc8 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,6 +24,10 @@ EndScriptData */ /* ContentData at_shade_of_eranikus npc_malfurion_stormrage +event_antalarion_statue_activation +event_avatar_of_hakkar +go_eternal_flame +effectDummy_summon_hakkar EndContentData */ #include "precompiled.h" @@ -35,18 +39,18 @@ 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 + // 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) { - pPlayer->SummonCreature(NPC_MALFURION, -639.378723f, -4.238533f, -90.835098f, 2.724664f, TEMPSUMMON_DEAD_DESPAWN, 0); + pPlayer->SummonCreature(NPC_MALFURION, aSunkenTempleLocation[2].x, aSunkenTempleLocation[2].y, aSunkenTempleLocation[2].z, aSunkenTempleLocation[2].o, TEMPSUMMON_DEAD_DESPAWN, 0); pInstance->SetData(TYPE_MALFURION, DONE); } } @@ -57,6 +61,7 @@ bool AreaTrigger_at_shade_of_eranikus(Player* pPlayer, AreaTriggerEntry const* p /*###### ## npc_malfurion_stormrage ######*/ + enum { EMOTE_MALFURION1 = -1109000, @@ -72,8 +77,14 @@ struct MANGOS_DLL_DECL npc_malfurionAI : public ScriptedAI { npc_malfurionAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiSpeech = 0; - m_uiSayTimer = 0; + // 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); } @@ -81,9 +92,9 @@ struct MANGOS_DLL_DECL npc_malfurionAI : public ScriptedAI uint32 m_uiSpeech; void Reset() {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - // we are in Sunken Temple + // We are in Sunken Temple if (m_creature->GetMap()->IsDungeon()) { if (m_uiSpeech < MAX_MALFURION_TEMPLE_SPEECHES) @@ -93,28 +104,29 @@ struct MANGOS_DLL_DECL npc_malfurionAI : public ScriptedAI switch (m_uiSpeech) { case 0: - DoScriptText(EMOTE_MALFURION1, m_creature); - m_uiSayTimer = 1500; - break; - case 1: m_creature->HandleEmote(EMOTE_ONESHOT_BOW); m_uiSayTimer = 2000; break; - case 2: + case 1: DoScriptText(SAY_MALFURION1, m_creature); - m_uiSayTimer = 1000; + m_creature->HandleEmote(EMOTE_STATE_TALK); + m_uiSayTimer = 12000; break; - case 3: + case 2: DoScriptText(SAY_MALFURION2, m_creature); - m_uiSayTimer = 1000; + m_uiSayTimer = 12000; break; - case 4: + case 3: DoScriptText(SAY_MALFURION3, m_creature); - m_uiSayTimer = 2000; + m_uiSayTimer = 11000; break; - case 5: + case 4: DoScriptText(SAY_MALFURION4, m_creature); + m_uiSayTimer = 4000; + break; + case 5: m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->HandleEmote(EMOTE_STATE_NONE); break; } @@ -132,17 +144,140 @@ CreatureAI* GetAI_npc_malfurion(Creature* pCreature) return new npc_malfurionAI(pCreature); } +/*###### +## event_antalarion_statues +######*/ + +bool ProcessEventId_event_antalarion_statue_activation(uint32 uiEventId, Object* pSource, Object* pTarget, bool /*bIsStart*/) +{ + if (pSource->GetTypeId() == TYPEID_PLAYER && pTarget->GetTypeId() == TYPEID_GAMEOBJECT) + { + if (instance_sunken_temple* pInstance = (instance_sunken_temple*)((Player*)pSource)->GetInstanceData()) + { + // return if event completed + if (pInstance->GetData(TYPE_ATALARION) != NOT_STARTED) + return true; + + // Send the event id to process + if (pInstance->ProcessStatueEvent(uiEventId)) + { + // Activate the green light if the correct statue is activated + if (GameObject* pLight = GetClosestGameObjectWithEntry((GameObject*)pTarget, GO_ATALAI_LIGHT, INTERACTION_DISTANCE)) + pInstance->DoRespawnGameObject(pLight->GetObjectGuid(), 30 * MINUTE); + } + else + { + // If the wrong statue was activated, then trigger trap + // We don't know actually which trap goes to which statue so we need to search for each + if (GameObject* pTrap = GetClosestGameObjectWithEntry((GameObject*)pTarget, GO_ATALAI_TRAP_1, INTERACTION_DISTANCE)) + pTrap->Use((Unit*)pSource); + else if (GameObject* pTrap = GetClosestGameObjectWithEntry((GameObject*)pTarget, GO_ATALAI_TRAP_2, INTERACTION_DISTANCE)) + pTrap->Use((Unit*)pSource); + else if (GameObject* pTrap = GetClosestGameObjectWithEntry((GameObject*)pTarget, GO_ATALAI_TRAP_3, INTERACTION_DISTANCE)) + pTrap->Use((Unit*)pSource); + } + + return true; + } + } + return false; +} + +/*###### +## event_avatar_of_hakkar +######*/ +bool ProcessEventId_event_avatar_of_hakkar(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (pSource->GetTypeId() == TYPEID_PLAYER) + { + if (instance_sunken_temple* pInstance = (instance_sunken_temple*)((Player*)pSource)->GetInstanceData()) + { + // return if not NOT_STARTED + if (pInstance->GetData(TYPE_AVATAR) != NOT_STARTED) + return true; + + pInstance->SetData(TYPE_AVATAR, IN_PROGRESS); + + return true; + } + } + return false; +} + +/*###### +## go_eternal_flame +######*/ +bool GOUse_go_eternal_flame(Player* /*pPlayer*/, GameObject* pGo) +{ + instance_sunken_temple* pInstance = (instance_sunken_temple*)pGo->GetInstanceData(); + + if (!pInstance) + return false; + + if (pInstance->GetData(TYPE_AVATAR) != IN_PROGRESS) + return false; + + // Set data to special when flame is used + pInstance->SetData(TYPE_AVATAR, SPECIAL); + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + + return true; +} + +/*###### +## effectDummy_summon_hakkar +######*/ +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) + { + if (!pCaster || pCaster->GetTypeId() != TYPEID_UNIT) + return true; + + // Update entry to avatar of Hakkar and cast some visuals + ((Creature*)pCaster)->UpdateEntry(NPC_AVATAR_OF_HAKKAR); + pCaster->CastSpell(pCaster, SPELL_AVATAR_SUMMONED, true); + DoScriptText(SAY_AVATAR_SPAWN, pCaster); + + // Always return true when we are handling this spell and effect + return true; + } + + return false; +} + void AddSC_sunken_temple() { - Script* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "at_shade_of_eranikus"; + pNewScript->pAreaTrigger = &AreaTrigger_at_shade_of_eranikus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_malfurion_stormrage"; + pNewScript->GetAI = &GetAI_npc_malfurion; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_antalarion_statue_activation"; + pNewScript->pProcessEventId = &ProcessEventId_event_antalarion_statue_activation; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_avatar_of_hakkar"; + pNewScript->pProcessEventId = &ProcessEventId_event_avatar_of_hakkar; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "at_shade_of_eranikus"; - newscript->pAreaTrigger = &AreaTrigger_at_shade_of_eranikus; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_eternal_flame"; + pNewScript->pGOUse = &GOUse_go_eternal_flame; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_malfurion_stormrage"; - newscript->GetAI = &GetAI_npc_malfurion; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_shade_of_hakkar"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_summon_hakkar; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h b/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h index 84a10197aa..651409122c 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,20 +7,24 @@ enum { - MAX_ENCOUNTER = 4, + MAX_ENCOUNTER = 5, + MAX_STATUES = 6, + MAX_FLAMES = 4, - TYPE_ATALARION = 1, - TYPE_PROTECTORS = 2, - TYPE_JAMMALAIN = 3, - TYPE_MALFURION = 4, + TYPE_ATALARION = 0, + TYPE_PROTECTORS = 1, + TYPE_JAMMALAN = 2, + TYPE_MALFURION = 3, + TYPE_AVATAR = 4, NPC_ATALARION = 8580, NPC_DREAMSCYTH = 5721, NPC_WEAVER = 5720, + NPC_JAMMALAN = 5710, NPC_AVATAR_OF_HAKKAR = 8443, NPC_SHADE_OF_ERANIKUS = 5709, - // Jammalain min-bosses + // Jammalain mini-bosses NPC_ZOLO = 5712, NPC_GASHER = 5713, NPC_LORO = 5714, @@ -28,23 +32,69 @@ enum NPC_ZULLOR = 5716, NPC_MIJAN = 5717, + // Avatar of hakkar mobs + NPC_SHADE_OF_HAKKAR = 8440, // Shade of Hakkar appears when the event starts; will despawn when avatar of hakkar is summoned + NPC_BLOODKEEPER = 8438, // Spawned rarely and contains the hakkari blood -> used to extinguish the flames + NPC_HAKKARI_MINION = 8437, // Npc randomly spawned during the event = trash + NPC_SUPPRESSOR = 8497, // Npc summoned at one of the two doors and moves to the boss; + NPC_MALFURION = 15362, - GO_ALTAR_OF_HAKKAR = 148836, + GO_ALTAR_OF_HAKKAR = 148836, // Used in order to show the player the order of the statue activation + GO_IDOL_OF_HAKKAR = 148838, // Appears when atalarion is summoned; this was removed in 4.0.1 + + GO_ATALAI_LIGHT = 148883, // Green light, activates when the correct statue is chosen + GO_ATALAI_LIGHT_BIG = 148937, // Big light, used at the altar event - GO_ATALAI_STATUE_1 = 148830, - GO_ATALAI_STATUE_2 = 148831, - GO_ATALAI_STATUE_3 = 148832, - GO_ATALAI_STATUE_4 = 148833, - GO_ATALAI_STATUE_5 = 148834, - GO_ATALAI_STATUE_6 = 148835, + GO_ATALAI_TRAP_1 = 177484, // Trapps triggered if the wrong statue is activated + GO_ATALAI_TRAP_2 = 177485, // The traps are spawned in DB randomly around the statues (we don't know exactly which statue has which trap) + GO_ATALAI_TRAP_3 = 148837, GO_ETERNAL_FLAME_1 = 148418, GO_ETERNAL_FLAME_2 = 148419, GO_ETERNAL_FLAME_3 = 148420, GO_ETERNAL_FLAME_4 = 148421, - GO_JAMMALAIN_BARRIER = 149431 + GO_EVIL_CIRCLE = 148998, // Objects used at the avatar event. they are spawned when the event starts, and the mobs are summon atop of them + GO_HAKKAR_DOOR_1 = 149432, // Combat doors + GO_HAKKAR_DOOR_2 = 149433, + + GO_JAMMALAN_BARRIER = 149431, + + // Event ids related to the statue activation + EVENT_ID_STATUE_1 = 3094, + EVENT_ID_STATUE_2 = 3095, + EVENT_ID_STATUE_3 = 3097, + EVENT_ID_STATUE_4 = 3098, + EVENT_ID_STATUE_5 = 3099, + EVENT_ID_STATUE_6 = 3100, + + SPELL_SUMMON_AVATAR = 12639, // Cast by the shade of hakkar, updates entry to avatar + SPELL_AVATAR_SUMMONED = 12948, + + SAY_JAMMALAN_INTRO = -1109005, + SAY_AVATAR_BRAZIER_1 = -1109006, + SAY_AVATAR_BRAZIER_2 = -1109007, + SAY_AVATAR_BRAZIER_3 = -1109008, + SAY_AVATAR_BRAZIER_4 = -1109009, + SAY_AVATAR_SPAWN = -1109010, +}; + +// This is also the needed order for activation: S, N, SW, SE, NW, NE +static const uint32 m_aAtalaiStatueEvents[MAX_STATUES] = {EVENT_ID_STATUE_1, EVENT_ID_STATUE_2, EVENT_ID_STATUE_3, EVENT_ID_STATUE_4, EVENT_ID_STATUE_5, EVENT_ID_STATUE_6}; + +static const LOCATION 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 +}; + +// Summon location for the suppressors +static const LOCATION aHakkariDoorLocations[2] = +{ + { -420.629f, 276.682f, -90.827f}, + { -512.015f, 276.134f, -90.827f} }; class MANGOS_DLL_DECL instance_sunken_temple : public ScriptedInstance @@ -53,22 +103,42 @@ class MANGOS_DLL_DECL instance_sunken_temple : public ScriptedInstance instance_sunken_temple(Map* pMap); ~instance_sunken_temple() {} - void Initialize(); + void Initialize() override; + + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + void OnCreatureEvade(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 Update(uint32 uiDiff) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + bool ProcessStatueEvent(uint32 uiEventId); - const char* Save() { return 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]; - std::string strInstData; + void DoSpawnAtalarionIfCan(); + void DoUpdateFlamesFlags(bool bRestore); - uint64 m_uiJammalainBarrierGUID; - uint8 m_uiProtectorsRemaining; + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint8 m_uiProtectorsRemaining; // Jammalan door handling + uint8 m_uiStatueCounter; // Atalarion Statue Event + uint8 m_uiFlameCounter; // Avatar of Hakkar Event + uint32 m_uiAvatarSummonTimer; + uint32 m_uiSupressorTimer; + bool m_bIsFirstHakkarWave; + bool m_bCanSummonBloodkeeper; + + 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 f8c09810ca..db46df9f94 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,15 +16,15 @@ /* ScriptData SDName: Boss_Brutallus -SD%Complete: 50 -SDComment: Intro not made. Script for Madrigosa to be added here. +SD%Complete: 90 +SDComment: Intro may need some adjustments SDCategory: Sunwell Plateau EndScriptData */ #include "precompiled.h" #include "sunwell_plateau.h" -enum Brutallus +enum { YELL_INTRO = -1580017, YELL_INTRO_BREAK_ICE = -1580018, @@ -50,16 +50,64 @@ enum Brutallus SPELL_METEOR_SLASH = 45150, SPELL_BURN = 45141, - SPELL_BURN_AURA_EFFECT = 46394, SPELL_STOMP = 45185, - SPELL_BERSERK = 26662 + SPELL_BERSERK = 26662, + SPELL_SUMMON_DEATH_CLOUD = 45884, // Summoned on death + + // Epilogue spells + SPELL_BRUTALLUS_DEATH_CLOUD = 45212, + SPELL_FELBLAZE_PREVIZUAL = 44885, + SPELL_SUMMON_FELBLAZE = 45069, + + NPC_BRUTALLUS_DEATH_CLOUD = 25703, + + // spells used during the intro event + SPELL_FROST_BLAST = 45203, // Madrigosa's spells + SPELL_FREEZE = 46609, // Activates the ice barrier - script effect for 46610 + SPELL_FROSTBOLT = 44843, + SPELL_FROST_BREATH = 45065, + SPELL_ENCAPSULATE = 44883, + SPELL_FEL_FIREBALL = 44844, // Brutallus' spells + 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 + + POINT_MOVE_GROUND = 1, + POINT_MOVE_ICE_BLOCK = 2, }; -struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI +static const DialogueEntry aIntroDialogue[] = { - boss_brutallusAI(Creature* pCreature) : ScriptedAI(pCreature) + {NPC_MADRIGOSA, 0, 6000}, + {YELL_MADR_ICE_BARRIER, NPC_MADRIGOSA, 7000}, + {YELL_MADR_INTRO, NPC_MADRIGOSA, 7000}, + {YELL_INTRO, NPC_BRUTALLUS, 6000}, + {SPELL_FROST_BREATH, 0, 6000}, + {POINT_MOVE_ICE_BLOCK, 0, 5000}, + {YELL_MADR_ICE_BLOCK, NPC_MADRIGOSA, 5000}, + {SPELL_FLAME_RING, 0, 7000}, + {YELL_INTRO_BREAK_ICE, NPC_BRUTALLUS, 1000}, + {SPELL_FEL_FIREBALL, 0, 4000}, + {POINT_MOVE_GROUND, 0, 5000}, + {YELL_MADR_TRAP, NPC_MADRIGOSA, 14000}, + {YELL_INTRO_CHARGE, NPC_BRUTALLUS, 10000}, + {YELL_INTRO_KILL_MADRIGOSA, NPC_BRUTALLUS, 8000}, + {YELL_INTRO_TAUNT, NPC_BRUTALLUS, 0}, + {0, 0, 0}, +}; + +/*###### +## boss_brutallus +######*/ + +struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHelper +{ + boss_brutallusAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); } @@ -71,30 +119,44 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI uint32 m_uiBerserkTimer; uint32 m_uiLoveTimer; - void Reset() + uint32 m_uiMadrigosaSpellTimer; + + bool m_bCanDoMeleeAttack; + bool m_bIsIntroInProgress; + + void Reset() override { - m_uiSlashTimer = 11000; - m_uiStompTimer = 30000; - m_uiBurnTimer = 60000; - m_uiBerserkTimer = 360000; - m_uiLoveTimer = urand(10000, 17000); + m_uiSlashTimer = 11000; + m_uiStompTimer = 30000; + m_uiBurnTimer = 20000; + m_uiBerserkTimer = 6 * MINUTE * IN_MILLISECONDS; + m_uiLoveTimer = urand(10000, 17000); - //TODO: correct me when pre-event implemented - if (m_pInstance) - m_pInstance->SetData(TYPE_BRUTALLUS, NOT_STARTED); + m_uiMadrigosaSpellTimer = 0; + + m_bCanDoMeleeAttack = true; + m_bIsIntroInProgress = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { + // Don't aggro when attacking Madrigosa + if (pWho->GetEntry() == NPC_MADRIGOSA) + return; + DoScriptText(YELL_AGGRO, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_BRUTALLUS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { - switch(urand(0, 2)) + // Don't yell for Madrigosa + if (pVictim->GetEntry() == NPC_MADRIGOSA) + return; + + switch (urand(0, 2)) { case 0: DoScriptText(YELL_KILL1, m_creature); break; case 1: DoScriptText(YELL_KILL2, m_creature); break; @@ -102,28 +164,239 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(YELL_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DEATH_CLOUD, CAST_TRIGGERED); if (m_pInstance) m_pInstance->SetData(TYPE_BRUTALLUS, DONE); } - void SpellHitTarget(Unit* pCaster, const SpellEntry* pSpell) + void JustReachedHome() override + { + if (m_pInstance) + { + // When evade from the fight with Madrigosa skip this + if (m_pInstance->GetData(TYPE_BRUTALLUS) == SPECIAL) + return; + + m_pInstance->SetData(TYPE_BRUTALLUS, FAIL); + } + } + + void GetAIInformation(ChatHandler& reader) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_BRUTALLUS) == SPECIAL) + reader.PSendSysMessage("Brutallus intro event is currently %s", m_bIsIntroInProgress ? "in progress" : "completed"); + else + reader.PSendSysMessage("Brutallus intro event is currently %s", m_pInstance->GetData(TYPE_BRUTALLUS) == NOT_STARTED ? "not started" : "completed"); + + if (m_pInstance->GetData(TYPE_BRUTALLUS) != NOT_STARTED) + { + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA, true)) + reader.PSendSysMessage("Madrigosa guid is %s and has %u health.", pMadrigosa->GetObjectGuid().GetString().c_str(), pMadrigosa->GetHealth()); + } + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // Error log if Madrigosa dies + if (pSummoned->GetEntry() == NPC_MADRIGOSA) + script_error_log("Npc %u, %s, died unexpectedly. Felmyst won't be summoned anymore.", pSummoned->GetEntry(), pSummoned->GetName()); + } + + 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) override + { + if (pSummoned->GetEntry() == NPC_MADRIGOSA) + { + pSummoned->SetWalk(false); + pSummoned->SetLevitate(true); + 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) override + { + if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_MADRIGOSA) + return; + + if (uiPointId == POINT_MOVE_GROUND) + pSummoned->SetLevitate(false); + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + // Fake death Madrigosa when charged + if (pTarget->GetEntry() == NPC_MADRIGOSA && pSpell->Id == SPELL_CHARGE) + { + DoScriptText(YELL_MADR_DEATH, pTarget); + pTarget->InterruptNonMeleeSpells(true); + pTarget->SetHealth(0); + pTarget->StopMoving(); + pTarget->ClearComboPointHolders(); + pTarget->RemoveAllAurasOnDeath(); + pTarget->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + pTarget->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + pTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTarget->ClearAllReactives(); + pTarget->GetMotionMaster()->Clear(); + pTarget->GetMotionMaster()->MoveIdle(); + pTarget->SetStandState(UNIT_STAND_STATE_DEAD); + + // Brutallus evades + EnterEvadeMode(); + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case NPC_MADRIGOSA: + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_FLIGHT_TRIGGER_LEFT)) + m_creature->SummonCreature(NPC_MADRIGOSA, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_bIsIntroInProgress = true; + break; + case YELL_MADR_ICE_BARRIER: + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + pMadrigosa->CastSpell(pMadrigosa, SPELL_FREEZE, true); + break; + case YELL_MADR_INTRO: + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + 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)) + m_creature->AI()->AttackStart(pMadrigosa); + break; + case SPELL_FROST_BREATH: + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + { + pMadrigosa->CastSpell(m_creature, SPELL_FROST_BREATH, true); + pMadrigosa->GetMotionMaster()->MoveIdle(); + } + break; + case POINT_MOVE_ICE_BLOCK: + m_bCanDoMeleeAttack = false; + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + { + 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 + m_creature->GetMotionMaster()->MoveIdle(); + break; + case YELL_MADR_ICE_BLOCK: + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + pMadrigosa->CastSpell(m_creature, SPELL_FROST_BLAST, true); + 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: + m_creature->RemoveAurasDueToSpell(SPELL_FLAME_RING); + break; + case SPELL_FEL_FIREBALL: + // Spell has script target Madrigosa + DoCastSpellIfCan(m_creature, SPELL_FEL_FIREBALL); + break; + case POINT_MOVE_GROUND: + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + 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: + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + { + pMadrigosa->CastSpell(m_creature, SPELL_ENCAPSULATE, true); + // Need to remove the fire aura after 4 sec so Madrigosa won't die so soon + pMadrigosa->RemoveAurasDueToSpell(SPELL_FEL_FIREBALL); + } + break; + case YELL_INTRO_CHARGE: + m_bCanDoMeleeAttack = true; + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + DoCastSpellIfCan(m_creature, SPELL_CHARGE); + break; + case YELL_INTRO_KILL_MADRIGOSA: + // Face the players + if (GameObject* pIceWall = m_pInstance->GetSingleGameObjectFromStorage(GO_ICE_BARRIER)) + m_creature->SetFacingToObject(pIceWall); + break; + case YELL_INTRO_TAUNT: + DoCastSpellIfCan(m_creature, SPELL_BREAK_ICE); + m_bIsIntroInProgress = false; + break; + } + } + + // Wrapper to start the dialogue text + void DoStartIntro() + { + StartNextDialogueText(NPC_MADRIGOSA); + } + + // Wrapper to keep all the intro event stuff together + void UpdateIntroEvent(const uint32 uiDiff) { - if (pSpell->Id == SPELL_BURN) - pCaster->CastSpell(pCaster, SPELL_BURN_AURA_EFFECT, true, NULL, NULL, m_creature->GetGUID()); + // Dialogue updates outside of combat too + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiMadrigosaSpellTimer) + { + if (m_uiMadrigosaSpellTimer <= uiDiff) + { + if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) + pMadrigosa->CastSpell(m_creature, SPELL_FROSTBOLT, true); + m_uiMadrigosaSpellTimer = urand(1000, 2000); + } + else + m_uiMadrigosaSpellTimer -= uiDiff; + } + + // We need to limit the melee attacks for the intro event + if (m_bCanDoMeleeAttack) + DoMeleeAttackIfReady(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + // Update only the intro related stuff + if (m_pInstance && m_pInstance->GetData(TYPE_BRUTALLUS) == SPECIAL) + { + UpdateIntroEvent(uiDiff); + return; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; 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; @@ -136,52 +409,44 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI if (m_uiSlashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_METEOR_SLASH); - m_uiSlashTimer = 11000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_METEOR_SLASH) == CAST_OK) + m_uiSlashTimer = 11000; } else m_uiSlashTimer -= uiDiff; if (m_uiStompTimer < uiDiff) { - if (Unit* pTarget = m_creature->getVictim()) - { - DoCastSpellIfCan(pTarget,SPELL_STOMP); - - if (pTarget->HasAura(SPELL_BURN_AURA_EFFECT, EFFECT_INDEX_0)) - pTarget->RemoveAurasDueToSpell(SPELL_BURN_AURA_EFFECT); - } - - m_uiStompTimer = 30000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STOMP) == CAST_OK) + m_uiStompTimer = 30000; } else m_uiStompTimer -= uiDiff; if (m_uiBurnTimer < uiDiff) { - //returns any unit - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BURN, SELECT_FLAG_PLAYER)) { - //so we get owner, in case unit was pet/totem/etc - if (Player* pPlayer = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself()) - DoCastSpellIfCan(pPlayer, SPELL_BURN); + if (DoCastSpellIfCan(pTarget, SPELL_BURN) == CAST_OK) + m_uiBurnTimer = 20000; } - - m_uiBurnTimer = 60000; } else m_uiBurnTimer -= uiDiff; - if (m_uiBerserkTimer < uiDiff) + if (m_uiBerserkTimer) { - if (DoCastSpellIfCan(m_creature,SPELL_BERSERK) == CAST_OK) + if (m_uiBerserkTimer <= uiDiff) { - DoScriptText(YELL_BERSERK, m_creature); - m_uiBerserkTimer = 20000; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(YELL_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } } + else + m_uiBerserkTimer -= uiDiff; } - else - m_uiBerserkTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -192,14 +457,54 @@ CreatureAI* GetAI_boss_brutallus(Creature* pCreature) return new boss_brutallusAI(pCreature); } -bool AreaTrigger_at_madrigosa(Player* pPlayer, AreaTriggerEntry const* pAt) +/*###### +## 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 + if (pAura->GetId() == SPELL_BRUTALLUS_DEATH_CLOUD && pAura->GetEffIndex() == EFFECT_INDEX_0 && !bApply) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + if (ScriptedInstance* pInstance = (ScriptedInstance*)pTarget->GetInstanceData()) + { + 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); + } + } + } + } + return true; +} + +/*###### +## 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); + + // Start the intro event + if (Creature* pBrutallus = pInstance->GetSingleCreatureFromStorage(NPC_BRUTALLUS)) + { + if (boss_brutallusAI* pBossAI = dynamic_cast(pBrutallus->AI())) + pBossAI->DoStartIntro(); + } + } } return false; @@ -207,15 +512,20 @@ bool AreaTrigger_at_madrigosa(Player* pPlayer, AreaTriggerEntry const* pAt) void AddSC_boss_brutallus() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_brutallus"; - newscript->GetAI = &GetAI_boss_brutallus; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "at_madrigosa"; - newscript->pAreaTrigger = &AreaTrigger_at_madrigosa; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_brutallus"; + pNewScript->GetAI = &GetAI_boss_brutallus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "spell_dummy_npc_brutallus_cloud"; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_npc_brutallus_cloud; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_madrigosa"; + pNewScript->pAreaTrigger = &AreaTrigger_at_madrigosa; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp new file mode 100644 index 0000000000..4b0ba38168 --- /dev/null +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp @@ -0,0 +1,663 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_eredar_twins +SD%Complete: 75 +SDComment: A few spells are not working proper yet; Shadow image script needs improvement +SDCategory: Sunwell Plateau +EndScriptData */ + +#include "precompiled.h" +#include "sunwell_plateau.h" + +enum +{ + SAY_INTRO_1 = -1580044, + SAY_INTRO_2 = -1580045, + SAY_INTRO_3 = -1580046, + SAY_INTRO_4 = -1580047, + SAY_INTRO_5 = -1580048, + SAY_INTRO_6 = -1580049, + SAY_INTRO_7 = -1580050, + SAY_INTRO_8 = -1580051, + + SAY_SACROLASH_SHADOW_NOVA = -1580052, + SAY_SACROLASH_EMPOWER = -1580053, + SAY_SACROLASH_KILL_1 = -1580054, + SAY_SACROLASH_KILL_2 = -1580055, + SAY_SACROLASH_DEAD = -1580056, + SAY_SACROLASH_BERSERK = -1580057, + + SAY_ALYTHESS_CONFLAGRATION = -1580058, + SAY_ALYTHESS_EMPOWER = -1580059, + SAY_ALYTHESS_KILL_1 = -1580060, + SAY_ALYTHESS_KILL_2 = -1580061, + SAY_ALYTHESS_DEAD = -1580062, + SAY_ALYTHESS_BERSERK = -1580063, + + // Shared spells + SPELL_TWINS_ENRAGE = 46587, + SPELL_EMPOWER = 45366, // Cast on self when the twin sister dies + SPELL_DARK_FLAME = 45345, + + // Sacrolash spells + 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 + SPELL_CONFOUNDING_BLOW = 45256, // Daze; 25 secs + SPELL_SHADOW_NOVA_UNK = 45332, // Unknown + + // Shadow Image spells + NPC_SHADOW_IMAGE = 25214, + SPELL_SHADOWFURY = 45270, + SPELL_IMAGE_VISUAL = 45263, + + // Alythess spells + SPELL_PYROGENICS = 45230, // Self buff; 15secs + 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_BLAZE_SUMMON = 45236, //187366 GO // firepatch + SPELL_BLAZE_BURN = 45246, // used by GO + SPELL_FLAME_SEAR = 46771, // A few random targets debuff + SPELL_CONFLAGRATION_UNK = 45333, // Unknown +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_INTRO_1, NPC_SACROLASH, 1000}, + {SAY_INTRO_2, NPC_ALYTHESS, 1500}, + {SAY_INTRO_3, NPC_SACROLASH, 1500}, + {SAY_INTRO_4, NPC_ALYTHESS, 1500}, + {SAY_INTRO_5, NPC_SACROLASH, 1500}, + {SAY_INTRO_6, NPC_ALYTHESS, 1500}, + {SAY_INTRO_7, NPC_SACROLASH, 2500}, + {SAY_INTRO_8, NPC_ALYTHESS, 0}, + {0, 0, 0}, +}; + +/*###### +## boss_alythess +######*/ + +struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI +{ + boss_alythessAI(Creature* pCreature) : ScriptedAI(pCreature), + m_introDialogue(aIntroDialogue) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + m_introDialogue.InitializeDialogueHelper(m_pInstance); + Reset(); + } + + ScriptedInstance* m_pInstance; + DialogueHelper m_introDialogue; + + uint32 m_uiEnrageTimer; + uint32 m_uiPyrogenicsTimer; + uint32 m_uiConflagrationTimer; + uint32 m_uiBlazeTimer; + uint32 m_uiFlameSearTimer; + bool m_bDidIntro; + + void Reset() override + { + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; + m_uiPyrogenicsTimer = 20000; + m_uiConflagrationTimer = urand(25000, 30000); + m_uiBlazeTimer = 1000; + m_uiFlameSearTimer = 5000; + m_bDidIntro = false; + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_EREDAR_TWINS) != FAIL) + m_pInstance->SetData(TYPE_EREDAR_TWINS, FAIL); + + // Respawn dead sister + if (Creature* pSister = m_pInstance->GetSingleCreatureFromStorage(NPC_SACROLASH)) + { + if (!pSister->isAlive()) + pSister->Respawn(); + } + } + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_EREDAR_TWINS) != IN_PROGRESS) + m_pInstance->SetData(TYPE_EREDAR_TWINS, IN_PROGRESS); + } + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + // Only range attack + m_creature->GetMotionMaster()->MoveChase(pWho, 10.0f); + } + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_ALYTHESS_KILL_1 : SAY_ALYTHESS_KILL_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + if (Creature* pSacrolash = m_pInstance->GetSingleCreatureFromStorage(NPC_SACROLASH)) + { + if (!pSacrolash->isAlive()) + { + m_pInstance->SetData(TYPE_EREDAR_TWINS, DONE); + DoScriptText(SAY_ALYTHESS_DEAD, m_creature); + } + else + { + // Remove loot flag and cast empower + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + DoScriptText(SAY_SACROLASH_EMPOWER, pSacrolash); + pSacrolash->InterruptNonMeleeSpells(true); + pSacrolash->CastSpell(pSacrolash, SPELL_EMPOWER, false); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_EREDAR_TWINS) == SPECIAL) + { + if (!m_bDidIntro) + { + m_introDialogue.StartNextDialogueText(SAY_INTRO_1); + m_bDidIntro = true; + } + m_introDialogue.DialogueUpdate(uiDiff); + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWINS_ENRAGE) == CAST_OK) + { + DoScriptText(SAY_ALYTHESS_BERSERK, m_creature); + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiEnrageTimer -= uiDiff; + + if (m_uiPyrogenicsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PYROGENICS) == CAST_OK) + m_uiPyrogenicsTimer = urand(25000, 30000); + } + else + m_uiPyrogenicsTimer -= uiDiff; + + if (m_uiConflagrationTimer < uiDiff) + { + // If sister is dead cast shadownova instead of conflagration + bool bSwitchSpell = m_creature->HasAura(SPELL_EMPOWER); + Unit* pTarget = NULL; + + if (bSwitchSpell) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 2); + else + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 3); + + if (!pTarget) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + + if (DoCastSpellIfCan(pTarget, bSwitchSpell ? SPELL_SHADOW_NOVA : SPELL_CONFLAGRATION) == CAST_OK) + { + if (!bSwitchSpell) + { + DoScriptText(SAY_ALYTHESS_CONFLAGRATION, m_creature); + m_uiConflagrationTimer = urand(30000, 35000); + } + else + { + DoScriptText(SAY_SACROLASH_SHADOW_NOVA, m_creature); + m_uiConflagrationTimer = urand(20000, 25000); + } + } + } + else + m_uiConflagrationTimer -= uiDiff; + + if (m_uiFlameSearTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_SEAR) == CAST_OK) + m_uiFlameSearTimer = 10000; + } + else + m_uiFlameSearTimer -= uiDiff; + + if (m_uiBlazeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLAZE) == CAST_OK) + m_uiBlazeTimer = 3000; + } + else + m_uiBlazeTimer -= uiDiff; + } +}; + +/*###### +## boss_sacrolash +######*/ + +struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI +{ + boss_sacrolashAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiEnrageTimer; + uint32 m_uiDarkTouchedTimer; + uint32 m_uiShadowNovaTimer; + uint32 m_uiConfoundingBlowTimer; + uint32 m_uiShadowBladesTimer; + uint32 m_uiSummonShadowImage; + + void Reset() override + { + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; + m_uiDarkTouchedTimer = 30000; + m_uiShadowNovaTimer = 15000; + m_uiConfoundingBlowTimer = 30000; + m_uiShadowBladesTimer = 15000; + m_uiSummonShadowImage = 10000; + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_EREDAR_TWINS) != FAIL) + m_pInstance->SetData(TYPE_EREDAR_TWINS, FAIL); + + // Respawn dead sister + if (Creature* pSister = m_pInstance->GetSingleCreatureFromStorage(NPC_ALYTHESS)) + { + if (!pSister->isAlive()) + pSister->Respawn(); + } + } + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_EREDAR_TWINS) != IN_PROGRESS) + m_pInstance->SetData(TYPE_EREDAR_TWINS, IN_PROGRESS); + } + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SACROLASH_KILL_1 : SAY_SACROLASH_KILL_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + if (Creature* pAlythess = m_pInstance->GetSingleCreatureFromStorage(NPC_ALYTHESS)) + { + if (!pAlythess->isAlive()) + { + m_pInstance->SetData(TYPE_EREDAR_TWINS, DONE); + DoScriptText(SAY_SACROLASH_DEAD, m_creature); + } + else + { + // Remove loot flag and cast empower + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + DoScriptText(SAY_ALYTHESS_EMPOWER, pAlythess); + pAlythess->InterruptNonMeleeSpells(true); + pAlythess->CastSpell(pAlythess, SPELL_EMPOWER, false); + } + } + } + } + + // 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) + { + if (Unit* pTempTarget = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid())) + { + if (!pTempTarget->IsWithinDistInMap(m_creature, fDist)) + m_vRangeTargets.push_back(pTempTarget); + } + } + + if (!m_vRangeTargets.empty()) + return m_vRangeTargets[urand(0, m_vRangeTargets.size() - 1)]; + else + return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SHADOW_IMAGE) + { + pSummoned->CastSpell(pSummoned, SPELL_IMAGE_VISUAL, false); + // Attack random range target + if (Unit* pTarget = GetRandomTargetAtDist(10.0f)) + pSummoned->AI()->AttackStart(pTarget); + else + // Solo fight + if (Unit* pTarget = m_creature->getVictim()) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* spell) + { + switch(spell->Id) + { + case SPELL_SHADOW_BLADES: + case SPELL_SHADOW_NOVA: + case SPELL_CONFOUNDING_BLOW: + case SPELL_SHADOWFURY: + case SPELL_DARK_STRIKE: + HandleTouchedSpells(pTarget, SPELL_DARK_TOUCHED); + break; + case SPELL_CONFLAGRATION: + HandleTouchedSpells(pTarget, SPELL_FLAME_TOUCHED); + break; + } + } + + void HandleTouchedSpells(Unit* pTarget, uint32 TouchedType) + { + if (pTarget != m_creature->getVictim()) + return; + + switch(TouchedType) + { + case SPELL_FLAME_TOUCHED: + if (!pTarget->HasAura(SPELL_DARK_FLAME)) + { + 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); + } + break; + case SPELL_DARK_TOUCHED: + if (!pTarget->HasAura(SPELL_DARK_FLAME)) + { + 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); + } + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWINS_ENRAGE) == CAST_OK) + { + DoScriptText(SAY_SACROLASH_BERSERK, m_creature); + 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) + m_uiShadowBladesTimer = urand(13000, 15000); + } + else + m_uiShadowBladesTimer -= uiDiff; + + if (m_uiShadowNovaTimer < uiDiff) + { + // If sister is dead cast conflagration instead of shadownova + bool bSwitchSpell = m_creature->HasAura(SPELL_EMPOWER); + Unit* pTarget = NULL; + + if (bSwitchSpell) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 3); + else + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 2); + + if (!pTarget) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + + if (DoCastSpellIfCan(pTarget, bSwitchSpell ? SPELL_CONFLAGRATION : SPELL_SHADOW_NOVA) == CAST_OK) + { + if (!bSwitchSpell) + { + DoScriptText(SAY_SACROLASH_SHADOW_NOVA, m_creature); + m_uiShadowNovaTimer = urand(20000, 25000); + } + else + { + DoScriptText(SAY_ALYTHESS_CONFLAGRATION, m_creature); + m_uiShadowNovaTimer = urand(30000, 35000); + } + } + } + else + m_uiShadowNovaTimer -= uiDiff; + + if (m_uiConfoundingBlowTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONFOUNDING_BLOW) == CAST_OK) + { + // Reset threat + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -100); + + m_uiConfoundingBlowTimer = urand(25000, 30000); + } + } + else + m_uiConfoundingBlowTimer -= uiDiff; + + if (m_uiSummonShadowImage < uiDiff) + { + // Summon 3 shadow images at the boss position + 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); + } + else + m_uiSummonShadowImage -= uiDiff; + + // Overwrite the melee attack in order to apply the dark strike + 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)) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_STRIKE); + + m_creature->AttackerStateUpdate(m_creature->getVictim()); + m_creature->resetAttackTimer(); + } + } + } +}; + +/*###### +## npc_shadow_image +######*/ + +struct MANGOS_DLL_DECL npc_shadow_imageAI : public ScriptedAI +{ + npc_shadow_imageAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiChosenAbility; + uint32 m_uiSuicideTimer; + uint32 m_uiAbilityTimer; + uint8 m_uiDarkStrikes; + + void Reset() override + { + // Choose only one spell for attack + m_uiChosenAbility = urand(0, 1) ? SPELL_DARK_STRIKE : SPELL_SHADOWFURY; + m_uiAbilityTimer = 500; + m_uiDarkStrikes = 0; + m_uiSuicideTimer = 0; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Suicide on timer; this is needed because of the cast time + if (m_uiSuicideTimer) + { + if (m_uiSuicideTimer <= uiDiff) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + return; + } + else + m_uiSuicideTimer -= uiDiff; + } + else + { + // Do chosen ability + switch (m_uiChosenAbility) + { + case SPELL_SHADOWFURY: + if (m_uiAbilityTimer < uiDiff) + { + if (m_creature->IsWithinDistInMap(m_creature->getVictim(), INTERACTION_DISTANCE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOWFURY) == CAST_OK) + m_uiSuicideTimer = 1000; + } + } + else + m_uiAbilityTimer -= uiDiff; + break; + case SPELL_DARK_STRIKE: + if (m_uiAbilityTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_STRIKE) == CAST_OK) + { + ++m_uiDarkStrikes; + // kill itself after 2 strikes + if (m_uiDarkStrikes == 2) + m_uiSuicideTimer = 1000; + else + m_uiAbilityTimer = 1000; + } + } + else + m_uiAbilityTimer -= uiDiff; + break; + } + } + } +}; + +CreatureAI* GetAI_boss_alythess(Creature* pCreature) +{ + return new boss_alythessAI(pCreature); +} + +CreatureAI* GetAI_boss_sacrolash(Creature* pCreature) +{ + return new boss_sacrolashAI(pCreature); +} + +CreatureAI* GetAI_npc_shadow_image(Creature* pCreature) +{ + return new npc_shadow_imageAI(pCreature); +} + +void AddSC_boss_eredar_twins() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_alythess"; + pNewScript->GetAI = &GetAI_boss_alythess; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_sacrolash"; + pNewScript->GetAI = &GetAI_boss_sacrolash; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_shadow_image"; + pNewScript->GetAI = &GetAI_npc_shadow_image; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp new file mode 100644 index 0000000000..8fa8cb6869 --- /dev/null +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp @@ -0,0 +1,512 @@ +/* Copyright (C) 2006 - 2013 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_felmyst +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 +{ + SAY_INTRO = -1580036, + SAY_KILL_1 = -1580037, + SAY_KILL_2 = -1580038, + SAY_DEATH = -1580042, + 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 + SPELL_CLEAVE = 19983, + SPELL_CORROSION = 45866, + SPELL_GAS_NOVA = 45855, + SPELL_ENCAPSULATE = 45665, + SPELL_ENCAPSULATE_CHANNEL = 45661, + + // flight phase + SPELL_SUMMON_VAPOR = 45391, + 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 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, +}; + +/*###### +## boss_felmyst +######*/ + +struct MANGOS_DLL_DECL 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; + + // Ground Phase timers + uint32 m_uiFlyPhaseTimer; + uint32 m_uiCorrosionTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiEncapsulateTimer; + uint32 m_uiGasNovaTimer; + + // 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; + + // Ground Phase + m_uiCorrosionTimer = 30000; + m_uiCleaveTimer = urand(2000, 5000); + 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) override + { + if (!m_bHasTransformed) + { + if (pWho->GetTypeId() == TYPEID_PLAYER && pWho->IsWithinLOSInMap(m_creature) && pWho->IsWithinDistInMap(m_creature, 100.0f)) + { + DoScriptText(SAY_INTRO, m_creature); + m_bHasTransformed = true; + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void EnterEvadeMode() override + { + 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()) + { + 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) 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*/) override + { + DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FELMYST, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FELMYST, FAIL); + } + + 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) 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; + + 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_GROUND: + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(2000, 5000); + } + else + m_uiCleaveTimer -= 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_uiGasNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GAS_NOVA) == CAST_OK) + m_uiGasNovaTimer = 23000; + } + 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; + + 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; + } + } +}; + +CreatureAI* GetAI_boss_felmyst(Creature* pCreature) +{ + return new boss_felmystAI(pCreature); +} + +/*###### +## npc_demonic_vapor +######*/ + +struct MANGOS_DLL_DECL 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; + + pNewScript = new Script; + 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 f1c97d6e5a..ee970c84f6 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,127 +16,131 @@ /* ScriptData SDName: Boss_Kalecgos -SD%Complete: 40 -SDComment: Script must be considered not complete. +SD%Complete: 70 +SDComment: Timers; SDCategory: Sunwell Plateau EndScriptData */ #include "precompiled.h" #include "sunwell_plateau.h" -enum KalecgosEncounter +enum { - //kalecgos dragon form + // kalecgos dragon form SAY_EVIL_AGGRO = -1580000, - SAY_EVIL_SPELL1 = -1580001, - SAY_EVIL_SPELL2 = -1580002, - SAY_EVIL_SLAY1 = -1580003, - SAY_EVIL_SLAY2 = -1580004, + SAY_EVIL_SPELL_1 = -1580001, + SAY_EVIL_SPELL_2 = -1580002, + SAY_EVIL_SLAY_1 = -1580003, + SAY_EVIL_SLAY_2 = -1580004, SAY_EVIL_ENRAGE = -1580005, - //kalecgos humanoid form + // kalecgos humanoid form SAY_GOOD_AGGRO = -1580006, - SAY_GOOD_NEAR_DEATH = -1580007, - SAY_GOOD_NEAR_DEATH2 = -1580008, + SAY_GOOD_NEAR_DEATH_20 = -1580007, + SAY_GOOD_NEAR_DEATH_10 = -1580008, SAY_GOOD_PLRWIN = -1580009, SAY_SATH_AGGRO = -1580010, SAY_SATH_DEATH = -1580011, - SAY_SATH_SPELL1 = -1580012, - SAY_SATH_SPELL2 = -1580013, - SAY_SATH_SLAY1 = -1580014, - SAY_SATH_SLAY2 = -1580015, + SAY_SATH_SPELL_1 = -1580012, + SAY_SATH_SPELL_2 = -1580013, + SAY_SATH_SLAY_1 = -1580014, + SAY_SATH_SLAY_2 = -1580015, SAY_SATH_ENRAGE = -1580016, - //Kalecgos - SPELL_SPECTRAL_BLAST_DUMMY = 44869, - SPELL_SPECTRAL_BLAST = 44866, - + // Kalecgos + SPELL_SPECTRAL_BLAST = 44869, + 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, + SPELL_CRAZED_RAGE = 44807, + + // Kalecgos human SPELL_HEROIC_STRIKE = 45026, SPELL_REVITALIZE = 45027, - SPELL_TAIL_LASH = 45122, - SPELL_TRANSFORM_KALEC = 45027, - SPELL_CRAZED_RAGE = 44806, // this should be 44807 instead - //Sathrovarr - SPELL_SPECTRAL_INVIS = 44801, + // Sathrovarr + SPELL_SPECTRAL_INVISIBILITY = 44801, SPELL_CORRUPTING_STRIKE = 45029, SPELL_CURSE_OF_BOUNDLESS_AGONY = 45032, SPELL_SHADOW_BOLT_VOLLEY = 45031, - //Misc + // Misc SPELL_BANISH = 44836 }; -uint32 WildMagic[]= { 44978, 45001, 45002, 45004, 45006, 45010 }; - -const float KALECGOS_ARENA[3] = { 1704.34f, 928.17f, 53.08f }; +static const uint32 aWildMagicSpells[6] = {44978, 45001, 45002, 45004, 45006, 45010}; +static const float aKalecHumanLoc[4] = {1709.094f, 927.5035f, -74.28364f, 2.932153f}; -//#define NOTIFY_SPECTRALLY_EXHAUSTED "Your body is too exhausted to travel to the Spectral Realm." +/*###### +## boss_kalecgos +######*/ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI { boss_kalecgosAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - - /*if (pCreature->getFaction() != 14) - { - error_db_log("SD2: creature entry %u has faction %u but spellId %u requires different.", pCreature->GetEntry(), pCreature->getFaction(), SPELL_SPECTRAL_REALM_FORCE_FACTION); - pCreature->setFaction(14); - }*/ - + m_pInstance = (instance_sunwell_plateau*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; + instance_sunwell_plateau* m_pInstance; uint32 m_uiArcaneBuffetTimer; uint32 m_uiFrostBreathTimer; uint32 m_uiWildMagicTimer; uint32 m_uiSpectralBlastTimer; + uint32 m_uiTailLashTimer; uint32 m_uiExitTimer; - bool m_bUncorrupted; - bool m_bBanished; - bool m_bChecked; - bool m_bEnraged; - bool m_bHasSpectralTarget; + bool m_bIsUncorrupted; + bool m_bIsBanished; + bool m_bIsEnraged; - void Reset() + void Reset() override { m_uiArcaneBuffetTimer = 8000; + m_uiTailLashTimer = 5000; m_uiFrostBreathTimer = 24000; m_uiWildMagicTimer = 18000; m_uiSpectralBlastTimer = 30000; + m_uiExitTimer = 0; - m_uiExitTimer = 0; - - m_bUncorrupted = false; - m_bBanished = false; - m_bChecked = false; - m_bEnraged = false; - m_bHasSpectralTarget = false; + m_bIsUncorrupted = false; + m_bIsBanished = false; + m_bIsEnraged = false; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { - // Reset Sathrovarr too - if (Creature* pSath = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_SATHROVARR))) - { - if (pSath->isAlive() && pSath->getVictim()) - pSath->AI()->EnterEvadeMode(); - } + m_pInstance->DoEjectSpectralPlayers(); + m_pInstance->SetData(TYPE_KALECGOS, FAIL); + } + } - m_pInstance->SetData(TYPE_KALECGOS, NOT_STARTED); + void EnterEvadeMode() override + { + // Check if the boss is uncorrupted when evading + if (m_bIsUncorrupted) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + return; } + + ScriptedAI::EnterEvadeMode(); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_EVIL_AGGRO, m_creature); @@ -144,442 +148,435 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI m_pInstance->SetData(TYPE_KALECGOS, IN_PROGRESS); } - void DamageTaken(Unit* done_by, uint32 &damage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (damage >= m_creature->GetHealth() && done_by != m_creature) + if (uiDamage > m_creature->GetHealth()) { - if (!m_bUncorrupted) + uiDamage = 0; + + // If Sathrovarr is not banished yet, then banish the boss + if (!m_bIsUncorrupted) { - damage = 0; - m_bBanished = true; - DoCastSpellIfCan(m_creature, SPELL_BANISH, true); - m_creature->GetMotionMaster()->MoveIdle(); + if (DoCastSpellIfCan(m_creature, SPELL_BANISH, CAST_TRIGGERED) == CAST_OK) + m_bIsBanished = true; } else - { - damage = 0; - BeginOutro(); - } + DoStartOutro(); } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - DoScriptText(urand(0, 1) ? SAY_EVIL_SLAY1 : SAY_EVIL_SLAY2, m_creature); - } - - void SendToInnerVeil(Unit* pTarget) - { - if (m_pInstance) - { - //just a hack for not implemented spell effect 144 - ((Player*)pTarget)->TeleportTo(pTarget->GetMapId(), pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()-125.0f, pTarget->GetOrientation()); - - pTarget->CastSpell(pTarget, SPELL_SPECTRAL_REALM_FORCE_FACTION, true); - pTarget->CastSpell(pTarget, SPELL_SPECTRAL_REALM, true); - - m_pInstance->SetData64(DATA_PLAYER_SPECTRAL_REALM, pTarget->GetGUID()); - } - } - - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) - { - if (pSpell->Id == SPELL_SPECTRAL_BLAST_DUMMY && !m_bHasSpectralTarget) - { - if (pTarget->GetTypeId() != TYPEID_PLAYER) - return; - - if (pTarget->HasAura(SPELL_SPECTRAL_EXHAUSTION, EFFECT_INDEX_0) || pTarget->HasAura(SPELL_SPECTRAL_REALM)) - return; - - if (pTarget == m_creature->getVictim()) - return; - - m_bHasSpectralTarget = true; - pTarget->CastSpell(pTarget, SPELL_SPECTRAL_BLAST, true); - - SendToInnerVeil(pTarget); - } + DoScriptText(urand(0, 1) ? SAY_EVIL_SLAY_1 : SAY_EVIL_SLAY_2, m_creature); } - void BeginOutro() + void DoStartOutro() { - debug_log("SD2: KALEC: Beginning Outro"); - if (!m_pInstance) return; - if (Creature* pSathrovarr = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_SATHROVARR))) + // Bring Sathrovarr in the normal realm and kill him + if (Creature* pSathrovarr = m_pInstance->GetSingleCreatureFromStorage(NPC_SATHROVARR)) { - if (pSathrovarr->isAlive()) - { - pSathrovarr->NearTeleportTo(KALECGOS_ARENA[0], KALECGOS_ARENA[1], KALECGOS_ARENA[2], 0.0f); - pSathrovarr->DealDamage(pSathrovarr, pSathrovarr->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } + // The teleport spell doesn't work right for this, so we need to teleport him manually + pSathrovarr->NearTeleportTo(1704.34f, 928.17f, 53.08f, 0); + pSathrovarr->DealDamage(pSathrovarr, pSathrovarr->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } - if (Creature* pKalec = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_KALECGOS_HUMAN))) - { - pKalec->DeleteThreatList(); - pKalec->SetVisibility(VISIBILITY_OFF); - } + if (Creature* pKalec = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS_HUMAN)) + pKalec->ForcedDespawn(); + EnterEvadeMode(); + m_creature->SetFactionTemporary(35, TEMPFACTION_RESTORE_RESPAWN); m_creature->GetMotionMaster()->MoveIdle(); - m_creature->setFaction(35); DoScriptText(SAY_GOOD_PLRWIN, m_creature); - m_uiExitTimer = 1000; + m_uiExitTimer = 10000; } - void MovementInform(uint32 type, uint32 id) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { - if (type != POINT_MOTION_TYPE) + if (uiMotionType != POINT_MOTION_TYPE) return; - if (id) + if (uiPointId) { if (m_pInstance) m_pInstance->SetData(TYPE_KALECGOS, DONE); - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->ForcedDespawn(1000); } } - void UpdateAI(const uint32 diff) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override { - if (!m_creature->getVictim() || !m_creature->SelectHostileTarget() || m_bBanished) - return; + if (eventType == AI_EVENT_CUSTOM_A && m_pInstance) + m_pInstance->AddToSpectralRealm(pInvoker->GetObjectGuid()); + } - if (!m_bEnraged && m_creature->GetHealthPercent() < 10.0f) + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiExitTimer) { - if (Creature* pSathrovarr = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SATHROVARR))) + if (m_uiExitTimer <= uiDiff) { - if (pSathrovarr->isAlive()) - pSathrovarr->CastSpell(pSathrovarr, SPELL_CRAZED_RAGE, true); - } + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 30.0f, fX, fY, fZ); + fZ = 70.0f; - m_creature->CastSpell(m_creature, SPELL_CRAZED_RAGE, true); - m_bEnraged = true; + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_uiExitTimer = 0; + } + else + m_uiExitTimer -= uiDiff; } - if (!m_bChecked && m_creature->GetHealthPercent() < 1.0f) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bIsBanished) { - m_bChecked = true; + // When Sathrovarr is banished then start outro + if (m_bIsUncorrupted) + DoStartOutro(); - if (!m_bUncorrupted) - { - m_bBanished = true; - DoCastSpellIfCan(m_creature, SPELL_BANISH, true); - m_creature->GetMotionMaster()->MoveIdle(); - } - else - BeginOutro(); + // return when banished + return; } - if (m_uiExitTimer) + if (!m_bIsEnraged && m_creature->GetHealthPercent() < 10.0f) { - if (m_uiExitTimer <= diff) + // If the boss already has the aura, then mark the enraged as true + if (m_creature->HasAura(SPELL_CRAZED_RAGE)) + m_bIsEnraged = true; + else { - debug_log("SD2: KALEC: Exiting the arena"); - - float x, y, z; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 30, x, y, z); - - z = 70.0f; - - m_creature->GetMotionMaster()->MovePoint(1, x, y, z); - m_uiExitTimer = 0; - }else m_uiExitTimer -= diff; + // Spell is targeting both bosses + if (DoCastSpellIfCan(m_creature, SPELL_CRAZED_RAGE) == CAST_OK) + m_bIsEnraged = true; + } } - if (m_uiArcaneBuffetTimer < diff) + if (m_uiArcaneBuffetTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BUFFET) == CAST_OK) { if (!urand(0, 2)) - DoScriptText(SAY_EVIL_SPELL1, m_creature); + DoScriptText(SAY_EVIL_SPELL_1, m_creature); m_uiArcaneBuffetTimer = 20000; } } else - m_uiArcaneBuffetTimer -= diff; + m_uiArcaneBuffetTimer -= uiDiff; - if (m_uiFrostBreathTimer < diff) + if (m_uiFrostBreathTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_BREATH) == CAST_OK) { if (!urand(0, 1)) - DoScriptText(SAY_EVIL_SPELL2, m_creature); + DoScriptText(SAY_EVIL_SPELL_2, m_creature); m_uiFrostBreathTimer = 25000; } } else - m_uiFrostBreathTimer -= diff; + m_uiFrostBreathTimer -= uiDiff; - if (m_uiWildMagicTimer < diff) + if (m_uiTailLashTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, WildMagic[rand()%6]); + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(10000, 20000); + } + else + m_uiTailLashTimer -= uiDiff; - m_uiWildMagicTimer = 19000; + if (m_uiWildMagicTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, aWildMagicSpells[urand(0, 5)]) == CAST_OK) + m_uiWildMagicTimer = 19000; + } } else - m_uiWildMagicTimer -= diff; + m_uiWildMagicTimer -= uiDiff; - if (m_uiSpectralBlastTimer < diff) + if (m_uiSpectralBlastTimer < uiDiff) { - m_bHasSpectralTarget = false; - m_creature->CastSpell(m_creature, SPELL_SPECTRAL_BLAST_DUMMY, false); - m_uiSpectralBlastTimer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_SPECTRAL_BLAST) == CAST_OK) + m_uiSpectralBlastTimer = 25000; } else - m_uiSpectralBlastTimer -= diff; + m_uiSpectralBlastTimer -= uiDiff; - if (!m_bBanished) - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(); } }; +/*###### +## boss_sathrovarr +######*/ + struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI { boss_sathrovarrAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_sunwell_plateau*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; + instance_sunwell_plateau* m_pInstance; - uint32 CorruptingStrikeTimer; - uint32 CurseOfBoundlessAgonyTimer; - uint32 ShadowBoltVolleyTimer; - bool m_bBanished; - bool m_bEnraged; + uint32 m_uiCorruptingStrikeTimer; + uint32 m_uiCurseOfBoundlessAgonyTimer; + uint32 m_uiShadowBoltVolleyTimer; + bool m_bIsBanished; + bool m_bIsEnraged; - void Reset() + void Reset() override { // FIXME: Timers - CorruptingStrikeTimer = 5000; - CurseOfBoundlessAgonyTimer = 15000; - ShadowBoltVolleyTimer = 10000; + m_uiCorruptingStrikeTimer = 5000; + m_uiCurseOfBoundlessAgonyTimer = 15000; + m_uiShadowBoltVolleyTimer = 10000; - m_bBanished = false; - m_bEnraged = false; + m_bIsBanished = false; + m_bIsEnraged = false; - m_creature->CastSpell(m_creature, SPELL_SPECTRAL_INVIS, true); + DoCastSpellIfCan(m_creature, SPELL_SPECTRAL_INVISIBILITY); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_SATH_AGGRO, m_creature); if (!m_pInstance) return; - if (Creature* pKalec = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_KALECGOS_HUMAN))) - { - m_creature->AddThreat(pKalec, 10000000.0f); - pKalec->AddThreat(m_creature, 10000000.0f); - } + // 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* done_by, uint32 &damage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (damage > m_creature->GetHealth()) + if (uiDamage > m_creature->GetHealth()) { - damage = 0; - DoCastSpellIfCan(m_creature, SPELL_BANISH, CAST_TRIGGERED); - m_bBanished = true; + uiDamage = 0; + + if (m_bIsBanished) + return; - DoScriptText(SAY_SATH_DEATH, m_creature); + // banish Sathrovarr and eject the players + if (DoCastSpellIfCan(m_creature, SPELL_BANISH, CAST_TRIGGERED) == CAST_OK) + m_bIsBanished = true; if (!m_pInstance) return; - m_pInstance->SetData(DATA_SET_SPECTRAL_CHECK, 5000); - - if (Creature* pKalecgos = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_KALECGOS_DRAGON))) + if (Creature* pKalecgos = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON)) { if (boss_kalecgosAI* pKalecgosAI = dynamic_cast(pKalecgos->AI())) - { - pKalecgosAI->m_bChecked = false; - pKalecgosAI->m_bUncorrupted = true; - } + pKalecgosAI->m_bIsUncorrupted = true; + } + + m_pInstance->DoEjectSpectralPlayers(); + } + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(urand(0, 1) ? SAY_SATH_SLAY_1 : SAY_SATH_SLAY_2, m_creature); + + // !!! Workaround which ejects the players from the spectral realm on death !!! + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + pVictim->CastSpell(pVictim, SPELL_TELEPORT_NORMAL_REALM, true); + pVictim->CastSpell(pVictim, SPELL_SPECTRAL_EXHAUSTION, true); + } + } + + 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)) + { + if (!pWho->HasAura(SPELL_SPECTRAL_REALM_AURA)) + { + 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*/) override + { + DoScriptText(SAY_SATH_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_KALECGOS_HUMAN) + pSummoned->AI()->AttackStart(m_creature); } - void KilledUnit(Unit* victim) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override { - DoScriptText(urand(0, 1) ? SAY_SATH_SLAY1 : SAY_SATH_SLAY2, m_creature); + if (eventType == AI_EVENT_CUSTOM_A && m_pInstance) + m_pInstance->AddToSpectralRealm(pInvoker->GetObjectGuid()); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_creature->getVictim() || !m_creature->SelectHostileTarget() || m_bBanished) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bIsBanished) return; - if (!m_bEnraged && m_creature->GetHealthPercent() < 10.0f) + if (!m_bIsEnraged && m_creature->GetHealthPercent() < 10.0f) { - if (Creature* pKalecgos = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_KALECGOS_DRAGON))) + // If the boss already has the aura, then mark the enraged as true + if (m_creature->HasAura(SPELL_CRAZED_RAGE)) + m_bIsEnraged = true; + else { - if (pKalecgos->isAlive()) - pKalecgos->CastSpell(pKalecgos, SPELL_CRAZED_RAGE, true); + // Spell is targeting both bosses + if (DoCastSpellIfCan(m_creature, SPELL_CRAZED_RAGE) == CAST_OK) + m_bIsEnraged = true; } - - m_creature->CastSpell(m_creature, SPELL_CRAZED_RAGE, true); - m_bEnraged = true; } - if (CorruptingStrikeTimer < diff) + if (m_uiCorruptingStrikeTimer < uiDiff) { - if (!urand(0, 1)) - DoScriptText(SAY_SATH_SPELL2, m_creature); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORRUPTING_STRIKE) == CAST_OK) + { + if (!urand(0, 1)) + DoScriptText(SAY_SATH_SPELL_2, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORRUPTING_STRIKE); - CorruptingStrikeTimer = 13000; - }else CorruptingStrikeTimer -= diff; + m_uiCorruptingStrikeTimer = 13000; + } + } + else + m_uiCorruptingStrikeTimer -= uiDiff; - if (CurseOfBoundlessAgonyTimer < diff) + if (m_uiCurseOfBoundlessAgonyTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_CURSE_OF_BOUNDLESS_AGONY); - - CurseOfBoundlessAgonyTimer = 35000; - }else CurseOfBoundlessAgonyTimer -= diff; + { + if (DoCastSpellIfCan(pTarget, SPELL_CURSE_OF_BOUNDLESS_AGONY) == CAST_OK) + m_uiCurseOfBoundlessAgonyTimer = 35000; + } + } + else + m_uiCurseOfBoundlessAgonyTimer -= uiDiff; - if (ShadowBoltVolleyTimer < diff) + if (m_uiShadowBoltVolleyTimer < uiDiff) { - if (!urand(0, 1)) - DoScriptText(SAY_SATH_SPELL1, m_creature); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY) == CAST_OK) + { + if (!urand(0, 1)) + DoScriptText(SAY_SATH_SPELL_1, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); - ShadowBoltVolleyTimer = 15000; - }else ShadowBoltVolleyTimer -= diff; + m_uiShadowBoltVolleyTimer = 15000; + } + } + else + m_uiShadowBoltVolleyTimer -= uiDiff; DoMeleeAttackIfReady(); } }; +/*###### +## boss_kalecgos_humanoid +######*/ + struct MANGOS_DLL_DECL boss_kalecgos_humanoidAI : public ScriptedAI { boss_kalecgos_humanoidAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_sunwell_plateau*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; + instance_sunwell_plateau* m_pInstance; - uint32 RevitalizeTimer; - uint32 HeroicStrikeTimer; + uint32 m_uiRevitalizeTimer; + uint32 m_uiHeroicStrikeTimer; - bool HasYelled10Percent; - bool HasYelled20Percent; + bool m_bHasYelled10Percent; + bool m_bHasYelled20Percent; - void Reset() + void Reset() override { - //TODO: Times! - RevitalizeTimer = 30000; - HeroicStrikeTimer = 8000; + // TODO: Times! + m_uiRevitalizeTimer = 30000; + m_uiHeroicStrikeTimer = 8000; - HasYelled10Percent = false; - HasYelled20Percent = false; + m_bHasYelled10Percent = false; + m_bHasYelled20Percent = false; - m_creature->CastSpell(m_creature, SPELL_SPECTRAL_INVIS, true); + DoCastSpellIfCan(m_creature, SPELL_SPECTRAL_INVISIBILITY); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_GOOD_AGGRO, m_creature); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { - // Whatever happens when Kalec (Half-elf) dies + if (m_pInstance) + { + m_pInstance->DoEjectSpectralPlayers(); + m_pInstance->SetData(TYPE_KALECGOS, FAIL); + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_creature->getVictim() || !m_creature->SelectHostileTarget()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (RevitalizeTimer < diff) - { - if (m_pInstance) - { - /*Player* pPlayer = m_creature->GetMap()->GetPlayer(m_pInstance->GetData64(DATA_RANDOM_SPECTRAL_PLAYER)); - if (pPlayer) - DoCastSpellIfCan(pPlayer, SPELL_REVITALIZE);*/ - RevitalizeTimer = 30000; - } - }else RevitalizeTimer -= diff; - - if (HeroicStrikeTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEROIC_STRIKE); - HeroicStrikeTimer = 30000; - }else HeroicStrikeTimer -= diff; - - if (m_creature->GetHealthPercent() < 20.0f && !HasYelled20Percent) + if (m_uiRevitalizeTimer < uiDiff) { - DoScriptText(SAY_GOOD_NEAR_DEATH, m_creature); - HasYelled20Percent = true; + // Cast on self because spell has target "all friendly units around the caster" + if (DoCastSpellIfCan(m_creature, SPELL_REVITALIZE) == CAST_OK) + m_uiRevitalizeTimer = 30000; } + else + m_uiRevitalizeTimer -= uiDiff; - if (m_creature->GetHealthPercent() < 10.0f && !HasYelled10Percent) + if (m_uiHeroicStrikeTimer < uiDiff) { - DoScriptText(SAY_GOOD_NEAR_DEATH2, m_creature); - HasYelled10Percent = true; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEROIC_STRIKE) == CAST_OK) + m_uiHeroicStrikeTimer = 30000; } - } -}; - -bool GOHello_go_spectral_rift(Player* pPlayer, GameObject* pGo) -{ - if (pGo->GetGoType() != GAMEOBJECT_TYPE_GOOBER) - return true; - - if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) - { - if (pPlayer->HasAura(SPELL_SPECTRAL_EXHAUSTION, EFFECT_INDEX_0)) - return true; - - // Make them able to see Sathrovarr (he's invisible for some reason). Also, when this buff wears off, they get teleported back to Normal Realm (this is handled by Instance Script) - pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_TO_SPECTRAL_REALM, true); - pPlayer->CastSpell(pPlayer, SPELL_SPECTRAL_REALM_FORCE_FACTION, true); - pPlayer->CastSpell(pPlayer, SPELL_SPECTRAL_REALM, true); + else + m_uiHeroicStrikeTimer -= uiDiff; - // Add player to pSath's threat list - /*if (Creature* pSath = pInstance->instance->GetCreature(pInstance->GetData64(DATA_KALECGOS_DRAGON))) + if (m_creature->GetHealthPercent() < 20.0f && !m_bHasYelled20Percent) { - if (pSath->isAlive()) - { - debug_log("SD2: Adding %s in pSath' threatlist", pPlayer->GetName()); - pSath->AddThreat(pPlayer); - } + DoScriptText(SAY_GOOD_NEAR_DEATH_20, m_creature); + m_bHasYelled20Percent = true; } - // Remove player from Sathrovarr's threat list - if (Creature* pKalecgos = pInstance->instance->GetCreature(pInstance->GetData64(DATA_SATHROVARR))) + if (m_creature->GetHealthPercent() < 10.0f && !m_bHasYelled10Percent) { - if (pKalecgos->isAlive()) - { - if (HostileReference* pRef = pKalecgos->getThreatManager().getOnlineContainer().getReferenceByTarget(pPlayer)) - { - pRef->removeReference(); - debug_log("SD2: Deleting %s from pKalecgos's threatlist", pPlayer->GetName()); - } - } - }*/ + DoScriptText(SAY_GOOD_NEAR_DEATH_10, m_creature); + m_bHasYelled10Percent = true; + } - pInstance->SetData64(DATA_PLAYER_SPECTRAL_REALM, pPlayer->GetGUID()); + DoMeleeAttackIfReady(); } - - return true; -} +}; CreatureAI* GetAI_boss_kalecgos(Creature* pCreature) { @@ -596,27 +593,38 @@ 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* newscript; - - newscript = new Script; - newscript->GetAI = &GetAI_boss_kalecgos; - newscript->Name = "boss_kalecgos"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_sathrovarr; - newscript->Name = "boss_sathrovarr"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->GetAI = &GetAI_boss_kalecgos_humanoid; - newscript->Name = "boss_kalecgos_humanoid"; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->pGOHello = &GOHello_go_spectral_rift; - newscript->Name = "go_spectral_rift"; - newscript->RegisterSelf(); + Script* pNewScript; + + 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 new file mode 100644 index 0000000000..c1826bd466 --- /dev/null +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp @@ -0,0 +1,882 @@ +/* Copyright (C) 2006 - 2013 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_kiljaeden +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_EMERGE = -1580069, + SAY_SLAY_1 = -1580070, + SAY_SLAY_2 = -1580071, + SAY_REFLECTION_1 = -1580072, + SAY_REFLECTION_2 = -1580073, + SAY_DARKNESS_1 = -1580074, + SAY_DARKNESS_2 = -1580075, + SAY_DARKNESS_3 = -1580076, + SAY_PHASE_3 = -1580077, + SAY_PHASE_4 = -1580078, + SAY_PHASE_5 = -1580079, + SAY_KALECGOS_INTRO = -1580080, + SAY_KALECGOS_AWAKE_1 = -1580081, + SAY_ANVEENA_IMPRISONED = -1580082, + SAY_KALECGOS_AWAKE_2 = -1580083, + SAY_ANVEENA_LOST = -1580084, + SAY_KALECGOS_AWAKE_4 = -1580085, + SAY_ANVEENA_AWAKE = -1580086, + SAY_KALECGOS_AWAKE_5 = -1580087, + SAY_ANVEENA_SACRIFICE = -1580088, + SAY_KALECGOS_GOODBYE = -1580089, + SAY_KALECGOS_ENCOURAGE = -1580090, + SAY_KALECGOS_ORB_1 = -1580091, + SAY_KALECGOS_ORB_2 = -1580092, + SAY_KALECGOS_ORB_3 = -1580093, + SAY_KALECGOS_ORB_4 = -1580094, + + // outro + SAY_OUTRO_1 = -1580095, // Velen + SAY_OUTRO_2 = -1580096, + SAY_OUTRO_3 = -1580097, + SAY_OUTRO_4 = -1580098, + SAY_OUTRO_5 = -1580099, // Liadrin + SAY_OUTRO_6 = -1580100, // Velen + SAY_OUTRO_7 = -1580101, // Liadrin + SAY_OUTRO_8 = -1580102, // Velen + SAY_OUTRO_9 = -1580103, + SAY_OUTRO_10 = -1580104, // Liadrin + SAY_OUTRO_11 = -1580105, // Velen + SAY_OUTRO_12 = -1580106, + + // generic spells + SPELL_BIRTH = 37745, // Kiljaeden spawn animation + + // transition spells + SPELL_DESTROY_DRAKES = 46707, + SPELL_SINISTER_REFLECTION = 45892, + SPELL_SHADOW_SPIKE = 46680, + + // phase 1 + SPELL_SOUL_FLY = 45442, + SPELL_LEGION_LIGHTING = 45664, + SPELL_FIRE_BLOOM = 45641, + + // phase 2 + SPELL_FLAME_DART = 45740, + SPELL_DARKNESS_OF_SOULS = 46605, + + // phase 3 + SPELL_ARMAGEDDON = 45921, // used from 50% hp - summons 25735 on target location + + // Npc spells + SPELL_SHADOW_BOLT_AURA = 45679, // periodic aura on shield orbs + 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, // npc handled by eventAI + NPC_BLUE_ORB_TARGET = 25640, // dummy npc near gameobjects 187869, 188114, 188115, 188116 + + // phases + PHASE_INFERNO = 1, + PHASE_DARKNESS = 2, + PHASE_ARMAGEDDON = 3, + PHASE_SACRIFICE = 4, + PHASE_TRANSITION = 5, + + // dummy members, used in the phase switch event + EVENT_SWITCH_PHASE_2 = 6, + EVENT_SWITCH_PHASE_3 = 7, + EVENT_SWITCH_PHASE_4 = 8, + EVENT_DRAGON_ORB = 9, + + // outro + 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_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, + + POINT_SUMMON_SOLDIERS = 1, + POINT_MOVE_LIADRIN = 2, + POINT_EVENT_EXIT = 3, +}; + +// Encounter phase dialogue +static const DialogueEntry aPhaseDialogue[] = +{ + {PHASE_DARKNESS, 0, 2000}, + {EVENT_SWITCH_PHASE_2, 0, 17000}, + {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 + {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 + {PHASE_SACRIFICE, 0, 2000}, + {EVENT_SWITCH_PHASE_4, 0, 5000}, + {SAY_KALECGOS_AWAKE_4, NPC_KALECGOS, 10000}, + {SAY_ANVEENA_AWAKE, NPC_ANVEENA, 2000}, + {SAY_KALECGOS_AWAKE_5, NPC_KALECGOS, 6000}, + {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 + {0, 0, 0}, +}; + +// Epilogue dialogue +static const DialogueEntry aOutroDialogue[] = +{ + {NPC_KALECGOS, 0, 15000}, + {SAY_KALECGOS_GOODBYE, NPC_KALECGOS, 40000}, + {NPC_INERT_PORTAL, 0, 10000}, + {POINT_SUMMON_SOLDIERS, 0, 18000}, + {NPC_VELEN, 0, 1000}, + {NPC_LIADRIN, 0, 4000}, + {SAY_OUTRO_1, NPC_VELEN, 25000}, + {SAY_OUTRO_2, NPC_VELEN, 15000}, + {SAY_OUTRO_3, NPC_VELEN, 13000}, + {SPELL_CALL_ENTROPIUS, 0, 10000}, + {SAY_OUTRO_4, NPC_VELEN, 20000}, + {POINT_MOVE_LIADRIN, 0, 5000}, + {SAY_OUTRO_5, NPC_LIADRIN, 10000}, + {SAY_OUTRO_6, NPC_VELEN, 15000}, + {SAY_OUTRO_7, NPC_LIADRIN, 3000}, + {SAY_OUTRO_8, NPC_VELEN, 4000}, + {SPELL_BLAZE_TO_LIGHT, 0, 13000}, + {SAY_OUTRO_9, NPC_VELEN, 14000}, + {SAY_OUTRO_10, NPC_LIADRIN, 20000}, + {SAY_OUTRO_11, NPC_VELEN, 8000}, + {SAY_OUTRO_12, NPC_VELEN, 4000}, + {POINT_EVENT_EXIT, 0, 0}, + {0, 0, 0}, +}; + +static const EventLocations aOutroLocations[] = +{ + {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 + {1698.946f, 628.206f, 83.003f, 0.76f}, // entropius core summon loc +}; + +// 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 MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI, private DialogueHelper +{ + npc_kiljaeden_controllerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature), + DialogueHelper(aOutroDialogue) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + ObjectGuid m_EntropiusGuid; + ObjectGuid m_PortalGuid; + + void Reset() override + { + // Visual spell before the encounter starts + DoCastSpellIfCan(m_creature, SPELL_ANVEENA_DRAIN); + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + 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, aOutroLocations[5].m_fX, aOutroLocations[5].m_fY, aOutroLocations[5].m_fZ, aOutroLocations[5].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + case NPC_INERT_PORTAL: + // ToDo: summon soldiers to the right + 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 + break; + case NPC_VELEN: + 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); + break; + case SPELL_CALL_ENTROPIUS: + if (Creature* pVelen = m_pInstance->GetSingleCreatureFromStorage(NPC_VELEN)) + pVelen->CastSpell(pVelen, SPELL_CALL_ENTROPIUS, false); + // Set point id = 1 for movement event + if (Creature* pEntropius = m_creature->GetMap()->GetCreature(m_EntropiusGuid)) + { + pEntropius->SetWalk(false); + pEntropius->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX(), m_creature->GetPositionY(), 35.0f); + } + break; + case POINT_MOVE_LIADRIN: + if (Creature* pLiadrin = m_pInstance->GetSingleCreatureFromStorage(NPC_LIADRIN)) + pLiadrin->GetMotionMaster()->MovePoint(0, aOutroLocations[4].m_fX, aOutroLocations[4].m_fY, aOutroLocations[4].m_fZ); + break; + case SPELL_BLAZE_TO_LIGHT: + if (Creature* pEntropius = m_creature->GetMap()->GetCreature(m_EntropiusGuid)) + { + pEntropius->CastSpell(pEntropius, SPELL_BLAZE_TO_LIGHT, true); + pEntropius->RemoveAurasDueToSpell(SPELL_ENTROPIUS_BODY); + pEntropius->SetWalk(true); + pEntropius->GetMotionMaster()->MovePoint(2, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + } + break; + case POINT_EVENT_EXIT: + // Set point id = 1 for the despawn event + if (Creature* pVelen = m_pInstance->GetSingleCreatureFromStorage(NPC_VELEN)) + pVelen->GetMotionMaster()->MovePoint(1, aOutroLocations[1].m_fX, aOutroLocations[1].m_fY, aOutroLocations[1].m_fZ); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_VELEN: + pSummoned->GetMotionMaster()->MovePoint(0, aOutroLocations[3].m_fX, aOutroLocations[3].m_fY, aOutroLocations[3].m_fZ); + // no break here + case NPC_LIADRIN: + pSummoned->CastSpell(pSummoned, SPELL_TELEPORT_VISUAL, true); + break; + case NPC_CORE_ENTROPIUS: + pSummoned->CastSpell(pSummoned, SPELL_ENTROPIUS_BODY, true); + pSummoned->SetLevitate(true); + m_EntropiusGuid = pSummoned->GetObjectGuid(); + break; + case NPC_INERT_PORTAL: + m_PortalGuid = pSummoned->GetObjectGuid(); + pSummoned->CastSpell(pSummoned, SPELL_ARCANE_PORTAL, true); + break; + } + } + + 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; + + if (uiPointId == 1) + { + if (pSummoned->GetEntry() == NPC_CORE_ENTROPIUS) + { + // Interrupt Velen's casting when entropius has reached the ground + if (Creature* pVelen = m_pInstance->GetSingleCreatureFromStorage(NPC_VELEN)) + pVelen->InterruptNonMeleeSpells(false); + } + else if (pSummoned->GetEntry() == NPC_VELEN) + { + // Cast teleport and despawn Velen, the portal and Kalec; Liadrin will despawn on timer + pSummoned->CastSpell(pSummoned, SPELL_TELEPORT_VISUAL, true); + pSummoned->ForcedDespawn(1000); + + // Note: portal should despawn only after all the soldiers have reached this point and "teleported" outside + if (Creature* pPortal = m_creature->GetMap()->GetCreature(m_PortalGuid)) + pPortal->ForcedDespawn(5000); + + if (Creature* pKalec = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS)) + pKalec->ForcedDespawn(1000); + } + } + else if (uiPointId == 2 && pSummoned->GetEntry() == NPC_CORE_ENTROPIUS) + { + // When the purified Muru reaches the ground the sunwell ignites and Muru despawns + DoCastSpellIfCan(m_creature, SPELL_SUNWELL_IGNITION); + + if (Creature* pLiadrin = m_pInstance->GetSingleCreatureFromStorage(NPC_LIADRIN)) + pLiadrin->SetStandState(UNIT_STAND_STATE_KNEEL); + + pSummoned->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + } +}; + +/*###### +## boss_kiljaeden +######*/ + +struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private DialogueHelper +{ + boss_kiljaedenAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature), + DialogueHelper(aPhaseDialogue) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiMaxShieldOrbs; + uint8 m_uiShieldOrbCount; + + uint32 m_uiKalecSummonTimer; + + uint32 m_uiSoulFlyTimer; + uint32 m_uiLegionLightingTimer; + uint32 m_uiFireBloomTimer; + uint32 m_uiShieldOrbTimer; + + uint32 m_uiFlameDartTimer; + uint32 m_uiDarknessOfSoulsTimer; + + uint32 m_uiArmageddonTimer; + + void Reset() override + { + m_uiPhase = PHASE_INFERNO; + m_uiKalecSummonTimer = 35000; + m_uiMaxShieldOrbs = 1; + m_uiShieldOrbCount = 0; + + m_uiSoulFlyTimer = 10000; + m_uiLegionLightingTimer = urand(10000, 15000); + m_uiFireBloomTimer = urand(15000, 20000); + m_uiShieldOrbTimer = 30000; + + m_uiFlameDartTimer = urand(20000, 25000); + m_uiDarknessOfSoulsTimer = urand(45000, 50000); + + m_uiArmageddonTimer = 20000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KILJAEDEN, IN_PROGRESS); + + DoScriptText(SAY_EMERGE, m_creature); + DoCastSpellIfCan(m_creature, SPELL_BIRTH); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_KILJAEDEN, FAIL); + + // Reset the corrupt Sunwell aura + if (Creature* pKiljaedenController = m_pInstance->GetSingleCreatureFromStorage(NPC_KILJAEDEN_CONTROLLER)) + pKiljaedenController->CastSpell(pKiljaedenController, SPELL_ANVEENA_DRAIN, true); + } + + // Despawn on wipe + m_creature->ForcedDespawn(); + } + + 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*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KILJAEDEN, DONE); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_KALECGOS) + { + DoScriptText(SAY_KALECGOS_INTRO, pSummoned); + 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 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) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case PHASE_DARKNESS: + case PHASE_ARMAGEDDON: + case PHASE_SACRIFICE: + if (DoCastSpellIfCan(m_creature, SPELL_SINISTER_REFLECTION, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(irand(0, 1) ? SAY_REFLECTION_1 : SAY_REFLECTION_2, m_creature); + + // In the 2nd and 3rd transition kill all drakes + if (iEntry == PHASE_ARMAGEDDON || iEntry == PHASE_SACRIFICE) + DoCastSpellIfCan(m_creature, SPELL_DESTROY_DRAKES, CAST_TRIGGERED); + + m_uiPhase = PHASE_TRANSITION; + // Darkness of Souls needs the timer reseted + m_uiDarknessOfSoulsTimer = iEntry == PHASE_SACRIFICE ? 30000 : 45000; + } + break; + case EVENT_SWITCH_PHASE_2: + case EVENT_SWITCH_PHASE_3: + case EVENT_SWITCH_PHASE_4: + 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); + DoActivateDragonOrb(GO_ORB_BLUE_FLIGHT_2); + break; + case SAY_KALECGOS_ORB_1: + DoActivateDragonOrb(GO_ORB_BLUE_FLIGHT_1); + break; + case SAY_KALECGOS_ORB_4: + 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); + pAnveena->CastSpell(pAnveena, SPELL_SACRIFICE_ANVEENA, true); + pAnveena->ForcedDespawn(3000); + } + m_uiPhase = PHASE_SACRIFICE; + break; + } + } + + // 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; + + DialogueUpdate(uiDiff); + + switch (m_uiPhase) + { + case PHASE_TRANSITION: + // Transition phase is handled in the dialogue helper; however we don't want the spell timers to be decreased so we use a specific phase + break; + case PHASE_SACRIFICE: + // Final phase - use the same spells + // no break; + case PHASE_ARMAGEDDON: + + // In the last phase he uses Armageddon continuously + if (m_uiArmageddonTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ARMAGEDDON) == CAST_OK) + m_uiArmageddonTimer = m_uiPhase == PHASE_SACRIFICE ? 20000 : 30000; + } + else + m_uiArmageddonTimer -= uiDiff; + + // Go to next phase and start transition dialogue + if (m_uiPhase == PHASE_ARMAGEDDON && m_creature->GetHealthPercent() < 25.0f) + StartNextDialogueText(PHASE_SACRIFICE); + + // no break - use the spells from the phases below; + case PHASE_DARKNESS: + + // In the last phase he uses this spell more often + if (m_uiDarknessOfSoulsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARKNESS_OF_SOULS) == CAST_OK) + m_uiDarknessOfSoulsTimer = m_uiPhase == PHASE_SACRIFICE ? 30000 : 45000; + } + else + m_uiDarknessOfSoulsTimer -= uiDiff; + + if (m_uiFlameDartTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_DART) == CAST_OK) + m_uiFlameDartTimer = urand(25000, 30000); + } + else + m_uiFlameDartTimer -= uiDiff; + + // Go to next phase and start transition dialogue + if (m_uiPhase == PHASE_DARKNESS && m_creature->GetHealthPercent() < 55.0f) + StartNextDialogueText(PHASE_ARMAGEDDON); + + // no break - use the spells from the phase below; + case PHASE_INFERNO: + + if (m_uiKalecSummonTimer) + { + if (m_uiKalecSummonTimer <= uiDiff) + { + m_creature->SummonCreature(NPC_KALECGOS, aKalegSpawnLoc[0], aKalegSpawnLoc[1], aKalegSpawnLoc[2], aKalegSpawnLoc[3], TEMPSUMMON_CORPSE_DESPAWN, 0); + m_uiKalecSummonTimer = 0; + } + else + m_uiKalecSummonTimer -= uiDiff; + } + + if (m_uiLegionLightingTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_LEGION_LIGHTING) == CAST_OK) + m_uiLegionLightingTimer = urand(10000, 15000); + } + } + else + m_uiLegionLightingTimer -= uiDiff; + + if (m_uiFireBloomTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FIRE_BLOOM) == CAST_OK) + m_uiFireBloomTimer = 20000; + } + else + m_uiFireBloomTimer -= uiDiff; + + if (m_uiSoulFlyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_FLY) == CAST_OK) + m_uiSoulFlyTimer = urand(3000, 10000); + } + 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); + + DoMeleeAttackIfReady(); + + break; + } + } +}; + +bool EffectAuraDummy_spell_aura_dummy_darkness_of_souls(const Aura* pAura, bool bApply) +{ + // On Aura removal cast the explosion and yell + // This is a special case when the dummy effect should be triggered at the end of the channeling + if (pAura->GetId() == SPELL_DARKNESS_OF_SOULS && pAura->GetEffIndex() == EFFECT_INDEX_0 && !bApply) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + pTarget->CastSpell(pTarget, pAura->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2), true); + + 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; + } + } + } + return true; +} + +/*###### +## npc_shield_orb +######*/ + +struct MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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) +{ + 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->GetAI = &GetAI_boss_kiljaeden; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_darkness_of_souls; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 new file mode 100644 index 0000000000..efcc60ae9f --- /dev/null +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp @@ -0,0 +1,608 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_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 +SDCategory: Sunwell Plateau +EndScriptData */ + +#include "precompiled.h" +#include "sunwell_plateau.h" + +enum +{ + // muru spells + SPELL_NEGATIVE_ENERGY = 46009, + SPELL_DARKNESS = 45996, // big void zone; at 45 sec + SPELL_OPEN_PORTAL_PERIODIC = 45994, // periodic spell which opens a portal at 30 secs; triggers 45976 + SPELL_OPEN_PORTAL = 45976, // has muru portal as target + SPELL_SUMMON_BERSERKER_1 = 46037, // humanoids summoned at 15 secs (3 on each side) then after 60 secs + SPELL_SUMMON_BERSERKER_2 = 46040, // there are two spells. one for each side + SPELL_SUMMON_FURY_MAGE_1 = 46038, + SPELL_SUMMON_FURY_MAGE_2 = 46039, + + SPELL_SUMMON_DARK_FIEND_1 = 46000, // summons 8 dark fiends (25744); ToDo: script npc in eventAI + SPELL_SUMMON_DARK_FIEND_2 = 46001, + SPELL_SUMMON_DARK_FIEND_3 = 46002, + SPELL_SUMMON_DARK_FIEND_4 = 46003, + SPELL_SUMMON_DARK_FIEND_5 = 46004, + SPELL_SUMMON_DARK_FIEND_6 = 46005, + SPELL_SUMMON_DARK_FIEND_7 = 46006, + SPELL_SUMMON_DARK_FIEND_8 = 46007, + + //Dark Fiend + SPELL_DARK_FIEND = 45934, + SPELL_DARK_FIEND_DMG = 45944, + + // transition + SPELL_OPEN_ALL_PORTALS = 46177, // dummy spell which opens all the portals to begin the transition phase - has muru portal as target + SPELL_SUMMON_ENTROPIUS = 46217, + SPELL_ENTROPIUS_SPAWN = 46223, // visual effect after spawn + + // entropius spells + SPELL_NEGATIVE_ENERGY_ENT = 46284, // periodic aura spell; triggers 46289 which has script effect. Damage spell is 46285 but it needs core support + SPELL_SUMMON_BLACK_HOLE = 46282, // 15 sec cooldown; summons 25855 + 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_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 + + MAX_TRANSFORM_CASTS = 10 +}; + +/*###### +## boss_muru +######*/ + +struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI +{ + boss_muruAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + uint32 m_uiDarknessTimer; + uint32 m_uiSummonHumanoidsTimer; + uint32 m_uiDarkFiendsTimer; + bool m_bIsTransition; + + void Reset() override + { + m_uiDarknessTimer = 45000; + m_uiSummonHumanoidsTimer = 15000; + m_uiDarkFiendsTimer = 0; + m_bIsTransition = false; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MURU, IN_PROGRESS); + + DoCastSpellIfCan(m_creature, SPELL_NEGATIVE_ENERGY, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_OPEN_PORTAL_PERIODIC, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MURU, FAIL); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + { + uiDamage = 0; + + if (!m_bIsTransition) + { + // Start transition + if (DoCastSpellIfCan(m_creature, SPELL_OPEN_ALL_PORTALS) == CAST_OK) + { + // remove the auras + m_creature->RemoveAurasDueToSpell(SPELL_NEGATIVE_ENERGY); + m_creature->RemoveAurasDueToSpell(SPELL_OPEN_PORTAL_PERIODIC); + m_bIsTransition = true; + } + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_ENTROPIUS: + // Cast the Entropius spawn effect and force despawn + pSummoned->CastSpell(pSummoned, SPELL_ENTROPIUS_SPAWN, true); + m_creature->ForcedDespawn(1000); + // no break here; All other summons should behave the same way + default: + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + } + } + + // Wrapper for summoning the humanoids + void DoSummonHumanoids() + { + // summon 2 berserkers and 1 fury mage on each side + for (uint8 i = 0; i < 2; i++) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_BERSERKER_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_BERSERKER_2, CAST_TRIGGERED); + } + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_FURY_MAGE_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_FURY_MAGE_2, CAST_TRIGGERED); + } + + // Wrapper for summoning the dark fiends + void DoSummonDarkFiends() + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_3, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_4, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_5, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_6, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_7, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_8, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Return if already in transition + if (m_bIsTransition) + return; + + if (m_uiDarknessTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARKNESS) == CAST_OK) + { + m_uiDarknessTimer = 45000; + m_uiDarkFiendsTimer = 4000; // in about 4 secs after darkness + } + } + else + m_uiDarknessTimer -= uiDiff; + + if (m_uiDarkFiendsTimer) + { + if (m_uiDarkFiendsTimer <= uiDiff) + { + DoSummonDarkFiends(); + m_uiDarkFiendsTimer = 0; + } + else + m_uiDarkFiendsTimer -= uiDiff; + } + + if (m_uiSummonHumanoidsTimer < uiDiff) + { + DoSummonHumanoids(); + m_uiSummonHumanoidsTimer = 1 * MINUTE * IN_MILLISECONDS; + } + else + m_uiSummonHumanoidsTimer -= uiDiff; + } +}; + +/*###### +## boss_entropius +######*/ + +struct MANGOS_DLL_DECL boss_entropiusAI : public ScriptedAI +{ + boss_entropiusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + uint32 m_uiBlackHoleTimer; + uint32 m_uiDarknessTimer; + + GuidList m_lSummonedCreaturesList; + + void Reset() override + { + m_uiBlackHoleTimer = 15000; + m_uiDarknessTimer = 20000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_NEGATIVE_ENERGY_ENT); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MURU, DONE); + + // Despawn summoned creatures + DespawnSummonedCreatures(); + } + + void JustSummoned(Creature* pSummoned) override + { + // 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() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_MURU, FAIL); + + // respawn muru + if (Creature* pMuru = m_pInstance->GetSingleCreatureFromStorage(NPC_MURU)) + pMuru->Respawn(); + } + + // despawn boss and summons for reset + DespawnSummonedCreatures(); + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBlackHoleTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SUMMON_BLACK_HOLE) == CAST_OK) + m_uiBlackHoleTimer = 15000; + } + } + else + m_uiBlackHoleTimer -= uiDiff; + + if (m_uiDarknessTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SUMMON_DARKNESS) == CAST_OK) + m_uiDarknessTimer = urand(15000, 20000); + } + } + else + m_uiDarknessTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_portal_target +######*/ + +struct MANGOS_DLL_DECL npc_portal_targetAI : public Scripted_NoMovementAI +{ + npc_portal_targetAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + uint8 m_uiTransformCount; + uint32 m_uiTransformTimer; + uint32 m_uiSentinelTimer; + + void Reset() override + { + m_uiTransformCount = 0; + m_uiTransformTimer = 0; + m_uiSentinelTimer = 0; + } + + 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) 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 + case SPELL_OPEN_PORTAL: + m_uiSentinelTimer = 5000; + break; + // Start transition effect + case SPELL_OPEN_ALL_PORTALS: + m_uiTransformTimer = 2000; + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSentinelTimer) + { + // Summon the sentinel on a short timer after the portal opens + if (m_uiSentinelTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SENTINEL_SUMMONER) == CAST_OK) + m_uiSentinelTimer = 0; + } + else + m_uiSentinelTimer -= uiDiff; + } + + if (m_uiTransformTimer) + { + if (m_uiTransformTimer <= uiDiff) + { + // Alternate the visuals + ++m_uiTransformCount; + 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; + else + { + m_uiTransformTimer = 0; + m_uiTransformCount = 0; + } + + // Summon Entropius when reached half of the transition + if (m_uiTransformCount == MAX_TRANSFORM_CASTS / 2) + { + if (Creature* pMuru = m_pInstance->GetSingleCreatureFromStorage(NPC_MURU)) + pMuru->CastSpell(pMuru, SPELL_SUMMON_ENTROPIUS, false); + } + } + else + m_uiTransformTimer -= uiDiff; + } + } +}; + +/*###### +## npc_void_sentinel_summoner +######*/ + +struct MANGOS_DLL_DECL npc_void_sentinel_summonerAI : public Scripted_NoMovementAI +{ + npc_void_sentinel_summonerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + void Reset() override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_VOID_SENTINEL) + { + // Attack Muru's target + if (Creature* pMuru = m_pInstance->GetSingleCreatureFromStorage(NPC_MURU)) + { + if (Unit* pTarget = pMuru->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_boss_muru(Creature* pCreature) +{ + return new boss_muruAI(pCreature); +} + +CreatureAI* GetAI_boss_entropius(Creature* pCreature) +{ + return new boss_entropiusAI(pCreature); +} + +CreatureAI* GetAI_npc_portal_target(Creature* pCreature) +{ + return new npc_portal_targetAI(pCreature); +} + +CreatureAI* GetAI_npc_void_sentinel_summoner(Creature* pCreature) +{ + return new npc_void_sentinel_summonerAI(pCreature); +} + +/*###### +## mob_dark_fiend // slowly chases a player and exlodes causing AOE to raid when its close to a player +######*/ + +struct MANGOS_DLL_DECL mob_dark_fiendAI : public ScriptedAI +{ + mob_dark_fiendAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + bool m_bIsReached; + + void Reset() + { + m_bIsReached = false; + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + AttackStart(pTarget); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // dispell & and should be purge -- will cause them to despawn + switch(pSpell->Id) + { + case 32375: + case 72734: + case 32592: + case 39897: + case 988: + case 8012: + m_creature->ForcedDespawn(); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + m_creature->SetInCombatWithZone(); + return; + } + + //Are we with in melee attack distance + if (!m_bIsReached && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_DARK_FIEND_DMG, true); + m_creature->RemoveAurasDueToSpell(SPELL_DARK_FIEND); + m_creature->ForcedDespawn(10000); // 10 seconds remaining for Periodic Damage Aura + m_bIsReached = true; + } + } +}; + +CreatureAI* GetAI_mob_dark_fiend(Creature *pCreature) +{ + return new mob_dark_fiendAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_singularityAI : public ScriptedAI +{ + mob_singularityAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiChangeTargetTimer; + uint32 m_uiLifeTime; + + void Reset() + { + m_uiChangeTargetTimer = 5000; + m_uiLifeTime = 22000; + m_creature->SetInCombatWithZone(); + } + + //nullAI + void Aggro(Unit* pWho) {} + void JustDied(Unit* pKiller) override {} + void KilledUnit(Unit* pVictim) override {} + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiLifeTime < uiDiff) + { + m_creature->ForcedDespawn(); + } + else + m_uiLifeTime -= uiDiff; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiChangeTargetTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, (uint32)0, SELECT_FLAG_PLAYER)) + AttackStart(pTarget); + m_uiChangeTargetTimer = 5000; + } + else + m_uiChangeTargetTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_singularity(Creature *_Creature) +{ + return new mob_singularityAI(_Creature); +} + +void AddSC_boss_muru() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_muru"; + pNewScript->GetAI = &GetAI_boss_muru; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_entropius"; + pNewScript->GetAI = &GetAI_boss_entropius; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_dark_fiend"; + pNewScript->GetAI = &GetAI_mob_dark_fiend; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_singularity"; + pNewScript->GetAI = &GetAI_mob_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 ecad826cef..47d11fc87c 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp @@ -1,6 +1,18 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ +/* Copyright (C) 2006 - 2013 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: Instance_Sunwell_Plateau @@ -21,357 +33,472 @@ EndScriptData */ 5 - Kil'Jaeden */ -struct MANGOS_DLL_DECL instance_sunwell_plateau : public ScriptedInstance +static const DialogueEntry aFelmystOutroDialogue[] = { - instance_sunwell_plateau(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - // Creatures - uint64 m_uiKalecgos_DragonGUID; - uint64 m_uiKalecgos_HumanGUID; - uint64 m_uiSathrovarrGUID; - uint64 m_uiBrutallusGUID; - uint64 m_uiFelmystGUID; - uint64 m_uiAlythessGUID; - uint64 m_uiSacrolashGUID; - uint64 m_uiMuruGUID; - uint64 m_uiKilJaedenGUID; - uint64 m_uiKilJaedenControllerGUID; - uint64 m_uiAnveenaGUID; - uint64 m_uiKalecgosGUID; - - // GameObjects - uint64 m_uiForceFieldGUID; // Kalecgos Encounter - uint64 m_uiBossCollision1GUID; - uint64 m_uiBossCollision2GUID; - uint64 m_uiIceBarrierGUID; // Brutallus Encounter - uint64 m_uiDoorFireBarrierGUID; - uint64 m_uiDoorTheFirstGateGUID; // Felmyst Encounter - uint64 m_uiDoorTheSecondGateGUID; // Alythess Encounter - uint64 m_uiDoorRaid_Gate_07GUID; // Sacrolash Encounter - uint64 m_uiDoorRaid_Gate_08GUID; // Muru Encounter - uint64 m_uiDoorTheThirdGateGUID; // Entropius Encounter - - // Misc - uint32 m_uiSpectralRealmTimer; - std::list SpectralRealmList; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - // Creatures - m_uiKalecgos_DragonGUID = 0; - m_uiKalecgos_HumanGUID = 0; - m_uiSathrovarrGUID = 0; - m_uiBrutallusGUID = 0; - m_uiFelmystGUID = 0; - m_uiAlythessGUID = 0; - m_uiSacrolashGUID = 0; - m_uiMuruGUID = 0; - m_uiKilJaedenGUID = 0; - m_uiKilJaedenControllerGUID = 0; - m_uiAnveenaGUID = 0; - m_uiKalecgosGUID = 0; - - // GameObjects - m_uiForceFieldGUID = 0; - m_uiBossCollision1GUID = 0; - m_uiBossCollision2GUID = 0; - m_uiIceBarrierGUID = 0; - m_uiDoorFireBarrierGUID = 0; - m_uiDoorTheFirstGateGUID = 0; - m_uiDoorTheSecondGateGUID = 0; - m_uiDoorRaid_Gate_07GUID = 0; - m_uiDoorRaid_Gate_08GUID = 0; - m_uiDoorTheThirdGateGUID = 0; - - // Misc - m_uiSpectralRealmTimer = 5000; - } + {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}, +}; - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; +instance_sunwell_plateau::instance_sunwell_plateau(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aFelmystOutroDialogue), + m_uiDeceiversKilled(0), + m_uiSpectralRealmTimer(5000), + m_uiKalecRespawnTimer(0), + m_uiMuruBerserkTimer(0), + m_uiKiljaedenYellTimer(90000) +{ + Initialize(); +} - return false; - } +void instance_sunwell_plateau::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + InitializeDialogueHelper(this); +} - void OnCreatureCreate(Creature* pCreature) +bool instance_sunwell_plateau::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - switch(pCreature->GetEntry()) - { - case 24850: m_uiKalecgos_DragonGUID = pCreature->GetGUID(); break; - case 24891: m_uiKalecgos_HumanGUID = pCreature->GetGUID(); break; - case 24892: m_uiSathrovarrGUID = pCreature->GetGUID(); break; - case 24882: m_uiBrutallusGUID = pCreature->GetGUID(); break; - case 25038: m_uiFelmystGUID = pCreature->GetGUID(); break; - case 25166: m_uiAlythessGUID = pCreature->GetGUID(); break; - case 25165: m_uiSacrolashGUID = pCreature->GetGUID(); break; - case 25741: m_uiMuruGUID = pCreature->GetGUID(); break; - case 25315: m_uiKilJaedenGUID = pCreature->GetGUID(); break; - case 25608: m_uiKilJaedenControllerGUID = pCreature->GetGUID(); break; - case 26046: m_uiAnveenaGUID = pCreature->GetGUID(); break; - case 25319: m_uiKalecgosGUID = pCreature->GetGUID(); break; - } + if (m_auiEncounter[i] == IN_PROGRESS) + return true; } - void OnObjectCreate(GameObject* pGo) + return false; +} + +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; + + // Summon Felmyst in reload case + pPlayer->SummonCreature(NPC_FELMYST, aMadrigosaLoc[0].m_fX, aMadrigosaLoc[0].m_fY, aMadrigosaLoc[0].m_fZ, aMadrigosaLoc[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); +} + +void instance_sunwell_plateau::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pGo->GetEntry()) - { - case 188421: - m_uiForceFieldGUID = pGo->GetGUID(); - break; - case 188523: - m_uiBossCollision1GUID = pGo->GetGUID(); - break; - case 188524: - m_uiBossCollision2GUID = pGo->GetGUID(); - break; - case 188119: - m_uiIceBarrierGUID = pGo->GetGUID(); - break; - case 188075: - m_uiDoorFireBarrierGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE && m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 187766: - m_uiDoorTheFirstGateGUID = pGo->GetGUID(); - break; - case 187764: - m_uiDoorTheSecondGateGUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 187990: - m_uiDoorRaid_Gate_07GUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 188118: - m_uiDoorRaid_Gate_08GUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 187765: - m_uiDoorTheThirdGateGUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - } + 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: + case NPC_ENTROPIUS: + case NPC_KILJAEDEN_CONTROLLER: + case NPC_KILJAEDEN: + case NPC_KALECGOS: + case NPC_ANVEENA: + case NPC_VELEN: + 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; } +} - uint32 GetData(uint32 uiType) +void instance_sunwell_plateau::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_DECEIVER) { - switch(uiType) + ++m_uiDeceiversKilled; + // Spawn Kiljaeden when all deceivers are killed + if (m_uiDeceiversKilled == MAX_DECEIVERS) { - case TYPE_KALECGOS: return m_auiEncounter[0]; - case TYPE_BRUTALLUS: return m_auiEncounter[1]; - case TYPE_FELMYST: return m_auiEncounter[2]; - case TYPE_EREDAR_TWINS: return m_auiEncounter[3]; - case TYPE_MURU: return m_auiEncounter[4]; - case TYPE_KILJAEDEN: return m_auiEncounter[5]; - } + if (Creature* pController = GetSingleCreatureFromStorage(NPC_KILJAEDEN_CONTROLLER)) + { + if (Creature* pKiljaeden = pController->SummonCreature(NPC_KILJAEDEN, pController->GetPositionX(), pController->GetPositionY(), pController->GetPositionZ(), pController->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0)) + pKiljaeden->SetInCombatWithZone(); - return 0; + pController->RemoveAurasDueToSpell(SPELL_ANVEENA_DRAIN); + } + } } +} - uint64 GetData64(uint32 id) +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(id) - { - case DATA_KALECGOS_DRAGON: return m_uiKalecgos_DragonGUID; - case DATA_KALECGOS_HUMAN: return m_uiKalecgos_HumanGUID; - case DATA_SATHROVARR: return m_uiSathrovarrGUID; - case DATA_BRUTALLUS: return m_uiBrutallusGUID; - case DATA_FELMYST: return m_uiFelmystGUID; - case DATA_ALYTHESS: return m_uiAlythessGUID; - case DATA_SACROLASH: return m_uiSacrolashGUID; - case DATA_MURU: return m_uiMuruGUID; - case DATA_KILJAEDEN: return m_uiKilJaedenGUID; - case DATA_KILJAEDEN_CONTROLLER: return m_uiKilJaedenControllerGUID; - case DATA_ANVEENA: return m_uiAnveenaGUID; - case DATA_KALECGOS: return m_uiKalecgosGUID; - case DATA_GO_FORCEFIELD: return m_uiForceFieldGUID; - } - return 0; + case GO_FORCEFIELD: + case GO_BOSS_COLLISION_1: + case GO_BOSS_COLLISION_2: + case GO_ICE_BARRIER: + break; + case GO_FIRE_BARRIER: + 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); + break; + 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: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void SetData(uint32 uiType, uint32 uiData) +void instance_sunwell_plateau::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(uiType) - { - case TYPE_KALECGOS: - if (uiData == IN_PROGRESS) - SpectralRealmList.clear(); - - DoUseDoorOrButton(m_uiForceFieldGUID); - DoUseDoorOrButton(m_uiBossCollision1GUID); - DoUseDoorOrButton(m_uiBossCollision2GUID); - - m_auiEncounter[0] = uiData; - break; - case TYPE_BRUTALLUS: - if (uiData == SPECIAL) - DoUseDoorOrButton(m_uiIceBarrierGUID,MINUTE); - - m_auiEncounter[1] = uiData; - break; - case TYPE_FELMYST: - m_auiEncounter[2] = uiData; - if (uiData == DONE) - DoUseDoorOrButton(m_uiDoorFireBarrierGUID); - break; - case TYPE_EREDAR_TWINS: - m_auiEncounter[3] = uiData; - if (uiData == DONE) + case TYPE_KALECGOS: + m_auiEncounter[uiType] = uiData; + // combat doors + DoUseDoorOrButton(GO_FORCEFIELD); + DoUseDoorOrButton(GO_BOSS_COLLISION_1); + DoUseDoorOrButton(GO_BOSS_COLLISION_2); + if (uiData == FAIL) + { + m_uiKalecRespawnTimer = 20000; + + if (Creature* pKalecDragon = GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON)) + pKalecDragon->ForcedDespawn(); + if (Creature* pKalecHuman = GetSingleCreatureFromStorage(NPC_KALECGOS_HUMAN)) + pKalecHuman->ForcedDespawn(); + if (Creature* pSathrovarr = GetSingleCreatureFromStorage(NPC_SATHROVARR)) + pSathrovarr->AI()->EnterEvadeMode(); + } + break; + case TYPE_BRUTALLUS: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_FELMYST: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + 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); + } + break; + case TYPE_MURU: + m_auiEncounter[uiType] = 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; + break; + case TYPE_KILJAEDEN: + m_auiEncounter[uiType] = uiData; + 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) { - DoUseDoorOrButton(m_uiDoorTheSecondGateGUID); - DoUseDoorOrButton(m_uiDoorRaid_Gate_07GUID); + if (Creature* pDeceiver = instance->GetCreature(*itr)) + { + if (!pDeceiver->isAlive()) + pDeceiver->Respawn(); + } } - break; - case TYPE_MURU: - m_auiEncounter[4] = uiData; - if (uiData == DONE) - DoUseDoorOrButton(m_uiDoorRaid_Gate_08GUID); - break; - case TYPE_KILJAEDEN: m_auiEncounter[5] = uiData; break; - case DATA_SET_SPECTRAL_CHECK: m_uiSpectralRealmTimer = uiData; break; - } + } + break; + } - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; + 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]; + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - const char* Save() - { - return strInstData.c_str(); - } +uint32 instance_sunwell_plateau::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - void SetData64(uint32 uiData, uint64 uiGuid) + return 0; +} + +void instance_sunwell_plateau::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (m_uiKalecRespawnTimer) { - if (uiData == DATA_PLAYER_SPECTRAL_REALM) - SpectralRealmList.push_back(uiGuid); + if (m_uiKalecRespawnTimer <= uiDiff) + { + if (Creature* pKalecDragon = GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON)) + pKalecDragon->Respawn(); + if (Creature* pKalecHuman = GetSingleCreatureFromStorage(NPC_KALECGOS_HUMAN)) + pKalecHuman->Respawn(); + m_uiKalecRespawnTimer = 0; + } + else + m_uiKalecRespawnTimer -= uiDiff; } - void EjectPlayer(Player* pPlayer) + // Muru berserk timer; needs to be done here because it involves two distinct creatures + if (m_auiEncounter[TYPE_MURU] == IN_PROGRESS) { - debug_log("SD2: Ejecting Player %s from Spectral Realm", pPlayer->GetName()); - - // Put player back in Kalecgos(Dragon)'s threat list - /*if (Creature* pKalecgos = instance->GetCreature(m_uiKalecgos_DragonGUID)) + if (m_uiMuruBerserkTimer < uiDiff) { - if (pKalecgos->isAlive()) - { - debug_log("SD2: Adding %s in Kalecgos' threatlist", pPlayer->GetName()); - pKalecgos->AddThreat(pPlayer); - } + 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; } + else + m_uiMuruBerserkTimer -= uiDiff; + } - // Remove player from Sathrovarr's threat list - if (Creature* pSath = instance->GetCreature(m_uiSathrovarrGUID)) + if (m_auiEncounter[TYPE_KILJAEDEN] == NOT_STARTED || m_auiEncounter[TYPE_KILJAEDEN] == FAIL) + { + if (m_uiKiljaedenYellTimer < uiDiff) { - if (pSath->isAlive()) + switch (urand(0, 4)) { - if (HostileReference* pRef = pSath->getThreatManager().getOnlineContainer().getReferenceByTarget(pPlayer)) - { - pRef->removeReference(); - debug_log("SD2: Deleting %s from Sathrovarr's threatlist", pPlayer->GetName()); - } + 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; } - }*/ - - pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_NORMAL_REALM, true); - pPlayer->CastSpell(pPlayer, SPELL_SPECTRAL_EXHAUSTION, true); + m_uiKiljaedenYellTimer = 90000; + } + else + m_uiKiljaedenYellTimer -= uiDiff; } +} - void EjectPlayers() +void instance_sunwell_plateau::Load(const char* in) +{ + if (!in) { - if (SpectralRealmList.empty()) - return; + OUT_LOAD_INST_DATA_FAIL; + return; + } - Map::PlayerList const& players = instance->GetPlayers(); + OUT_LOAD_INST_DATA(in); - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - Player* plr = itr->getSource(); + std::istringstream loadStream(in); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> + m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - if (plr && !plr->HasAura(SPELL_SPECTRAL_REALM)) - { - SpectralRealmList.remove(plr->GetGUID()); - EjectPlayer(plr); - } - } + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +static bool sortByPositionX(Creature* pFirst, Creature* pSecond) +{ + return pFirst && pSecond && pFirst->GetPositionX() > pSecond->GetPositionX(); +} - //SpectralRealmList.clear(); +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; } - void Update(uint32 uiDiff) + std::list lTriggers; // Valid pointers, only used locally + for (GuidList::const_iterator itr = m_lAllFlightTriggersList.begin(); itr != m_lAllFlightTriggersList.end(); ++itr) { - // Only check for Spectral Realm if Kalecgos Encounter is running - if (m_auiEncounter[0] == IN_PROGRESS) - { - if (m_uiSpectralRealmTimer <= uiDiff) - { - EjectPlayers(); - m_uiSpectralRealmTimer = 1000; - } - else - m_uiSpectralRealmTimer -= uiDiff; - } + if (Creature* pTrigger = instance->GetCreature(*itr)) + lTriggers.push_back(pTrigger); } - void Load(const char* in) + 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 (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + 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; - OUT_LOAD_INST_DATA(in); + if (uiIndex >= vTemp.size()) + return ObjectGuid(); - std::istringstream loadStream(in); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> - m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; + return vTemp[uiIndex]; +} - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) +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 (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; + 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); } + } +} - OUT_LOAD_INST_DATA_COMPLETE; +void instance_sunwell_plateau::JustDidDialogueStep(int32 iEntry) +{ + switch (iEntry) + { + case NPC_KALECGOS_MADRIGOSA: + if (Creature* pTrigger = GetSingleCreatureFromStorage(NPC_FLIGHT_TRIGGER_LEFT)) + { + 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, 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_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; } -}; +} InstanceData* GetInstanceData_instance_sunwell_plateau(Map* pMap) { return new instance_sunwell_plateau(pMap); } +bool AreaTrigger_at_sunwell_plateau(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_TWINS) + { + if (pPlayer->isGameMaster() || pPlayer->isDead()) + return false; + + instance_sunwell_plateau* pInstance = (instance_sunwell_plateau*)pPlayer->GetInstanceData(); + + if (pInstance && pInstance->GetData(TYPE_EREDAR_TWINS) == NOT_STARTED) + pInstance->SetData(TYPE_EREDAR_TWINS, SPECIAL); + } + + return false; +} + void AddSC_instance_sunwell_plateau() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_sunwell_plateau"; - newscript->GetInstanceData = &GetInstanceData_instance_sunwell_plateau; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_sunwell_plateau"; + pNewScript->GetInstanceData = &GetInstanceData_instance_sunwell_plateau; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_sunwell_plateau"; + pNewScript->pAreaTrigger = &AreaTrigger_at_sunwell_plateau; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h b/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h index a71dea42fa..bbd8e8f1c8 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h +++ b/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h @@ -1,11 +1,12 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef DEF_SUNWELLPLATEAU_H #define DEF_SUNWELLPLATEAU_H -enum InstanceSWP +enum { MAX_ENCOUNTER = 6, @@ -16,34 +17,134 @@ enum InstanceSWP TYPE_MURU = 4, TYPE_KILJAEDEN = 5, - DATA_KALECGOS_DRAGON = 6, - DATA_KALECGOS_HUMAN = 7, - DATA_SATHROVARR = 8, - DATA_BRUTALLUS = 9, - DATA_FELMYST = 10, - DATA_ALYTHESS = 11, - DATA_SACROLASH = 12, - DATA_MURU = 13, - DATA_KILJAEDEN = 14, - DATA_KILJAEDEN_CONTROLLER = 15, - DATA_ANVEENA = 16, - DATA_KALECGOS = 17, - - DATA_GO_FORCEFIELD = 18, - DATA_GO_FIRE_BARRIER = 19, - DATA_GO_FIRST_GATE = 20, - DATA_GO_SECOND_GATE = 21, - DATA_GO_RAID_GATE_07 = 22, - DATA_GO_RAID_GATE_08 = 23, - DATA_GO_THIRD_GATE = 24, - - DATA_PLAYER_SPECTRAL_REALM = 25, - DATA_SET_SPECTRAL_CHECK = 26, - - SPELL_SPECTRAL_REALM = 46021, - SPELL_TELEPORT_NORMAL_REALM = 46020, - SPELL_TELEPORT_TO_SPECTRAL_REALM = 46019, - SPELL_SPECTRAL_EXHAUSTION = 44867, - SPELL_SPECTRAL_REALM_FORCE_FACTION = 44852 + NPC_KALECGOS_DRAGON = 24850, // kalecgos blue dragon hostile + NPC_KALECGOS_HUMAN = 24891, // kalecgos human form in spectral realm + NPC_SATHROVARR = 24892, + 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_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_DECEIVER = 25588, + NPC_KILJAEDEN = 25315, + NPC_KILJAEDEN_CONTROLLER = 25608, // kiljaeden event controller + NPC_ANVEENA = 26046, // related to kiljaeden event + NPC_KALECGOS = 25319, // related to kiljaeden event + NPC_VELEN = 26246, + NPC_LIADRIN = 26247, + + GO_FORCEFIELD = 188421, // kalecgos door + collisions + GO_BOSS_COLLISION_1 = 188523, + 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_MURU_ENTER_GATE = 187990, // muru gates + GO_MURU_EXIT_GATE = 188118, + GO_THIRD_GATE = 187765, // door after muru; why another? + GO_ORB_OF_THE_BLUE_FLIGHT = 188415, + + 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 + SPELL_MURU_BERSERK = 26662, + // visuals for Kiljaeden encounter + SPELL_ANVEENA_DRAIN = 46410, + + MAX_DECEIVERS = 3 +}; + +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 +}; + +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 +}; + +class MANGOS_DLL_DECL instance_sunwell_plateau : public ScriptedInstance, private DialogueHelper +{ + public: + instance_sunwell_plateau(Map* pMap); + ~instance_sunwell_plateau() {} + + 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) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void Update(uint32 uiDiff) override; + + ObjectGuid SelectFelmystFlightTrigger(bool bLeftSide, uint8 uiIndex); + + void AddToSpectralRealm(ObjectGuid playerGuid) { m_spectralRealmPlayers.insert(playerGuid); } + void RemoveFromSpectralRealm(ObjectGuid playerGuid) { m_spectralRealmPlayers.erase(playerGuid); } + void DoEjectSpectralPlayers(); + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + protected: + void JustDidDialogueStep(int32 iEntry) override; + void DoSortFlightTriggers(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + // Misc + uint8 m_uiDeceiversKilled; + 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; }; #endif diff --git a/scripts/eastern_kingdoms/swamp_of_sorrows.cpp b/scripts/eastern_kingdoms/swamp_of_sorrows.cpp index 29e1094961..0d86256712 100644 --- a/scripts/eastern_kingdoms/swamp_of_sorrows.cpp +++ b/scripts/eastern_kingdoms/swamp_of_sorrows.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -49,13 +49,9 @@ enum Galen struct MANGOS_DLL_DECL npc_galen_goodwardAI : public npc_escortAI { - npc_galen_goodwardAI(Creature* pCreature) : npc_escortAI(pCreature) - { - m_uiGalensCageGUID = 0; - Reset(); - } + npc_galen_goodwardAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - uint64 m_uiGalensCageGUID; + ObjectGuid m_galensCageGuid; uint32 m_uiPeriodicSay; void Reset() @@ -63,42 +59,43 @@ struct MANGOS_DLL_DECL npc_galen_goodwardAI : public npc_escortAI 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_uiGalensCageGUID) - pCage = m_creature->GetMap()->GetGameObject(m_uiGalensCageGUID); - else - pCage = GetClosestGameObjectWithEntry(m_creature, GO_GALENS_CAGE, INTERACTION_DISTANCE); - if (pCage) - { - pCage->UseDoorOrButton(); - m_uiGalensCageGUID = pCage->GetGUID(); - } - 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) { case 0: - if (GameObject* pCage = m_creature->GetMap()->GetGameObject(m_uiGalensCageGUID)) + if (GameObject* pCage = m_creature->GetMap()->GetGameObject(m_galensCageGuid)) pCage->ResetDoorOrButton(); break; case 20: @@ -114,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) @@ -140,8 +137,8 @@ bool QuestAccept_npc_galen_goodward(Player* pPlayer, Creature* pCreature, const if (npc_galen_goodwardAI* pEscortAI = dynamic_cast(pCreature->AI())) { - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE); + pEscortAI->Start(false, pPlayer, pQuest); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_QUEST_ACCEPTED, pCreature); } } @@ -155,11 +152,11 @@ CreatureAI* GetAI_npc_galen_goodward(Creature* pCreature) void AddSC_swamp_of_sorrows() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_galen_goodward"; - newscript->GetAI = &GetAI_npc_galen_goodward; - newscript->pQuestAccept = &QuestAccept_npc_galen_goodward; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_galen_goodward"; + pNewScript->GetAI = &GetAI_npc_galen_goodward; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_galen_goodward; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/throne_of_the_tides/boss_commander_ulthok.cpp b/scripts/eastern_kingdoms/throne_of_the_tides/boss_commander_ulthok.cpp new file mode 100644 index 0000000000..c22b9c6c1c --- /dev/null +++ b/scripts/eastern_kingdoms/throne_of_the_tides/boss_commander_ulthok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_commander_ulthok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Tides +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_commander_ulthok() +{ +} diff --git a/scripts/eastern_kingdoms/throne_of_the_tides/boss_erunak_and_ghursha.cpp b/scripts/eastern_kingdoms/throne_of_the_tides/boss_erunak_and_ghursha.cpp new file mode 100644 index 0000000000..a7aee76eb9 --- /dev/null +++ b/scripts/eastern_kingdoms/throne_of_the_tides/boss_erunak_and_ghursha.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_erunak_and_ghursha +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Tides +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_erunak_and_ghursha() +{ +} diff --git a/scripts/eastern_kingdoms/throne_of_the_tides/boss_lady_nazjar.cpp b/scripts/eastern_kingdoms/throne_of_the_tides/boss_lady_nazjar.cpp new file mode 100644 index 0000000000..0f0bee3769 --- /dev/null +++ b/scripts/eastern_kingdoms/throne_of_the_tides/boss_lady_nazjar.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lady_nazjar +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Tides +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lady_nazjar() +{ +} diff --git a/scripts/eastern_kingdoms/throne_of_the_tides/boss_ozumat.cpp b/scripts/eastern_kingdoms/throne_of_the_tides/boss_ozumat.cpp new file mode 100644 index 0000000000..7a91756f11 --- /dev/null +++ b/scripts/eastern_kingdoms/throne_of_the_tides/boss_ozumat.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ozumat +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Tides +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ozumat() +{ +} diff --git a/scripts/eastern_kingdoms/throne_of_the_tides/instance_throne_of_the_tides.cpp b/scripts/eastern_kingdoms/throne_of_the_tides/instance_throne_of_the_tides.cpp new file mode 100644 index 0000000000..6742081f2f --- /dev/null +++ b/scripts/eastern_kingdoms/throne_of_the_tides/instance_throne_of_the_tides.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_throne_of_the_tides +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Tides +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_throne_of_the_tides() +{ +} diff --git a/scripts/eastern_kingdoms/throne_of_the_tides/throne_of_the_tides.h b/scripts/eastern_kingdoms/throne_of_the_tides/throne_of_the_tides.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/eastern_kingdoms/throne_of_the_tides/throne_of_the_tides.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/eastern_kingdoms/tirisfal_glades.cpp b/scripts/eastern_kingdoms/tirisfal_glades.cpp index b924039d40..6fa7c63d40 100644 --- a/scripts/eastern_kingdoms/tirisfal_glades.cpp +++ b/scripts/eastern_kingdoms/tirisfal_glades.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -42,7 +42,7 @@ enum GO_DOOR = 176594 }; -bool GOHello_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,14 +50,14 @@ bool GOHello_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; } return false; } -bool GOHello_go_mausoleum_trigger(Player* pPlayer, GameObject* pGo) +bool GOUse_go_mausoleum_trigger(Player* pPlayer, GameObject* pGo) { if (pPlayer->GetQuestStatus(QUEST_ULAG) != QUEST_STATUS_INCOMPLETE) return false; @@ -65,7 +65,7 @@ bool GOHello_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; } @@ -88,26 +88,21 @@ struct MANGOS_DLL_DECL 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; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; void Reset() { m_uiPhase = 0; m_uiPhaseTimer = 5000; - m_uiPlayerGUID = 0; - - if (m_creature->getFaction() != m_uiNormFaction) - m_creature->setFaction(m_uiNormFaction); + m_playerGuid.Clear(); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim() || m_creature->IsFriendlyTo(pAttacker)) return; @@ -115,23 +110,22 @@ 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; if (pDoneBy->GetTypeId() == TYPEID_PLAYER) - m_uiPlayerGUID = pDoneBy->GetGUID(); + m_playerGuid = pDoneBy->GetObjectGuid(); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiPhase) { @@ -143,17 +137,17 @@ struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI return; } - switch(m_uiPhase) + switch (m_uiPhase) { case 1: DoScriptText(SAY_COMPLETE, m_creature); ++m_uiPhase; break; case 2: - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + 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; @@ -188,21 +182,21 @@ bool QuestAccept_npc_calvin_montague(Player* pPlayer, Creature* pCreature, const void AddSC_tirisfal_glades() { - Script *newscript; - - newscript = new Script; - newscript->Name = "go_mausoleum_door"; - newscript->pGOHello = &GOHello_go_mausoleum_door; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_mausoleum_trigger"; - newscript->pGOHello = &GOHello_go_mausoleum_trigger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_calvin_montague"; - newscript->GetAI = &GetAI_npc_calvin_montague; - newscript->pQuestAccept = &QuestAccept_npc_calvin_montague; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "go_mausoleum_door"; + pNewScript->pGOUse = &GOUse_go_mausoleum_door; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_mausoleum_trigger"; + pNewScript->pGOUse = &GOUse_go_mausoleum_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_calvin_montague"; + pNewScript->GetAI = &GetAI_npc_calvin_montague; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_calvin_montague; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/twilight_highlands.cpp b/scripts/eastern_kingdoms/twilight_highlands.cpp new file mode 100644 index 0000000000..30dd96bb20 --- /dev/null +++ b/scripts/eastern_kingdoms/twilight_highlands.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Twilight Highlands +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Twilight Highlands +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_twilight_highlands() +{ +} diff --git a/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp b/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp index 80d0f8f08e..9df8a94c1e 100644 --- a/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp +++ b/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,23 +26,23 @@ 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 { - boss_archaedasAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_archaedasAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_uldaman*)pCreature->GetInstanceData(); Reset(); @@ -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; + + uint8 m_uiHpPhaseCheck; void Reset() { 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,17 +107,23 @@ 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: - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_pInstance->GetData64(DATA_EVENT_STARTER))) + 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 EnterEvadeMode(); @@ -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 de4a758085..740c7fba0d 100644 --- a/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp +++ b/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,12 +26,8 @@ EndScriptData #include "uldaman.h" instance_uldaman::instance_uldaman(Map* pMap) : ScriptedInstance(pMap), - m_uiTempleDoorUpperGUID(0), - m_uiTempleDoorLowerGUID(0), - m_uiAncientVaultGUID(0), - m_uiPlayerGUID(0), - m_uiStoneKeepersFallen(0), - m_uiKeeperCooldown(5000) + m_uiKeeperCooldown(0), + m_uiStoneKeepersFallen(0) { Initialize(); } @@ -39,50 +35,42 @@ instance_uldaman::instance_uldaman(Map* pMap) : ScriptedInstance(pMap), void instance_uldaman::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - m_lWardens.clear(); - m_mKeeperMap.clear(); } 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); - m_uiTempleDoorUpperGUID = pGo->GetGUID(); - break; case GO_TEMPLE_DOOR_LOWER: - if (m_auiEncounter[0] == DONE) + if (GetData(TYPE_ALTAR_EVENT) == DONE) pGo->SetGoState(GO_STATE_ACTIVE); - m_uiTempleDoorLowerGUID = pGo->GetGUID(); break; case GO_ANCIENT_VAULT: - if (m_auiEncounter[1] == DONE) + if (GetData(TYPE_ARCHAEDAS) == DONE) pGo->SetGoState(GO_STATE_ACTIVE); - m_uiAncientVaultGUID = pGo->GetGUID(); break; - default: + case GO_ANCIENT_TREASURE: break; + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } 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->GetGUID()); - pCreature->CastSpell(pCreature, SPELL_STONED, true); - pCreature->SetNoCallAssistance(true); // no assistance + m_lWardens.push_back(pCreature->GetObjectGuid()); break; case NPC_STONE_KEEPER: - m_mKeeperMap[pCreature->GetGUID()] = pCreature->isAlive(); - pCreature->CastSpell(pCreature, SPELL_STONED, true); - pCreature->SetNoCallAssistance(true); // no assistance + m_lKeepers.push_back(pCreature->GetObjectGuid()); + break; + case NPC_ARCHAEDAS: + m_mNpcEntryGuidStore[NPC_ARCHAEDAS] = pCreature->GetObjectGuid(); break; default: break; @@ -91,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(m_uiTempleDoorUpperGUID); - DoUseDoorOrButton(m_uiTempleDoorLowerGUID); - - m_auiEncounter[0] = uiData; + DoUseDoorOrButton(GO_TEMPLE_DOOR_UPPER); + DoUseDoorOrButton(GO_TEMPLE_DOOR_LOWER); } + 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 (std::list::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 (std::list::iterator itr = m_lWardens.begin(); itr != m_lWardens.end(); ++itr) - { - Creature* pWarden = instance->GetCreature(*itr); - if (pWarden && pWarden->isAlive()) - pWarden->ForcedDespawn(); - } - DoUseDoorOrButton(m_uiAncientVaultGUID); + DoUseDoorOrButton(GO_ANCIENT_VAULT); + DoRespawnGameObject(GO_ANCIENT_TREASURE, HOUR); } m_auiEncounter[1] = uiData; break; @@ -138,7 +119,7 @@ void instance_uldaman::SetData(uint32 uiType, uint32 uiData) saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; } @@ -157,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; @@ -168,93 +149,82 @@ 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_uiPlayerGUID = uiGuid; - break; + m_playerGuid = ObjectGuid(uiGuid); + 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_uiPlayerGUID; + return m_playerGuid.GetRawValue(); } return 0; } void instance_uldaman::StartEvent(uint32 uiEventId, Player* pPlayer) { - m_uiPlayerGUID = pPlayer->GetGUID(); + m_playerGuid = pPlayer->GetObjectGuid(); 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->CastSpell(pKeeper, SPELL_STONED, true); - 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 (std::list::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()) @@ -264,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_uiPlayerGUID)) - { - // 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) @@ -324,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 7cf9786b5a..4d2371b023 100644 --- a/scripts/eastern_kingdoms/uldaman/uldaman.cpp +++ b/scripts/eastern_kingdoms/uldaman/uldaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,111 +16,14 @@ /* ScriptData SDName: Uldaman -SD%Complete: 100 -SDComment: Quest support: 2278 +SD%Complete: 0 +SDComment: Placeholder SDCategory: Uldaman EndScriptData */ -/* ContentData -npc_lore_keeper_of_norgannon -EndContentData */ - #include "precompiled.h" #include "uldaman.h" -/*###### -## npc_lore_keeper_of_norgannon -######*/ - -bool GossipHello_npc_lore_keeper_of_norgannon(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(2278) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Who are the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(1079, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lore_keeper_of_norgannon(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What is a \"subterranean being matrix\"?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(1080, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What are the anomalies you speak of?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(1081, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What is a resilient foundation of construction?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(1082, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "So... the Earthen were made out of stone?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(1083, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Anything else I should know about the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->SEND_GOSSIP_MENU(1084, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I think I understand the Creators' design intent for the Earthen now. What are the Earthen's anomalies that you spoke of earlier?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); - pPlayer->SEND_GOSSIP_MENU(1085, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What high-stress environments would cause the Earthen to destabilize?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+8); - pPlayer->SEND_GOSSIP_MENU(1086, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What happens when the Earthen destabilize?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); - pPlayer->SEND_GOSSIP_MENU(1087, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Troggs?! Are the troggs you mention the same as the ones in the world today?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+10); - pPlayer->SEND_GOSSIP_MENU(1088, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+10: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "You mentioned two results when the Earthen destabilize. What is the second?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+11); - pPlayer->SEND_GOSSIP_MENU(1089, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Dwarves!!! Now you're telling me that dwarves originally came from the Earthen?!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+12); - pPlayer->SEND_GOSSIP_MENU(1090, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+12: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "These dwarves are the same ones today, yes? Do the dwarves maintain any other links to the Earthen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+13); - pPlayer->SEND_GOSSIP_MENU(1091, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+13: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Who are the Creators?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+14); - pPlayer->SEND_GOSSIP_MENU(1092, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+14: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "This is a lot to think about.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+15); - pPlayer->SEND_GOSSIP_MENU(1093, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+15: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I will access the discs now.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+16); - pPlayer->SEND_GOSSIP_MENU(1094, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+16: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(2278); - break; - } - return true; -} - void AddSC_uldaman() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "npc_lore_keeper_of_norgannon"; - pNewScript->pGossipHello = &GossipHello_npc_lore_keeper_of_norgannon; - pNewScript->pGossipSelect = &GossipSelect_npc_lore_keeper_of_norgannon; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/uldaman/uldaman.h b/scripts/eastern_kingdoms/uldaman/uldaman.h index d89594552c..710ada4b00 100644 --- a/scripts/eastern_kingdoms/uldaman/uldaman.h +++ b/scripts/eastern_kingdoms/uldaman/uldaman.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -16,18 +16,17 @@ 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 @@ -39,41 +38,41 @@ class MANGOS_DLL_DECL instance_uldaman : public ScriptedInstance 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 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 strInstData; + std::string m_strInstData; - uint64 m_uiTempleDoorUpperGUID; - uint64 m_uiTempleDoorLowerGUID; - uint64 m_uiAncientVaultGUID; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; uint32 m_uiKeeperCooldown; uint32 m_uiStoneKeepersFallen; - std::list 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 3b457a8b00..83247859fa 100644 --- a/scripts/eastern_kingdoms/undercity.cpp +++ b/scripts/eastern_kingdoms/undercity.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,14 +17,12 @@ /* ScriptData SDName: Undercity SD%Complete: 95 -SDComment: Quest support: 6628(Parqual Fintallas questions/'answers' might have more to it, need more info), 9180(post-event). +SDComment: Quest support: 9180(post-event). SDCategory: Undercity EndScriptData */ /* ContentData npc_lady_sylvanas_windrunner -npc_highborne_lamenter -npc_parqual_fintallas EndContentData */ #include "precompiled.h" @@ -33,226 +31,185 @@ 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, + SPELL_BLACK_ARROW = 59712, + SPELL_FADE = 20672, + SPELL_MULTI_SHOT = 59713, + SPELL_SHOOT_SYLVANAS = 59710, + SPELL_SUMMON_SKELETON = 59711, -#define SOUND_CREDIT 10896 -#define ENTRY_HIGHBORNE_LAMENTER 21628 -#define ENTRY_HIGHBORNE_BUNNY 21641 + NPC_HIGHBORNE_LAMENTER = 21628, + NPC_HIGHBORNE_BUNNY = 21641, -#define SPELL_HIGHBORNE_AURA 37090 -#define SPELL_SYLVANAS_CAST 36568 -#define SPELL_RIBBON_OF_SOULS 34432 //the real one to use might be 37099 + QUEST_ID_JOURNEY_UNDERCITY = 9180, -float HighborneLoc[4][3]= + MAX_LAMENTERS = 4, +}; + +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 { npc_lady_sylvanas_windrunnerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 LamentEvent_Timer; - bool LamentEvent; - uint64 targetGUID; + uint32 m_uiLamentEventTimer; + uint32 m_uiSummonTimer; - float myX; - float myY; - float myZ; + uint32 m_uiBlackArrowTimer; + uint32 m_uiMultiShotTimer; + uint32 m_uiFadeTimer; + uint32 m_uiShootTimer; + uint32 m_uiSummonSkeletonTimer; - void Reset() + void Reset() override { - myX = m_creature->GetPositionX(); - myY = m_creature->GetPositionY(); - myZ = m_creature->GetPositionZ(); - - LamentEvent_Timer = 5000; - LamentEvent = false; - targetGUID = 0; + 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(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); - targetGUID = summoned->GetGUID(); + 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()) return; - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_lady_sylvanas_windrunner(Creature* pCreature) -{ - return new npc_lady_sylvanas_windrunnerAI(pCreature); -} - -bool ChooseReward_npc_lady_sylvanas_windrunner(Player* pPlayer, Creature* pCreature, const Quest* pQuest, uint32 slot) -{ - if (pQuest->GetQuestId() == 9180) - { - if (npc_lady_sylvanas_windrunnerAI* pSylvanAI = dynamic_cast(pCreature->AI())) + if (m_uiBlackArrowTimer < uiDiff) { - pSylvanAI->LamentEvent = true; - pSylvanAI->DoPlaySoundToSet(pCreature, SOUND_CREDIT); + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_BLACK_ARROW); + m_uiBlackArrowTimer = urand(15000, 25000); } + else + m_uiBlackArrowTimer -= uiDiff; - 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); - } - - 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; + if (m_uiMultiShotTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); + m_uiMultiShotTimer = urand(11000, 14000); + } + else + m_uiMultiShotTimer -= uiDiff; - void Reset() - { - EventMove_Timer = 10000; - EventCast_Timer = 17500; - EventMove = true; - EventCast = true; - } + if (m_uiFadeTimer < uiDiff) + { + DoCast(m_creature, SPELL_FADE); + m_uiFadeTimer = urand(15000, 20000); + } + else + m_uiFadeTimer -= uiDiff; - void UpdateAI(const uint32 diff) - { - if (EventMove) + if (m_uiShootTimer < uiDiff) { - if (EventMove_Timer < diff) - { - m_creature->AddSplineFlag(SPLINEFLAG_NO_SPLINE); - m_creature->SendMonsterMoveWithSpeed(m_creature->GetPositionX(),m_creature->GetPositionY(),HIGHBORNE_LOC_Y_NEW,5000); - m_creature->GetMap()->CreatureRelocation(m_creature,m_creature->GetPositionX(),m_creature->GetPositionY(),HIGHBORNE_LOC_Y_NEW,m_creature->GetOrientation()); - EventMove = false; - }else EventMove_Timer -= diff; + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_SHOOT_SYLVANAS); + m_uiShootTimer = urand(6000, 9000); } - if (EventCast) + else + m_uiShootTimer -= uiDiff; + + if (m_uiSummonSkeletonTimer < uiDiff) { - if (EventCast_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_HIGHBORNE_AURA); - EventCast = false; - }else EventCast_Timer -= diff; + DoCast(m_creature, SPELL_SUMMON_SKELETON); + m_uiSummonSkeletonTimer = urand(17000, 23000); } + else + m_uiSummonSkeletonTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_npc_highborne_lamenter(Creature* pCreature) -{ - return new npc_highborne_lamenterAI(pCreature); -} - -/*###### -## npc_parqual_fintallas -######*/ - -#define SPELL_MARK_OF_SHAME 6767 -bool GossipHello_npc_parqual_fintallas(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_lady_sylvanas_windrunner(Creature* pCreature) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(6628) == QUEST_STATUS_INCOMPLETE && !pPlayer->HasAura(SPELL_MARK_OF_SHAME, EFFECT_INDEX_0)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Gul'dan", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Kel'Thuzad", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ner'zhul", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(5822, pCreature->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(5821, pCreature->GetGUID()); - - return true; + return new npc_lady_sylvanas_windrunnerAI(pCreature); } -bool GossipSelect_npc_parqual_fintallas(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestRewarded_npc_lady_sylvanas_windrunner(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer,SPELL_MARK_OF_SHAME,false); - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (pQuest->GetQuestId() == QUEST_ID_JOURNEY_UNDERCITY) { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(6628); + if (npc_lady_sylvanas_windrunnerAI* pSylvanAI = dynamic_cast(pCreature->AI())) + pSylvanAI->DoStartLamentEvent(); } + return true; } -/*###### -## AddSC -######*/ - void AddSC_undercity() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_lady_sylvanas_windrunner"; - newscript->GetAI = &GetAI_npc_lady_sylvanas_windrunner; - newscript->pChooseReward = &ChooseReward_npc_lady_sylvanas_windrunner; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_highborne_lamenter"; - newscript->GetAI = &GetAI_npc_highborne_lamenter; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_parqual_fintallas"; - newscript->pGossipHello = &GossipHello_npc_parqual_fintallas; - newscript->pGossipSelect = &GossipSelect_npc_parqual_fintallas; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_lady_sylvanas_windrunner"; + pNewScript->GetAI = &GetAI_npc_lady_sylvanas_windrunner; + pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_lady_sylvanas_windrunner; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/vashjir.cpp b/scripts/eastern_kingdoms/vashjir.cpp new file mode 100644 index 0000000000..c24f0224be --- /dev/null +++ b/scripts/eastern_kingdoms/vashjir.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Vashjir +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Vashjir +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_vashjir() +{ +} diff --git a/scripts/eastern_kingdoms/western_plaguelands.cpp b/scripts/eastern_kingdoms/western_plaguelands.cpp index bc5f1c2a43..bbc2e112af 100644 --- a/scripts/eastern_kingdoms/western_plaguelands.cpp +++ b/scripts/eastern_kingdoms/western_plaguelands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,206 +17,1082 @@ /* ScriptData SDName: Western_Plaguelands SD%Complete: 90 -SDComment: Quest support: 5216,5219,5222,5225,5229,5231,5233,5235. To obtain Vitreous Focuser (could use more spesifics about gossip items) +SDComment: Quest support: 5216, 5219, 5222, 5225, 5229, 5231, 5233, 5235, 5862, 5944, 9446. SDCategory: Western Plaguelands EndScriptData */ /* ContentData -npcs_dithers_and_arbington -npc_myranda_hag npc_the_scourge_cauldron +npc_anchorite_truuen +npc_taelan_fordring +npc_isillien +npc_tirion_fordring EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### -## npcs_dithers_and_arbington +## npc_the_scourge_cauldron ######*/ -bool GossipHello_npcs_dithers_and_arbington(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + npc_the_scourge_cauldronAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - if (pPlayer->GetQuestRewardStatus(5237) || pPlayer->GetQuestRewardStatus(5238)) + void Reset() {} + + void DoDie() { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What does the Felstone Field Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What does the Dalson's Tears Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What does the Writhing Haunt Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What does the Gahrron's Withering Cauldron need?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(3985, pCreature->GetGUID()); - }else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // 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 + uint32 rTime = m_creature->GetRespawnDelay(); + if (rTime < 600) + m_creature->SetRespawnDelay(600); + } - return true; -} + void MoveInLineOfSight(Unit* who) override + { + if (!who || who->GetTypeId() != TYPEID_PLAYER) + return; -bool GossipSelect_npcs_dithers_and_arbington(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(3980, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(3981, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(3982, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks, i need a Vitreous Focuser", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(3983, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, 17529, false); - break; + if (who->GetTypeId() == TYPEID_PLAYER) + { + switch (m_creature->GetAreaId()) + { + case 199: // felstone + if (((Player*)who)->GetQuestStatus(5216) == QUEST_STATUS_INCOMPLETE || + ((Player*)who)->GetQuestStatus(5229) == QUEST_STATUS_INCOMPLETE) + { + m_creature->SummonCreature(11075, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); + DoDie(); + } + break; + case 200: // dalson + if (((Player*)who)->GetQuestStatus(5219) == QUEST_STATUS_INCOMPLETE || + ((Player*)who)->GetQuestStatus(5231) == QUEST_STATUS_INCOMPLETE) + { + m_creature->SummonCreature(11077, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); + DoDie(); + } + break; + case 201: // gahrron + if (((Player*)who)->GetQuestStatus(5225) == QUEST_STATUS_INCOMPLETE || + ((Player*)who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE) + { + m_creature->SummonCreature(11078, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); + DoDie(); + } + break; + case 202: // writhing + if (((Player*)who)->GetQuestStatus(5222) == QUEST_STATUS_INCOMPLETE || + ((Player*)who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE) + { + m_creature->SummonCreature(11076, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); + DoDie(); + } + break; + } + } } - return true; +}; + +CreatureAI* GetAI_npc_the_scourge_cauldron(Creature* pCreature) +{ + return new npc_the_scourge_cauldronAI(pCreature); } /*###### -## npc_myranda_the_hag +## npc_anchorite_truuen ######*/ enum { - QUEST_SUBTERFUGE = 5862, - QUEST_IN_DREAMS = 5944, - SPELL_SCARLET_ILLUSION = 17961 -}; + 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, -#define GOSSIP_ITEM_ILLUSION "I am ready for the illusion, Myranda." + QUEST_ID_TOMB_LIGHTBRINGER = 9446, +}; -bool GossipHello_npc_myranda_the_hag(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_anchorite_truuenAI: public npc_escortAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_anchorite_truuenAI(Creature* pCreature): npc_escortAI(pCreature) { Reset(); } + + ObjectGuid m_utherGhostGuid; + + void Reset() { } - if (pPlayer->GetQuestStatus(QUEST_SUBTERFUGE) == QUEST_STATUS_COMPLETE && - !pPlayer->GetQuestRewardStatus(QUEST_IN_DREAMS) && !pPlayer->HasAura(SPELL_SCARLET_ILLUSION)) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ILLUSION, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(4773, pCreature->GetGUID()); - return true; + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_BEGIN, m_creature); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + 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; + } + } -bool GossipSelect_npc_myranda_the_hag(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + void JustSummoned(Creature* pSummoned) override { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, SPELL_SCARLET_ILLUSION, false); + 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_the_scourge_cauldron +## npc_taelan_fordring ######*/ -struct MANGOS_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI +enum { - npc_the_scourge_cauldronAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + // scarlet end quest texts + SAY_SCARLET_COMPLETE_1 = -1001076, + SAY_SCARLET_COMPLETE_2 = -1001077, - void Reset() {} + // 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, - void DoDie() + // 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 MANGOS_DLL_DECL npc_taelan_fordringAI: public npc_escortAI, private DialogueHelper +{ + npc_taelan_fordringAI(Creature* pCreature): npc_escortAI(pCreature), + DialogueHelper(aScarletDialogue) { - //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 - uint32 rTime = m_creature->GetRespawnDelay(); - if (rTime<600) - m_creature->SetRespawnDelay(600); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_bScarletComplete = false; + m_bFightStarted = false; + m_bTaelanDead = false; + m_bHasMount = false; + Reset(); } - void MoveInLineOfSight(Unit *who) + 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 { - if (!who || who->GetTypeId() != TYPEID_PLAYER) + 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; - if (who->GetTypeId() == TYPEID_PLAYER) + 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 { - switch(m_creature->GetAreaId()) + 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: { - case 199: //felstone - if (((Player*)who)->GetQuestStatus(5216) == 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); - DoDie(); - } - break; - case 200: //dalson - if (((Player*)who)->GetQuestStatus(5219) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5231) == QUEST_STATUS_INCOMPLETE) + // 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->SummonCreature(11077, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - DoDie(); + m_creature->GetContactPoint(pCavalier, fX, fY, fZ); + pCavalier->GetMotionMaster()->MovePoint(0, fX, fY, fZ); } - break; - case 201: //gahrron - if (((Player*)who)->GetQuestStatus(5225) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE) + } + 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)) { - m_creature->SummonCreature(11078, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoDie(); + pTirion->AI()->AttackStart(pIsillien); + pIsillien->AI()->AttackStart(pTirion); } - break; - case 202: //writhing - if (((Player*)who)->GetQuestStatus(5222) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE) + } + 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()) { - m_creature->SummonCreature(11076, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoDie(); + pPlayer->GroupEventHappens(QUEST_ID_IN_DREAMS, m_creature); + pTirion->SetFacingToObject(pPlayer); } - break; + + 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_the_scourge_cauldron(Creature* pCreature) + +CreatureAI* GetAI_npc_taelan_fordring(Creature* pCreature) { - return new npc_the_scourge_cauldronAI(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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 *newscript; + Script* pNewScript; + + pNewScript = new Script; + 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(); - newscript = new Script; - newscript->Name = "npcs_dithers_and_arbington"; - newscript->pGossipHello = &GossipHello_npcs_dithers_and_arbington; - newscript->pGossipSelect = &GossipSelect_npcs_dithers_and_arbington; - newscript->RegisterSelf(); + pNewScript = new Script; + 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(); - newscript = new Script; - newscript->Name = "npc_myranda_the_hag"; - newscript->pGossipHello = &GossipHello_npc_myranda_the_hag; - newscript->pGossipSelect = &GossipSelect_npc_myranda_the_hag; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_isillien"; + pNewScript->GetAI = &GetAI_npc_isillien; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_the_scourge_cauldron"; - newscript->GetAI = &GetAI_npc_the_scourge_cauldron; - newscript->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 b65dcab652..32777b3d40 100644 --- a/scripts/eastern_kingdoms/westfall.cpp +++ b/scripts/eastern_kingdoms/westfall.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -62,7 +62,7 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI { 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; @@ -153,9 +153,8 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI { m_uiShootTimer = 1000; - if (!m_creature->IsWithinDist(m_creature->getVictim(), ATTACK_DISTANCE)) + if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOOT); - } else m_uiShootTimer -= uiDiff; @@ -171,7 +170,7 @@ bool QuestAccept_npc_daphne_stilwell(Player* pPlayer, Creature* pCreature, const DoScriptText(SAY_DS_START, pCreature); if (npc_daphne_stilwellAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(true, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(true, pPlayer, pQuest); } return true; @@ -201,7 +200,7 @@ struct MANGOS_DLL_DECL 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,9 +221,9 @@ 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); + DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature, pWho); } void Reset() { } @@ -237,7 +236,7 @@ bool QuestAccept_npc_defias_traitor(Player* pPlayer, Creature* pCreature, const DoScriptText(SAY_START, pCreature, pPlayer); if (npc_defias_traitorAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(true, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(true, pPlayer, pQuest); } return true; @@ -255,12 +254,12 @@ void AddSC_westfall() pNewScript = new Script; pNewScript->Name = "npc_daphne_stilwell"; pNewScript->GetAI = &GetAI_npc_daphne_stilwell; - pNewScript->pQuestAccept = &QuestAccept_npc_daphne_stilwell; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_daphne_stilwell; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_defias_traitor"; pNewScript->GetAI = &GetAI_npc_defias_traitor; - pNewScript->pQuestAccept = &QuestAccept_npc_defias_traitor; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_defias_traitor; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/wetlands.cpp b/scripts/eastern_kingdoms/wetlands.cpp index 8bbc8c89bd..de714cfbbb 100644 --- a/scripts/eastern_kingdoms/wetlands.cpp +++ b/scripts/eastern_kingdoms/wetlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,7 +16,7 @@ /* ScriptData SDName: Wetlands -SD%Complete: 80 +SD%Complete: 100 SDComment: Quest support: 1249 SDCategory: Wetlands EndScriptData */ @@ -35,88 +35,162 @@ EndContentData */ enum { + SAY_SLIM_AGGRO = -1000977, + SAY_SLIM_DEFEAT = -1000978, + SAY_FRIEND_DEFEAT = -1000979, + SAY_SLIM_NOTES = -1000980, + QUEST_MISSING_DIPLO_PT11 = 1249, - FACTION_ENEMY = 168, + 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_DIPLO_PT11, 0, 0}, + {0, 0, 0}, +}; + +struct MANGOS_DLL_DECL 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() { if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { m_bFriendSummoned = false; + m_bEventComplete = false; + } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 2: - if (m_creature->HasStealthAura()) - m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - 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)) + 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(); + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !HasEscortState(STATE_ESCORT_ESCORTING)) return; - AttackStart(pAttacker); + npc_escortAI::MovementInform(uiMoveType, uiPointId); + + // after the npc is defeated, start the dialog right after it reaches the evade point + if (m_bEventComplete) + { + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + + StartNextDialogueText(SAY_SLIM_DEFEAT); + } + } + + 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_DIPLO_PT11) { + // complete quest if (Player* pPlayer = GetPlayerForEscort()) - { pPlayer->GroupEventHappens(QUEST_MISSING_DIPLO_PT11, m_creature); - uiDamage = 0; + // despawn and respawn at inn + m_creature->ForcedDespawn(1000); + m_creature->SetRespawnDelay(2); + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_TAPOKE_SLIM_JAHN) + return m_creature; - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); + return NULL; + } - SetRun(false); - } - } + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); } }; @@ -134,16 +208,16 @@ bool QuestAccept_npc_mikhail(Player* pPlayer, Creature* pCreature, const Quest* if (pQuest->GetQuestId() == QUEST_MISSING_DIPLO_PT11) { 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->GetGUID(), pQuest); + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pSlim, pQuest->GetQuestId()); + return true; } + return false; } @@ -153,15 +227,15 @@ bool QuestAccept_npc_mikhail(Player* pPlayer, Creature* pCreature, const Quest* void AddSC_wetlands() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_tapoke_slim_jahn"; - newscript->GetAI = &GetAI_npc_tapoke_slim_jahn; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_tapoke_slim_jahn"; + pNewScript->GetAI = &GetAI_npc_tapoke_slim_jahn; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_mikhail"; - newscript->pQuestAccept = &QuestAccept_npc_mikhail; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_mikhail"; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_mikhail; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp b/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp index 20b3ca5bc5..6afdd95aa1 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,23 +38,17 @@ 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 @@ -73,31 +67,31 @@ struct MANGOS_DLL_DECL boss_akilzonAI : public ScriptedAI uint32 m_uiStormTimer; uint32 m_uiSummonEagleTimer; uint32 m_uiBerserkTimer; - bool m_bIsBerserk; void Reset() { - 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); - m_creature->SetInCombatWithZone(); + + if (m_pInstance) + 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); @@ -107,77 +101,102 @@ struct MANGOS_DLL_DECL boss_akilzonAI : public ScriptedAI m_pInstance->SetData(TYPE_AKILZON, DONE); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_AKILZON, FAIL); + } + + 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(); } @@ -188,12 +207,6 @@ 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 { mob_soaring_eagleAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -207,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() { - 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; @@ -231,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() @@ -244,49 +254,48 @@ struct MANGOS_DLL_DECL mob_soaring_eagleAI : public ScriptedAI if (!m_pInstance) return; - if (Creature* pAzkil = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_AKILZON))) + 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); - if (m_creature->HasSplineFlag(SPLINEFLAG_WALKMODE)) - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - - m_creature->GetMotionMaster()->MovePoint(POINT_ID_RANDOM, fX, fY, fZ); - - m_bCanMoveToRandom = false; + m_creature->SetWalk(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; + } } }; @@ -297,15 +306,15 @@ CreatureAI* GetAI_mob_soaring_eagle(Creature* pCreature) void AddSC_boss_akilzon() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_akilzon"; - newscript->GetAI = &GetAI_boss_akilzon; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_akilzon"; + pNewScript->GetAI = &GetAI_boss_akilzon; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_soaring_eagle"; - newscript->GetAI = &GetAI_mob_soaring_eagle; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_soaring_eagle"; + pNewScript->GetAI = &GetAI_mob_soaring_eagle; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp b/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp index f4c9b4afe9..e025cf1990 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 @@ -80,53 +85,57 @@ 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; + + bool m_bHasTransformed; + + ObjectGuid m_spiritLynxGuid; void Reset() { - 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->instance->GetCreature(m_pInstance->GetData64(DATA_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, NOT_STARTED); + if (m_pInstance) + m_pInstance->SetData(TYPE_HALAZZI, FAIL); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - m_creature->SetInCombatWithZone(); if (m_pInstance) m_pInstance->SetData(TYPE_HALAZZI, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -134,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); @@ -142,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->instance->GetCreature(m_pInstance->GetData64(DATA_SPIRIT_LYNX)); - if (m_creature->GetHealthPercent() < 10.0f || - (pSpiritLynx && pSpiritLynx->GetHealthPercent() < 10.0f)) - { - m_uiPhase = PHASE_SINGLE; - - DoScriptText(SAY_MERGE, m_creature); - - uint32 uiSpellId; - - 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(); } }; @@ -333,28 +314,25 @@ struct MANGOS_DLL_DECL boss_spirit_lynxAI : public ScriptedAI uint32 m_uiFrenzyTimer; uint32 m_uiShredArmorTimer; + bool m_bHasUnited; void Reset() { - 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; - if (Creature* pHalazzi = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_HALAZZI))) + if (Creature* pHalazzi = m_pInstance->GetSingleCreatureFromStorage(NPC_HALAZZI)) pHalazzi->AI()->KilledUnit(pVictim); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -362,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; @@ -375,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(); } }; @@ -386,15 +376,15 @@ CreatureAI* GetAI_boss_spirit_lynx(Creature* pCreature) void AddSC_boss_halazzi() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_halazzi"; - newscript->GetAI = &GetAI_boss_halazzi; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_halazzi"; + pNewScript->GetAI = &GetAI_boss_halazzi; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_spirit_lynx"; - newscript->GetAI = &GetAI_boss_spirit_lynx; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_spirit_lynx"; + pNewScript->GetAI = &GetAI_boss_spirit_lynx; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp b/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp index 648e2096fb..111bcfd1a4 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,123 +85,79 @@ struct WaypointDef float m_fX, m_fY, m_fZ; }; -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} -}; - -WaypointDef m_aHatcherLeft[]= +static const WaypointDef m_aHatcherRight[] = { - {-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} + { -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} }; -float hatcherway_l[5][3] = +static const WaypointDef m_aHatcherLeft[] = { - {-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} + { -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} }; struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI { boss_janalaiAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiHatcher1GUID = 0; - m_uiHatcher2GUID = 0; m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } ScriptedInstance* m_pInstance; - uint32 fire_breath_timer; - - std::list m_lBombsGUIDList; - std::list m_lEggsRemainingList; - + uint32 m_uiFireBreathTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiHatcherTimer; + uint32 m_uiBerserkTimer; uint32 m_uiBombTimer; - uint32 m_uiBombSequenzeTimer; - uint32 m_uiBombPhase; - uint32 m_uiBombCounter; + uint32 m_uiBombAuraTimer; + uint32 m_uiExplodeTimer; - uint32 enrage_timer; - uint32 hatchertime; - uint32 eggs; - uint32 wipetimer; + uint8 m_uiEggsHatchedLeft; + uint8 m_uiEggsHatchedRight; - bool m_bIsBombing; - bool m_bCanBlowUpBombs; - bool m_bIsEggRemaining; - bool enraged; - bool enragetime; + bool m_bIsFlameWall; + bool m_bHasHatchedEggs; + bool m_bIsEnraged; - uint64 m_uiHatcher1GUID; - uint64 m_uiHatcher2GUID; + ObjectGuid m_hatcherOneGuid; + ObjectGuid m_hatcherTwoGuid; void Reset() { - m_lBombsGUIDList.clear(); - m_lEggsRemainingList.clear(); - - if (Creature* pHatcher = m_creature->GetMap()->GetCreature(m_uiHatcher1GUID)) - { - pHatcher->AI()->EnterEvadeMode(); - pHatcher->SetDeathState(JUST_DIED); - m_uiHatcher1GUID = 0; - } - - if (Creature* pHatcher = m_creature->GetMap()->GetCreature(m_uiHatcher2GUID)) - { - pHatcher->AI()->EnterEvadeMode(); - pHatcher->SetDeathState(JUST_DIED); - m_uiHatcher2GUID = 0; - } - - fire_breath_timer = 8000; - - m_uiBombTimer = 30000; - m_bIsBombing = false; - m_uiBombSequenzeTimer = 1500; - m_uiBombPhase = 0; - m_uiBombCounter = 0; - m_bCanBlowUpBombs = false; - m_bIsEggRemaining = true; - - enrage_timer = MINUTE*5*IN_MILLISECONDS; - hatchertime = 10000; - wipetimer = MINUTE*10*IN_MILLISECONDS; - enraged = false; - enragetime = false; + m_uiFireBreathTimer = 8000; + 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 { if (m_pInstance) - m_pInstance->SetData(TYPE_JANALAI, NOT_STARTED); + m_pInstance->SetData(TYPE_JANALAI, FAIL); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -221,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); @@ -234,323 +178,194 @@ 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_uiHatcher1GUID = pSummoned->GetGUID(); + 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_uiHatcher2GUID = pSummoned->GetGUID(); + 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->GetGUID()); - - 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 - { - 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); - } - - void Throw5Bombs() - { - //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() + // Wrapper to create the firewalls during Bomb phase + void DoCreateFireWall() { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) - { - Unit* pTemp = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER && !m_creature->IsWithinDist(pTemp, 20.0f)) - m_creature->CastSpell(pTemp, SPELL_SUMMONALL, true); - } + // 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 BlowUpBombs() + void UpdateAI(const uint32 uiDiff) override { - if (m_lBombsGUIDList.empty()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - for(std::list::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->GetGUID()); - 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); + if (DoCastSpellIfCan(pTarget, SPELL_FLAME_BREATH) == CAST_OK) + m_uiFireBreathTimer = 8000; } + } + else + m_uiFireBreathTimer -= uiDiff; - m_bIsEggRemaining = false; - - if (!m_pInstance) - return; - - if (uint32 uiEggsRemaining_Right = m_pInstance->GetData(DATA_J_EGGS_RIGHT)) + // Remove bomb aura after five seconds + if (m_uiBombAuraTimer) + { + if (m_uiBombAuraTimer <= uiDiff) { - for(uint32 i = 0; i < uiEggsRemaining_Right; ++i) - m_pInstance->SetData(DATA_J_EGGS_RIGHT, SPECIAL); + m_creature->RemoveAurasDueToSpell(SPELL_FIRE_BOMB_CHANNEL); + m_uiBombAuraTimer = 0; + m_uiExplodeTimer = 5000; } + else + m_uiBombAuraTimer -= uiDiff; + } - if (uint32 uiEggsRemaining_Left = m_pInstance->GetData(DATA_J_EGGS_LEFT)) + // Explode the summoned bombs on timer + if (m_uiExplodeTimer) + { + if (m_uiExplodeTimer <= uiDiff) { - for(uint32 i = 0; i < uiEggsRemaining_Left; ++i) - m_pInstance->SetData(DATA_J_EGGS_LEFT, SPECIAL); + if (DoCastSpellIfCan(m_creature, SPELL_FIRE_BOMB_EXPLODE) == CAST_OK) + m_uiExplodeTimer = 0; } + else + m_uiExplodeTimer -= uiDiff; } - } - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //blow up bombs happen after bombing is over, so handle this here - if (m_bCanBlowUpBombs) + // Hatch all eggs at 35% health + if (!m_bHasHatchedEggs && m_creature->GetHealthPercent() < 35.0f) { - if (m_uiBombSequenzeTimer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_HATCH_ALL_EGGS) == CAST_OK) { - BlowUpBombs(); - m_bCanBlowUpBombs = false; - }else m_uiBombSequenzeTimer -= diff; + DoScriptText(SAY_ALL_EGGS, m_creature); + m_bHasHatchedEggs = true; + } } - if (!m_bIsBombing) // every Spell if NOT Bombing + // Soft Enrage - after 5 min, or at 20% health + if (!m_bIsEnraged) { - if (m_uiBombTimer < diff) + if (m_uiEnrageTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - 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_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; - }else m_uiBombTimer -=diff; - - //FIRE BREATH several videos says every 8Secounds - if (fire_breath_timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_FLAME_BREATH); - fire_breath_timer = 8000; - }else fire_breath_timer -=diff; - - //enrage if under 25% hp before 5 min. - if (m_creature->GetHealthPercent() < 25.0f && !enraged) - { - enragetime = true; - enrage_timer = 600000; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bIsEnraged = true; } + else + m_uiEnrageTimer -= uiDiff; - //Enrage but only if not bombing - if (enragetime && !enraged) + if (m_creature->GetHealthPercent() < 20.0f) { - DoScriptText(SAY_BERSERK, m_creature); - - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature,SPELL_ENRAGE); - enraged = true; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bIsEnraged = true; } + } - //Hatch All - if (m_bIsEggRemaining && m_creature->GetHealthPercent() < 35.0f) + // Spawn Hatchers - if necessary + if (!m_bHasHatchedEggs) + { + if (m_uiHatcherTimer < uiDiff) { - DoScriptText(SAY_ALL_EGGS, m_creature); + DoScriptText(SAY_SUMMON_HATCHER, m_creature); - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); + Creature* pHatcer1 = m_creature->GetMap()->GetCreature(m_hatcherOneGuid); + Creature* pHatcer2 = m_creature->GetMap()->GetCreature(m_hatcherTwoGuid); - DoCastSpellIfCan(m_creature, SPELL_HATCH_ALL_EGGS); + if (!pHatcer1 || !pHatcer1->isAlive()) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_HATCHER_1, CAST_TRIGGERED); - DoHatchRemainingEggs(); - } + if (!pHatcer2 || !pHatcer2->isAlive()) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_HATCHER_2, CAST_TRIGGERED); - DoMeleeAttackIfReady(); - } - else // every Spell if Bombing - { - if (m_uiBombSequenzeTimer < diff) - { - switch(m_uiBombPhase) - { - case 0: - m_creature->CastSpell(m_creature,SPELL_FIRE_BOMB_CHANNEL,true); - 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; - } - - }else m_uiBombSequenzeTimer -= diff; + m_uiHatcherTimer = 90000; + } + else + m_uiHatcherTimer -= uiDiff; } - //Enrage after 5 minutes - if (enrage_timer < diff) + // Hard enrage + if (m_uiBerserkTimer) { - enragetime = true; - enrage_timer = 600000; - }else enrage_timer -=diff; - - //Call Hatcher - if (m_bIsEggRemaining) - { - if (hatchertime < diff) + if (m_uiBerserkTimer <= uiDiff) { - if (!m_pInstance || (m_pInstance->GetData(DATA_J_EGGS_LEFT) == 0 && m_pInstance->GetData(DATA_J_EGGS_RIGHT) == 0)) - m_bIsEggRemaining = false; - else + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) { - DoScriptText(SAY_SUMMON_HATCHER, m_creature); - - Creature* pHatcer1 = m_creature->GetMap()->GetCreature(m_uiHatcher1GUID); - Creature* pHatcer2 = m_creature->GetMap()->GetCreature(m_uiHatcher2GUID); - - 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 (!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); - } - - hatchertime = 90000; + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; } - - }else hatchertime -=diff; + } + else + m_uiBerserkTimer -= uiDiff; } - //WIPE after 10 minutes - if (wipetimer < diff) - { - if (DoCastSpellIfCan(m_creature,SPELL_ENRAGE) == CAST_OK) - { - DoScriptText(SAY_BERSERK, m_creature); - wipetimer = 30000; - } - }else wipetimer -=diff; + DoMeleeAttackIfReady(); - //check for reset ... exploit preventing ... pulled from his podest - EnterEvadeIfOutOfCombatArea(diff); + // check for reset ... exploit preventing ... pulled from his podest + EnterEvadeIfOutOfCombatArea(uiDiff); } }; @@ -559,27 +374,9 @@ CreatureAI* GetAI_boss_janalaiAI(Creature* pCreature) return new boss_janalaiAI(pCreature); } -struct MANGOS_DLL_DECL mob_jandalai_firebombAI : public ScriptedAI -{ - mob_jandalai_firebombAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() {} - - void AttackStart(Unit* who) {} - - void MoveInLineOfSight(Unit* who) {} - - void UpdateAI(const uint32 diff) {} -}; - -CreatureAI* GetAI_mob_jandalai_firebombAI(Creature* pCreature) -{ - return new mob_jandalai_firebombAI(pCreature); -} - -struct MANGOS_DLL_DECL mob_amanishi_hatcherAI : public ScriptedAI +struct MANGOS_DLL_DECL npc_amanishi_hatcherAI : public ScriptedAI { - mob_amanishi_hatcherAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_amanishi_hatcherAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -589,196 +386,158 @@ struct MANGOS_DLL_DECL mob_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() { - m_uiWaypoint = 0; - m_uiHatchlingTimer = 1000; - m_uiHatchlingCount = 1; - m_bCanMoveNext = false; - m_bWaypointEnd = false; - - if (m_creature->HasSplineFlag(SPLINEFLAG_WALKMODE)) - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + 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 ? DATA_J_EGGS_RIGHT : DATA_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(DATA_J_EGGS_RIGHT) : m_pInstance->GetData(DATA_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; + } + else + m_uiHatchlingTimer -= uiDiff; } } }; -CreatureAI* GetAI_mob_amanishi_hatcherAI(Creature* pCreature) +CreatureAI* GetAI_npc_amanishi_hatcherAI(Creature* pCreature) { - return new mob_amanishi_hatcherAI(pCreature); + return new npc_amanishi_hatcherAI(pCreature); } -struct MANGOS_DLL_DECL mob_hatchlingAI : public ScriptedAI +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct MANGOS_DLL_DECL npc_dragonhawk_eggAI : public Scripted_NoMovementAI { - mob_hatchlingAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + npc_dragonhawk_eggAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} - ScriptedInstance* m_pInstance; - - uint32 buffer_timer; - bool start; - - void Reset() - { - buffer_timer = 7000; - start = false; - } - - void UpdateAI(const uint32 diff) - { - if (!start) - { - 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]); - start = true; - } + void Reset() {} - if (m_pInstance && m_pInstance->GetData(TYPE_JANALAI) == NOT_STARTED) - { - 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 (buffer_timer < diff) - { - 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 MANGOS_DLL_DECL npc_janalai_firebombAI : public Scripted_NoMovementAI +{ + npc_janalai_firebombAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} - buffer_timer = 7000; - }else buffer_timer -=diff; + void Reset() {} - DoMeleeAttackIfReady(); - } + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} }; -CreatureAI* GetAI_mob_hatchlingAI(Creature* pCreature) +CreatureAI* GetAI_npc_janalai_firebombAI(Creature* pCreature) { - return new mob_hatchlingAI(pCreature); + return new npc_janalai_firebombAI(pCreature); } void AddSC_boss_janalai() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_janalai"; - newscript->GetAI = &GetAI_boss_janalaiAI; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_jandalai_firebomb"; - newscript->GetAI = &GetAI_mob_jandalai_firebombAI; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_amanishi_hatcher"; - newscript->GetAI = &GetAI_mob_amanishi_hatcherAI; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_hatchling"; - newscript->GetAI = &GetAI_mob_hatchlingAI; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "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; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_amanishi_hatcher"; + pNewScript->GetAI = &GetAI_npc_amanishi_hatcherAI; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp b/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp index d1df11ae96..43e2f4b920 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Malacrass -SD%Complete: 10 -SDComment: Contain adds and adds selection +SD%Complete: 80 +SDComment: Contain adds and adds selection; Stolen abilities timers need improvement SDCategory: Zul'Aman EndScriptData */ @@ -38,38 +38,45 @@ enum SAY_ADD_DIED3 = -1568054, SAY_DEATH = -1568055, + /* Notes about the event: + * The boss casts siphon soul right after he finishes the spirit bolts channel, which takes 10 sec + * The siphon soul is a channeled spell for 30 sec during which the boss uses some class abilities of the target + * Basically the boss casts a dummy spell which chooses a random target on which it casts the actuall channel spell + * The drain power spell acts as a enrage timer. It's cast each 30 seconds after the boss' health is below 80% + */ SPELL_SPIRIT_BOLTS = 43383, + SPELL_SIPHON_SOUL_DUMMY = 43498, 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 = 61606, - SPELL_DK_MARK_OF_BLOOD = 61600, + 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, @@ -77,50 +84,133 @@ 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 = 43457, + 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 - //WEAPON_ID = 33494, //weapon equip id, must be set by database. + // misc + TARGET_TYPE_RANDOM = 0, + TARGET_TYPE_VICTIM = 1, + TARGET_TYPE_SELF = 2, + TARGET_TYPE_FRIENDLY = 3, + MAX_ACTIVE_ADDS = 4 }; -//Adds X positions -static float m_afAddPosX[4] = {128.279f, 123.261f, 112.084f, 106.473f}; +// Adds positions +static const float m_aAddPositions[MAX_ACTIVE_ADDS][4] = +{ + {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}, +}; -const float ADD_POS_Y = 921.279f; -const float ADD_POS_Z = 33.889f; -const float ADD_ORIENT = 1.527f; +// Each position is a random of two spawns +static const uint32 aSpawnEntries[MAX_ACTIVE_ADDS][2] = +{ + {NPC_ALYSON, NPC_THURG}, + {NPC_SLITHER, NPC_RADAAN}, + {NPC_GAZAKROTH, NPC_FENSTALKER}, + {NPC_DARKHEART, NPC_KORAGG}, +}; -struct SpawnGroup +struct PlayerAbilityStruct { - uint32 m_uiCreatureEntry; - uint32 m_uiCreatureEntryAlt; + uint32 m_uiSpellId; + uint8 m_uiTargetType; + uint32 m_uiInitialTimer, m_uiCooldown; }; -SpawnGroup m_auiSpawnEntry[] = +// Classes are in the same order as they are in DBC +static PlayerAbilityStruct m_aMalacrassStolenAbility[][4] = { - {24240, 24241}, //Alyson Antille / Thurg - {24242, 24243}, //Slither / Lord Raadan - {24244, 24245}, //Gazakroth / Fenstalker - {24246, 24247}, //Darkheart / Koragg + { + // 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 + {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 + {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 + {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 + {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 + {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 + {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 + {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 + {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 + {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 + }, + { + // 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 @@ -128,105 +218,85 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI boss_malacrassAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - memset(&m_auiAddGUIDs, 0, sizeof(m_auiAddGUIDs)); - m_lAddsEntryList.clear(); Reset(); } ScriptedInstance* m_pInstance; - std::list m_lAddsEntryList; - uint64 m_auiAddGUIDs[MAX_ACTIVE_ADDS]; + uint32 m_uiSpiritBoltsTimer; + uint32 m_uiDrainPowerTimer; + uint32 m_uiSiphonSoulTimer; + uint32 m_uiPlayerAbilityTimer; + uint8 m_uiPlayerClass; + + bool m_bCanUsePlayerSpell; + + std::vector m_vAddsEntryList; + std::vector m_vPlayerSpellTimer; void Reset() { - InitializeAdds(); + m_uiSpiritBoltsTimer = 30000; + m_uiDrainPowerTimer = 0; + m_uiSiphonSoulTimer = 40000; + m_uiPlayerAbilityTimer = 10000; + m_uiPlayerClass = 0; - if (!m_pInstance) - return; + m_bCanUsePlayerSpell = false; - m_pInstance->SetData(TYPE_MALACRASS, NOT_STARTED); + 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_auiAddGUIDs[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_auiAddGUIDs[j] = pAdd->GetGUID(); - - ++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_auiAddGUIDs[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_auiAddGUIDs[j] = pAdd->GetGUID(); - } - ++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 { - m_creature->SetInCombatWithZone(); - 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_auiAddGUIDs[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; @@ -234,634 +304,149 @@ 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; - - m_pInstance->SetData(TYPE_MALACRASS, DONE); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALACRASS, DONE); } - void CleanAdds() + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override { - for(uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) + switch (urand(0, 2)) { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_auiAddGUIDs[i])) - { - pAdd->AI()->EnterEvadeMode(); - pAdd->SetDeathState(JUST_DIED); - } + 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; } - - memset(&m_auiAddGUIDs, 0, sizeof(m_auiAddGUIDs)); - m_lAddsEntryList.clear(); } - void UpdateAI(const uint32 uiDiff) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; - -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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_MALACRASS))) - pMalacrass->AI()->KilledUnit(pVictim); - } - - void JustDied(Unit* pKiller) - { - if (!m_pInstance) - return; - - if (Creature* pMalacrass = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_MALACRASS))) + // Set the player's class when hit with soul siphon + if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_SIPHON_SOUL) { - 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; - } - } - } - - bool IsEnemyPlayerInRangeForSpell(uint32 uiSpellId) - { - SpellEntry const* pSpell = GetSpellStore()->LookupEntry(uiSpellId); - - //if spell not valid - if (!pSpell) - return false; - - //spell known, so lookup using rangeIndex - SpellRangeEntry const* pSpellRange = GetSpellRangeStore()->LookupEntry(pSpell->rangeIndex); + m_uiPlayerClass = ((Player*)pTarget)->getClass(); + m_bCanUsePlayerSpell = true; - //not valid, so return - if (!pSpellRange) - return false; + // In case the player it's priest we can choose either a holy priest or a shadow priest + if (m_uiPlayerClass == CLASS_PRIEST) + m_uiPlayerClass = urand(0, 1) ? CLASS_PRIEST : 0; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator iter = tList.begin();iter != tList.end(); ++iter) - { - Unit* pTarget = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid()); + // Init the spell timers + uint8 m_uiMaxSpells = m_uiPlayerClass == CLASS_MAGE ? 4 : 3; - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - { - //if target further away than maxrange or closer than minrange, statement is false - if (m_creature->IsInRange(pTarget, pSpellRange->minRange, pSpellRange->maxRange)) - return true; - } + m_vPlayerSpellTimer.clear(); + m_vPlayerSpellTimer.reserve(m_uiMaxSpells); + for (uint8 i = 0; i < m_uiMaxSpells; ++i) + m_vPlayerSpellTimer.push_back(m_aMalacrassStolenAbility[m_uiPlayerClass][i].m_uiInitialTimer); } - - return false; } -}; - -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() + bool CanUseSpecialAbility(uint32 uiSpellIndex) { - m_uiBloodlustTimer = 15000; - m_uiCleaveTimer = 10000; - } + Unit* pTarget = NULL; - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiBloodlustTimer < uiDiff) + switch (m_aMalacrassStolenAbility[m_uiPlayerClass][uiSpellIndex].m_uiTargetType) { - std::list lTempList = DoFindFriendlyMissingBuff(50.0f, SPELL_BLOODLUST); - - if (!lTempList.empty()) - { - Unit* pTarget = *(lTempList.begin()); - DoCastSpellIfCan(pTarget, SPELL_BLOODLUST); - } - - m_uiBloodlustTimer = 12000; + 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); + break; + case TARGET_TYPE_FRIENDLY: + pTarget = DoSelectLowestHpFriendly(50.0f); + break; } - else - m_uiBloodlustTimer -= uiDiff; - if (m_uiCleaveTimer < uiDiff) + if (pTarget) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 12000; + if (DoCastSpellIfCan(pTarget, m_aMalacrassStolenAbility[m_uiPlayerClass][uiSpellIndex].m_uiSpellId, CAST_TRIGGERED) == CAST_OK) + return true; } - 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); - } + return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiArcaneTorrentTimer < uiDiff) + // Acts as an enrage timer + if (m_creature->GetHealthPercent() < 80.0f) { - if (IsEnemyPlayerInRangeForSpell(SPELL_ARCANE_TORRENT)) + if (m_uiDrainPowerTimer < uiDiff) { - 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 (DoCastSpellIfCan(m_creature, SPELL_DRAIN_POWER) == CAST_OK) { - //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); - } + DoScriptText(SAY_DRAIN_POWER, m_creature); + m_uiDrainPowerTimer = 30000; } } - - 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); + m_uiDrainPowerTimer -= uiDiff; } - } - - 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_uiSpiritBoltsTimer < uiDiff) { - if (IsEnemyPlayerInRangeForSpell(SPELL_THUNDERCLAP)) + if (DoCastSpellIfCan(m_creature, SPELL_SPIRIT_BOLTS) == CAST_OK) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_THUNDERCLAP); - m_uiThunderclapTimer = 12000; + DoScriptText(SAY_SPIRIT_BOLTS, m_creature); + m_bCanUsePlayerSpell = false; + m_uiSpiritBoltsTimer = 40000; } - else - m_uiThunderclapTimer = 1000; } else - m_uiThunderclapTimer -= uiDiff; + m_uiSpiritBoltsTimer -= uiDiff; - if (m_uiFlameBreathTimer < uiDiff) + if (m_uiSiphonSoulTimer < 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 (IsEnemyPlayerInRangeForSpell(SPELL_PSYCHIC_WAIL)) + if (DoCastSpellIfCan(m_creature, SPELL_SIPHON_SOUL_DUMMY) == CAST_OK) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHIC_WAIL); - m_uiPsychicWailTimer = 12000; + DoScriptText(SAY_SOUL_SIPHON, m_creature); + m_uiSiphonSoulTimer = 40000; } - 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; + m_uiSiphonSoulTimer -= 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) + // Use abilities only during the siphon soul phases + if (m_bCanUsePlayerSpell) { - 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; + // Loop through all abilities + for (uint8 i = 0; i < m_vPlayerSpellTimer.size(); ++i) + { + if (m_vPlayerSpellTimer[i] < uiDiff) + { + if (CanUseSpecialAbility(i)) + m_vPlayerSpellTimer[i] = m_aMalacrassStolenAbility[m_uiPlayerClass][i].m_uiCooldown; + } + else + m_vPlayerSpellTimer[i] -= uiDiff; + } } - else - m_uiColdStareTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_mob_koragg(Creature* pCreature) +CreatureAI* GetAI_boss_malacrass(Creature* pCreature) { - return new mob_koraggAI(pCreature); + return new boss_malacrassAI(pCreature); } void AddSC_boss_malacrass() { - Script* newscript; - - newscript = new Script; - newscript->Name = "boss_malacrass"; - newscript->GetAI = &GetAI_boss_malacrass; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_thurg"; - newscript->GetAI = &GetAI_mob_thurg; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_gazakroth"; - newscript->GetAI = &GetAI_mob_gazakroth; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_lord_raadan"; - newscript->GetAI = &GetAI_mob_lord_raadan; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_darkheart"; - newscript->GetAI = &GetAI_mob_darkheart; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_slither"; - newscript->GetAI = &GetAI_mob_slither; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_fenstalker"; - newscript->GetAI = &GetAI_mob_fenstalker; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_koragg"; - newscript->GetAI = &GetAI_mob_koragg; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_alyson_antille"; - newscript->GetAI = &GetAI_mob_alyson_antille; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_malacrass"; + pNewScript->GetAI = &GetAI_boss_malacrass; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp b/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp index 68548d86ed..aead25ead0 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,72 +38,125 @@ 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_BRUTALSWIPE = 42384, + // Defines for Troll form + SPELL_BRUTAL_SWIPE = 42384, SPELL_MANGLE = 42389, SPELL_SURGE = 42402, - SPELL_BEARFORM = 42377, + SPELL_BEAR_SHAPE = 42377, - //Defines for Bear form - SPELL_LACERATINGSLASH = 42395, - SPELL_RENDFLESH = 42397, - SPELL_DEAFENINGROAR = 42398 + // Defines for Bear form + SPELL_LACERATING_SLASH = 42395, + SPELL_REND_FLESH = 42397, + SPELL_DEAFENING_ROAR = 42398 }; struct MANGOS_DLL_DECL 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; - - uint32 ChangeForm_Timer; - uint32 BrutalSwipe_Timer; - uint32 Mangle_Timer; - uint32 Surge_Timer; - uint32 LaceratingSlash_Timer; - uint32 RendFlesh_Timer; - uint32 DeafeningRoar_Timer; - uint32 ShapeShiftCheck_Timer; - uint32 Berserk_Timer; - bool inBearForm; - bool Berserking; - bool ChangedToBear; - bool ChangedToTroll; + instance_zulaman* m_pInstance; + + uint32 m_uiChangeFormTimer; + uint32 m_uiBrutalSwipeTimer; + uint32 m_uiMangleTimer; + uint32 m_uiSurgeTimer; + uint32 m_uiLaceratingSlashTimer; + uint32 m_uiRendFleshTimer; + uint32 m_uiDeafeningRoarTimer; + uint32 m_uiBerserkTimer; + uint8 m_uiCurrentWave; + bool m_bIsInBearForm; void Reset() { - ChangeForm_Timer = 45000; - BrutalSwipe_Timer = 12000; - Mangle_Timer = 15000; - Surge_Timer = 20000; - LaceratingSlash_Timer = 6000; - RendFlesh_Timer = 6000; - DeafeningRoar_Timer = 20000; - ShapeShiftCheck_Timer = 40000; - Berserk_Timer = 600000; - inBearForm = false; - Berserking = false; - ChangedToBear = false; - ChangedToTroll = true; + m_uiChangeFormTimer = 45000; + m_uiBrutalSwipeTimer = 12000; + m_uiMangleTimer = 15000; + m_uiSurgeTimer = 20000; + m_uiLaceratingSlashTimer = 6000; + m_uiRendFleshTimer = 6000; + m_uiDeafeningRoarTimer = 20000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_bIsInBearForm = false; + } + + 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 *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_NALORAKK, IN_PROGRESS); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -118,124 +166,127 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI m_pInstance->SetData(TYPE_NALORAKK, DONE); } - 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; - //Berserking - if ((Berserk_Timer < diff) && (!Berserking)) + // Berserking + if (m_uiBerserkTimer) { - if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + if (m_uiBerserkTimer <= uiDiff) { - DoScriptText(SAY_BERSERK, m_creature); - Berserking = true; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } } - }else Berserk_Timer -= diff; - - //Don't check if we're shapeshifted every UpdateAI - if (ShapeShiftCheck_Timer < diff) - { - //This will return true if we have bearform aura - inBearForm = m_creature->HasAura(SPELL_BEARFORM, EFFECT_INDEX_0); - ShapeShiftCheck_Timer = 1000; - }else ShapeShiftCheck_Timer -= diff; + else + m_uiBerserkTimer -= uiDiff; + } - //Spells for Troll Form (only to be casted if we NOT have bear phase aura) - if (!inBearForm) + // Spells for Troll Form (only to be casted if we NOT have bear phase aura) + if (!m_bIsInBearForm) { - //We just changed to troll form! - if (!ChangedToTroll) + // Brutal Swipe (some sources may say otherwise, but I've never seen this in Bear form) + if (m_uiBrutalSwipeTimer < uiDiff) { - DoScriptText(SAY_TOTROLL, m_creature); - - ChangedToTroll = true; - ChangedToBear = false; - //Reset spell timers - LaceratingSlash_Timer = urand(6000, 25000); - RendFlesh_Timer = urand(6000, 25000); - DeafeningRoar_Timer = urand(15000, 25000); - ShapeShiftCheck_Timer = 40000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BRUTAL_SWIPE) == CAST_OK) + m_uiBrutalSwipeTimer = urand(7000, 15000); } + else + m_uiBrutalSwipeTimer -= uiDiff; - //Brutal Swipe (some sources may say otherwise, but I've never seen this in Bear form) - if (BrutalSwipe_Timer < diff) + // Mangle + if (m_uiMangleTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BRUTALSWIPE); - BrutalSwipe_Timer = urand(7000, 15000); - }else BrutalSwipe_Timer -= diff; - - //Mangle - if (Mangle_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE); - Mangle_Timer = urand(3000, 15000); - }else Mangle_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE) == CAST_OK) + m_uiMangleTimer = urand(3000, 15000); + } + else + m_uiMangleTimer -= uiDiff; - //Surge - if (Surge_Timer < diff) + // Surge + if (m_uiSurgeTimer < uiDiff) { - //select a random unit other than the main tank - Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + // 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 (!target) - target = m_creature->getVictim(); + // if there aren't other units, cast on the tank + if (!pTtarget) + pTtarget = m_creature->getVictim(); - if (DoCastSpellIfCan(target, SPELL_SURGE) == CAST_OK) + if (DoCastSpellIfCan(pTtarget, SPELL_SURGE) == CAST_OK) + { DoScriptText(SAY_SURGE, m_creature); + m_uiSurgeTimer = urand(15000, 32500); + } + } + else + m_uiSurgeTimer -= uiDiff; - Surge_Timer = urand(15000, 32500); - }else Surge_Timer -= diff; - - //Change to Bear Form if we're in Troll Form for 45sec - if (ChangeForm_Timer < diff) + // Change to Bear Form if we're in Troll Form for 45sec + if (m_uiChangeFormTimer < uiDiff) { - m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - DoCastSpellIfCan(m_creature, SPELL_BEARFORM); - //And 30sec (bear form) + 45sec (troll form) before we should cast this again - ChangeForm_Timer = 75000; - }else ChangeForm_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_BEAR_SHAPE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_TOBEAR, m_creature); + m_uiChangeFormTimer = 30000; + m_bIsInBearForm = true; + // Reset bear form timers + m_uiLaceratingSlashTimer = urand(6000, 25000); + m_uiRendFleshTimer = urand(6000, 25000); + m_uiDeafeningRoarTimer = urand(15000, 25000); + } + } + 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 { - //We just changed to bear form! - if (!ChangedToBear) + // Timer to yell and reset spell timers when bear aura expires + if (m_uiChangeFormTimer < uiDiff) { - DoScriptText(SAY_TOBEAR, m_creature); - - ChangedToBear = true; - ChangedToTroll = false; - //Reset spell timers - Surge_Timer = urand(15000, 32000); - BrutalSwipe_Timer = urand(7000, 20000); - Mangle_Timer = urand(3000, 20000); - ShapeShiftCheck_Timer = 25000; + DoScriptText(SAY_TOTROLL, m_creature); + m_uiChangeFormTimer = 45000; + m_bIsInBearForm = false; + // Reset troll form timers + m_uiSurgeTimer = urand(15000, 32000); + m_uiBrutalSwipeTimer = urand(7000, 20000); + m_uiMangleTimer = urand(3000, 20000); } + else + m_uiChangeFormTimer -= uiDiff; - //Lacerating Slash - if (LaceratingSlash_Timer < diff) + // Lacerating Slash + if (m_uiLaceratingSlashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_LACERATINGSLASH); - LaceratingSlash_Timer = urand(6000, 20000); - }else LaceratingSlash_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_LACERATING_SLASH) == CAST_OK) + m_uiLaceratingSlashTimer = urand(6000, 20000); + } + else + m_uiLaceratingSlashTimer -= uiDiff; - //Rend Flesh - if (RendFlesh_Timer < diff) + // Rend Flesh + if (m_uiRendFleshTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_RENDFLESH); - RendFlesh_Timer = urand(6000, 20000); - }else RendFlesh_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_REND_FLESH) == CAST_OK) + m_uiRendFleshTimer = urand(6000, 20000); + } + else + m_uiRendFleshTimer -= uiDiff; - //Deafening Roar - if (DeafeningRoar_Timer < diff) + // Deafening Roar + if (m_uiDeafeningRoarTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEAFENINGROAR); - DeafeningRoar_Timer = urand(15000, 25000); - }else DeafeningRoar_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_DEAFENING_ROAR) == CAST_OK) + m_uiDeafeningRoarTimer = urand(15000, 25000); + } + else + m_uiDeafeningRoarTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -249,9 +300,10 @@ CreatureAI* GetAI_boss_nalorakk(Creature* pCreature) void AddSC_boss_nalorakk() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_nalorakk"; - newscript->GetAI = &GetAI_boss_nalorakk; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_nalorakk"; + pNewScript->GetAI = &GetAI_boss_nalorakk; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp b/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp index 6a4415edfe..58a8fb2b57 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Zuljin -SD%Complete: 0 -SDComment: +SD%Complete: 90 +SDComment: Timers should be improved. SDCategory: Zul'Aman EndScriptData */ @@ -38,40 +38,43 @@ enum SAY_KILL2 = -1568065, SAY_DEATH = -1568066, + EMOTE_BEAR_SPIRIT = -1568082, + EMOTE_EAGLE_SPIRIT = -1568083, + EMOTE_LYNX_SPIRIT = -1568084, + EMOTE_DRAGONHAWK_SPIRIT = -1568085, + // 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 - SPELL_ZAP_INFORM = 42577, - SPELL_ZAP_DAMAGE = 43137, //1250 damage - SPELL_SUMMON_CYCLONE = 43112, //summon four feather vortex - CREATURE_FEATHER_VORTEX = 24136, - 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, + SPELL_CLAW_RAGE = 42583, // Charges a random target and applies dummy effect 43149 on it SPELL_CLAW_RAGE_TRIGGER = 43149, - SPELL_CLAW_RAGE_DAMAGE = 43150, - SPELL_LYNX_RUSH_HASTE = 43152, - SPELL_LYNX_RUSH_DAMAGE = 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 - CREATURE_COLUMN_OF_FIRE = 24187, - SPELL_PILLAR_TRIGGER = 43218, //trigger 43217 + SPELL_SUMMON_PILLAR = 43216, // summon 24187 + NPC_COLUMN_OF_FIRE = 24187, + SPELL_PILLAR_TRIGGER = 43218, // trigger 43217 // Cosmetic - SPELL_SPIRIT_AURA = 42466, - SPELL_SIPHON_SOUL = 43501, + SPELL_SPIRIT_DRAINED = 42520, + SPELL_SPIRIT_DRAIN = 42542, // Transforms SPELL_SHAPE_OF_THE_BEAR = 42594, @@ -79,47 +82,133 @@ enum SPELL_SHAPE_OF_THE_LYNX = 42607, SPELL_SHAPE_OF_THE_DRAGONHAWK = 42608, - SPELL_BERSERK = 45078, + SPELL_BERSERK = 45078, // Berserk timer or existance is unk - WEAPON_ID = 33975, + MAX_VORTEXES = 4, + MAX_LYNX_RUSH = 10, + POINT_ID_CENTER = 0, PHASE_BEAR = 0, PHASE_EAGLE = 1, PHASE_LYNX = 2, PHASE_DRAGONHAWK = 3, - PHASE_TROLL = 4 + PHASE_TROLL = 4, +}; + +struct BossPhase +{ + uint32 uiSpiritSpellId; + int32 iYellId, iEmoteId; + uint32 uiSpiritId; + uint8 uiPhase; +}; + +static const BossPhase aZuljinPhases[] = +{ + {SPELL_SHAPE_OF_THE_BEAR, SAY_BEAR_TRANSFORM, EMOTE_BEAR_SPIRIT, NPC_BEAR_SPIRIT, PHASE_BEAR}, + {SPELL_SHAPE_OF_THE_EAGLE, SAY_EAGLE_TRANSFORM, EMOTE_EAGLE_SPIRIT, NPC_EAGLE_SPIRIT, PHASE_EAGLE}, + {SPELL_SHAPE_OF_THE_LYNX, SAY_LYNX_TRANSFORM, EMOTE_LYNX_SPIRIT, NPC_LYNX_SPIRIT, PHASE_LYNX}, + {SPELL_SHAPE_OF_THE_DRAGONHAWK, SAY_DRAGONHAWK_TRANSFORM, EMOTE_DRAGONHAWK_SPIRIT, NPC_DRAGONHAWK_SPIRIT, PHASE_DRAGONHAWK} }; -//coords for going for changing form -const float CENTER_X = 120.148811f; -const float CENTER_Y = 703.713684f; -const float CENTER_Z = 45.111477f; +// coords for going for changing form +static const float fZuljinMoveLoc[3] = {120.148811f, 703.713684f, 45.111477f}; + +/*###### +## boss_zuljin +######*/ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI { boss_zuljinAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bHasTaunted = false; Reset(); } ScriptedInstance* m_pInstance; + uint8 m_uiPhase; + uint8 m_uiHealthCheck; + + uint32 m_uiWhirlwindTimer; + uint32 m_uiGrievousThrowTimer; + + uint32 m_uiParalysisTimer; + uint32 m_uiOverpowerTimer; + + uint32 m_uiClawRageTimer; + uint32 m_uiLynxRushTimer; + uint8 m_uiLynxRushCount; + + uint32 m_uiFlameWhirlTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiPillarOfFireTimer; + + bool m_bHasTaunted; + bool m_bIsInTransition; + uint32 m_uiTransformTimer; + + GuidList m_lSummonsList; + void Reset() { + m_uiHealthCheck = 80; + m_uiPhase = PHASE_TROLL; + + m_uiWhirlwindTimer = 7000; + m_uiGrievousThrowTimer = 8000; + + m_uiParalysisTimer = 7000; + m_uiOverpowerTimer = 5000; + + m_uiClawRageTimer = 5000; + m_uiLynxRushTimer = 15000; + m_uiLynxRushCount = 0; + + m_uiFlameWhirlTimer = 7000; + m_uiFlameBreathTimer = 15000; + m_uiPillarOfFireTimer = 7000; + + m_bIsInTransition = false; + + SetCombatMovement(true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ZULJIN, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ZULJIN, FAIL); + + // Despawn all feather vortexes + DoDespawnVortexes(); + + // Reset all spirits + for (uint8 i = 0; i < MAX_VORTEXES; ++i) + { + if (Creature* pSpirit = m_pInstance->GetSingleCreatureFromStorage(aZuljinPhases[i].uiSpiritId)) + { + pSpirit->SetStandState(UNIT_STAND_STATE_STAND); + pSpirit->AI()->EnterEvadeMode(); + } + } } - 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); @@ -129,11 +218,260 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI m_pInstance->SetData(TYPE_ZULJIN, DONE); } - void UpdateAI(const uint32 diff) + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 60.0f)) + { + DoScriptText(SAY_INTRO, m_creature); + m_bHasTaunted = true; + } + + 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) + { + if (Creature* pVortex = m_creature->GetMap()->GetCreature(*itr)) + pVortex->ForcedDespawn(); + } + } + + void JustSummoned(Creature* pSummoned) override + { + 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()); + + // 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); + break; + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_ID_CENTER) return; + // increment phase + if (m_uiPhase == PHASE_TROLL) + m_uiPhase = PHASE_BEAR; + else + ++m_uiPhase; + + // drain the spirit + if (Creature* pSpirit = m_pInstance->GetSingleCreatureFromStorage(aZuljinPhases[m_uiPhase].uiSpiritId)) + pSpirit->CastSpell(m_creature, SPELL_SPIRIT_DRAIN, false); + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_SPIRIT_DRAIN) + { + DoCastSpellIfCan(m_creature, aZuljinPhases[m_uiPhase].uiSpiritSpellId, CAST_INTERRUPT_PREVIOUS); + DoScriptText(aZuljinPhases[m_uiPhase].iYellId, m_creature); + DoScriptText(aZuljinPhases[m_uiPhase].iEmoteId, m_creature); + + // in eagle phase we don't move + if (m_uiPhase != PHASE_EAGLE) + { + SetCombatMovement(true); + if (m_creature->getVictim()) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + // In Eagle phase we just cast Energy storm and summon 4 Feather cyclones; Boss doesn't move in this phase + else + { + DoCastSpellIfCan(m_creature, SPELL_ENERGY_STORM, CAST_TRIGGERED); + + // summon 4 vortexes + DoCastSpellIfCan(m_creature, SPELL_SUMMON_CYCLONE, CAST_TRIGGERED); + } + + m_bIsInTransition = false; + } + } + + 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; + + if (m_creature->GetHealthPercent() < m_uiHealthCheck) + { + m_uiHealthCheck -= 20; + m_bIsInTransition = true; + + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, fZuljinMoveLoc[0], fZuljinMoveLoc[1], fZuljinMoveLoc[2]); + + // Despawn vortexes and remvoe the energy storm after eagle phase is complete + if (m_uiPhase == PHASE_EAGLE) + { + m_creature->RemoveAurasDueToSpell(SPELL_ENERGY_STORM); + DoDespawnVortexes(); + } + + // Reset threat + DoResetThreat(); + + // don't do this after troll phase + if (m_uiPhase != PHASE_TROLL) + { + if (m_creature->HasAura(aZuljinPhases[m_uiPhase].uiSpiritSpellId)) + m_creature->RemoveAurasDueToSpell(aZuljinPhases[m_uiPhase].uiSpiritSpellId); + + // drain spirit + if (Creature* pSpirit = m_pInstance->GetSingleCreatureFromStorage(aZuljinPhases[m_uiPhase].uiSpiritId)) + { + pSpirit->InterruptNonMeleeSpells(false); + pSpirit->CastSpell(m_creature, SPELL_SPIRIT_DRAINED, false); + pSpirit->SetStandState(UNIT_STAND_STATE_DEAD); + } + } + } + + switch (m_uiPhase) + { + case PHASE_TROLL: + + if (m_uiWhirlwindTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = urand(15000, 20000); + } + else + m_uiWhirlwindTimer -= uiDiff; + + if (m_uiGrievousThrowTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_GRIEVOUS_THROW) == CAST_OK) + m_uiGrievousThrowTimer = 10000; + } + } + else + m_uiGrievousThrowTimer -= uiDiff; + + break; + case PHASE_BEAR: + + if (m_uiParalysisTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CREEPING_PARALYSIS) == CAST_OK) + m_uiParalysisTimer = 27000; + } + else + m_uiParalysisTimer -= uiDiff; + + if (m_uiOverpowerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_OVERPOWER) == CAST_OK) + m_uiOverpowerTimer = urand(12000, 16000); + } + else + m_uiOverpowerTimer -= uiDiff; + + break; + case PHASE_EAGLE: + // Nothing here; Spells casted just once at the beginning of the phase; + break; + case PHASE_LYNX: + + // 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 (DoCastSpellIfCan(m_creature, SPELL_FLAME_WHIRL) == CAST_OK) + m_uiFlameWhirlTimer = 15000; + } + else + m_uiFlameWhirlTimer -= uiDiff; + + if (m_uiPillarOfFireTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_PILLAR) == CAST_OK) + m_uiPillarOfFireTimer = urand(17000, 22000); + } + else + m_uiPillarOfFireTimer -= 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; + } + } + else + m_uiFlameBreathTimer -= uiDiff; + + break; + } + DoMeleeAttackIfReady(); } }; @@ -143,11 +481,56 @@ CreatureAI* GetAI_boss_zuljin(Creature* pCreature) return new boss_zuljinAI(pCreature); } +/*###### +## npc_feather_vortex +######*/ + +struct MANGOS_DLL_DECL npc_feather_vortexAI : public ScriptedAI +{ + npc_feather_vortexAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() { } + + 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 *newscript; - newscript = new Script; - newscript->Name = "boss_zuljin"; - newscript->GetAI = &GetAI_boss_zuljin; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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 f7bbf03c28..7ec0486e7a 100644 --- a/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp +++ b/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,338 +16,510 @@ /* ScriptData SDName: Instance_Zulaman -SD%Complete: 25 -SDComment: +SD%Complete: 50 +SDComment: Support for Quests and Mini-Events still TODO SDCategory: Zul'Aman EndScriptData */ #include "precompiled.h" #include "zulaman.h" -struct MANGOS_DLL_DECL instance_zulaman : public ScriptedInstance +instance_zulaman::instance_zulaman(Map* pMap) : ScriptedInstance(pMap), + m_uiEventTimer(MINUTE* IN_MILLISECONDS), + m_uiGongCount(0), + m_uiBearEventPhase(0), + m_bIsBearPhaseInProgress(false) { - instance_zulaman(Map* pMap) : ScriptedInstance(pMap) {Initialize();} - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint32 m_auiRandVendor[MAX_VENDOR]; - std::string strInstData; - - uint32 m_uiEventTimer; - uint32 m_uiEventMinuteStep; + Initialize(); +} - uint32 m_uiGongCount; +void instance_zulaman::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + memset(&m_auiRandVendor, 0, sizeof(m_auiRandVendor)); +} - uint64 m_uiAkilzonGUID; - uint64 m_uiNalorakkGUID; - uint64 m_uiJanalaiGUID; - uint64 m_uiHalazziGUID; - uint64 m_uiSpiritLynxGUID; - uint64 m_uiZuljinGUID; - uint64 m_uiMalacrassGUID; - uint64 m_uiHarrisonGUID; +bool instance_zulaman::IsEncounterInProgress() const +{ + // Skip Time-Event and Time-Event timer + for (uint8 i = 1; i < MAX_ENCOUNTER - 1; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } - uint64 m_uiStrangeGongGUID; - uint64 m_uiMassiveGateGUID; - uint64 m_uiMalacrassEntranceGUID; + return false; +} - std::list m_lEggsGUIDList; - uint32 m_uiEggsRemainingCount_Left; - uint32 m_uiEggsRemainingCount_Right; +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 Initialize() +void instance_zulaman::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_auiRandVendor, 0, sizeof(m_auiRandVendor)); - - m_uiEventTimer = MINUTE*IN_MILLISECONDS; - m_uiEventMinuteStep = MINUTE/3; - - m_uiGongCount = 0; - - m_uiAkilzonGUID = 0; - m_uiNalorakkGUID = 0; - m_uiJanalaiGUID = 0; - m_uiHalazziGUID = 0; - m_uiSpiritLynxGUID = 0; - m_uiZuljinGUID = 0; - m_uiMalacrassGUID = 0; - m_uiHarrisonGUID = 0; - - m_uiStrangeGongGUID = 0; - m_uiMassiveGateGUID = 0; - m_uiMalacrassEntranceGUID = 0; - - m_lEggsGUIDList.clear(); - m_uiEggsRemainingCount_Left = 20; - m_uiEggsRemainingCount_Right = 20; + case NPC_AKILZON: + case NPC_HALAZZI: + case NPC_NALORAKK: + case NPC_JANALAI: + case NPC_MALACRASS: + case NPC_ZULJIN: + case NPC_HARRISON: + 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; + + case NPC_TANZAR: m_aEventNpcInfo[INDEX_NALORAKK].npGuid = pCreature->GetObjectGuid(); break; + case NPC_KRAZ: m_aEventNpcInfo[INDEX_JANALAI].npGuid = pCreature->GetObjectGuid(); break; + case NPC_ASHLI: m_aEventNpcInfo[INDEX_HALAZZI].npGuid = pCreature->GetObjectGuid(); break; + case NPC_HARKOR: m_aEventNpcInfo[INDEX_AKILZON].npGuid = pCreature->GetObjectGuid(); break; + + 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 OnCreatureCreate(Creature* pCreature) +void instance_zulaman::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pCreature->GetEntry()) - { - case 23574: m_uiAkilzonGUID = pCreature->GetGUID(); break; - case 23576: m_uiNalorakkGUID = pCreature->GetGUID(); break; - case 23578: m_uiJanalaiGUID = pCreature->GetGUID(); break; - case 23577: m_uiHalazziGUID = pCreature->GetGUID(); break; - case 23863: m_uiZuljinGUID = pCreature->GetGUID(); break; - case 24239: m_uiMalacrassGUID = pCreature->GetGUID(); break; - case 24358: m_uiHarrisonGUID = pCreature->GetGUID(); break; - case NPC_SPIRIT_LYNX: m_uiSpiritLynxGUID = pCreature->GetGUID(); break; - case NPC_EGG: - if (m_auiEncounter[3] != DONE) - m_lEggsGUIDList.push_back(pCreature->GetGUID()); - break; - } + 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 OnObjectCreate(GameObject* pGo) +void instance_zulaman::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pGo->GetEntry()) - { - case 187359: - m_uiStrangeGongGUID = pGo->GetGUID(); - break; - case 186728: - m_uiMassiveGateGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == IN_PROGRESS || m_auiEncounter[0] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 186305: - m_uiMalacrassEntranceGUID = pGo->GetGUID(); - break; - } + 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 SetData(uint32 uiType, uint32 uiData) +void instance_zulaman::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - debug_log("SD2: Instance Zulaman: SetData received for type %u with data %u",uiType,uiData); + case GO_STRANGE_GONG: + break; + case GO_MASSIVE_GATE: + // 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: + break; + case GO_LYNX_TEMPLE_ENTRANCE: + break; + case GO_LYNX_TEMPLE_EXIT: + if (m_auiEncounter[TYPE_HALAZZI] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_HEXLORD_ENTRANCE: + if (GetKilledPreBosses() == 4) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_WOODEN_DOOR: + if (m_auiEncounter[TYPE_MALACRASS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FIRE_DOOR: + break; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - switch(uiType) - { - case TYPE_EVENT_RUN: - if (uiData == SPECIAL) - { - ++m_uiGongCount; - if (m_uiGongCount == 5) - m_auiEncounter[0] = uiData; - } - if (uiData == IN_PROGRESS) - { - DoUseDoorOrButton(m_uiMassiveGateGUID); - DoUpdateWorldState(WORLD_STATE_COUNTER,m_uiEventMinuteStep); - DoUpdateWorldState(WORLD_STATE_ID,1); - m_auiEncounter[0] = uiData; - } - break; - case TYPE_AKILZON: - if (uiData == DONE) +void instance_zulaman::SetData(uint32 uiType, uint32 uiData) +{ + debug_log("SD2: Instance Zulaman: SetData received for type %u with data %u", uiType, uiData); + + switch (uiType) + { + case TYPE_EVENT_RUN: + if (uiData == SPECIAL) + { + ++m_uiGongCount; + if (m_uiGongCount == 5) + m_auiEncounter[TYPE_EVENT_RUN] = uiData; + return; + } + if (uiData == IN_PROGRESS) + { + DoTimeRunSay(RUN_START); + DoUseDoorOrButton(GO_MASSIVE_GATE); + if (m_auiEncounter[TYPE_RUN_EVENT_TIME]) + SetData(TYPE_RUN_EVENT_TIME, m_auiEncounter[TYPE_RUN_EVENT_TIME]); + else + SetData(TYPE_RUN_EVENT_TIME, 20); // 20 Minutes as default time + DoUpdateWorldState(WORLD_STATE_ID, 1); + } + if (uiData == FAIL) + { + DoTimeRunSay(RUN_FAIL); + DoUpdateWorldState(WORLD_STATE_ID, 0); + // Kill remaining Event NPCs + for (uint8 i = 0; i < MAX_CHESTS; ++i) { - if (m_auiEncounter[0] == IN_PROGRESS) + // Not yet rescued, so too late + if (!m_aEventNpcInfo[i].uiSavePosition) { - m_uiEventMinuteStep += MINUTE/6; //add 10 minutes - DoUpdateWorldState(WORLD_STATE_COUNTER,m_uiEventMinuteStep); + if (Creature* pCreature = instance->GetCreature(m_aEventNpcInfo[i].npGuid)) + pCreature->ForcedDespawn(); } } - m_auiEncounter[1] = uiData; - break; - case TYPE_NALORAKK: - if (uiData == DONE) + } + if (uiData == DONE) + { + DoTimeRunSay(RUN_DONE); + DoUpdateWorldState(WORLD_STATE_ID, 0); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_AKILZON: + DoUseDoorOrButton(GO_WIND_DOOR); + if (uiData == DONE) + { + if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) { - if (m_auiEncounter[0] == IN_PROGRESS) - { - m_uiEventMinuteStep += MINUTE/4; //add 15 minutes - DoUpdateWorldState(WORLD_STATE_COUNTER,m_uiEventMinuteStep); - } + m_auiEncounter[TYPE_RUN_EVENT_TIME] += 10; // Add 10 minutes + SetData(TYPE_RUN_EVENT_TIME, m_auiEncounter[TYPE_RUN_EVENT_TIME]); + DoChestEvent(INDEX_AKILZON); } - m_auiEncounter[2] = uiData; - break; - case TYPE_JANALAI: - if (uiData == NOT_STARTED) + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_NALORAKK: + if (uiData == DONE) + { + if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) { - m_uiEggsRemainingCount_Left = 20; - m_uiEggsRemainingCount_Right = 20; - - if (!m_lEggsGUIDList.empty()) - { - for(std::list::iterator itr = m_lEggsGUIDList.begin(); itr != m_lEggsGUIDList.end(); ++itr) - { - if (Creature* pEgg = instance->GetCreature(*itr)) - { - if (!pEgg->isAlive()) - pEgg->Respawn(); - } - } - } + m_auiEncounter[TYPE_RUN_EVENT_TIME] += 15; // Add 15 minutes + SetData(TYPE_RUN_EVENT_TIME, m_auiEncounter[TYPE_RUN_EVENT_TIME]); + DoChestEvent(INDEX_NALORAKK); } - if (uiData == DONE) - m_lEggsGUIDList.clear(); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_JANALAI: + if (uiData == DONE) + { + if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) + DoChestEvent(INDEX_JANALAI); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_HALAZZI: + DoUseDoorOrButton(GO_LYNX_TEMPLE_ENTRANCE); + if (uiData == DONE) + { + DoUseDoorOrButton(GO_LYNX_TEMPLE_EXIT); + if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) + DoChestEvent(INDEX_HALAZZI); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_MALACRASS: + DoUseDoorOrButton(GO_HEXLORD_ENTRANCE); + if (uiData == DONE) + DoUseDoorOrButton(GO_WOODEN_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_ZULJIN: + DoUseDoorOrButton(GO_FIRE_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_RUN_EVENT_TIME: + m_auiEncounter[uiType] = uiData; + DoUpdateWorldState(WORLD_STATE_COUNTER, m_auiEncounter[uiType]); + break; + + case TYPE_RAND_VENDOR_1: + m_auiRandVendor[0] = uiData; + break; + case TYPE_RAND_VENDOR_2: + m_auiRandVendor[1] = uiData; + break; + + default: + script_error_log("Instance Zulaman: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; + } - m_auiEncounter[3] = uiData; - break; - case TYPE_HALAZZI: - m_auiEncounter[4] = uiData; - break; - case TYPE_ZULJIN: - m_auiEncounter[5] = uiData; - break; - case TYPE_MALACRASS: - m_auiEncounter[6] = uiData; - break; + if (uiData == DONE && GetKilledPreBosses() == 4 && (uiType == TYPE_AKILZON || uiType == TYPE_NALORAKK || uiType == TYPE_JANALAI || uiType == TYPE_HALAZZI)) + { + DoUseDoorOrButton(GO_HEXLORD_ENTRANCE); + if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) + SetData(TYPE_EVENT_RUN, DONE); + } - case DATA_J_EGGS_RIGHT: - --m_uiEggsRemainingCount_Right; - break; - case DATA_J_EGGS_LEFT: - --m_uiEggsRemainingCount_Left; - break; + if (uiData == DONE || uiType == TYPE_RUN_EVENT_TIME || uiType == TYPE_EVENT_RUN) + { + OUT_SAVE_INST_DATA; - case TYPE_RAND_VENDOR_1: - m_auiRandVendor[0] = uiData; - break; - case TYPE_RAND_VENDOR_2: - m_auiRandVendor[1] = uiData; - break; - default: - error_log("SD2: Instance Zulaman: ERROR SetData = %u for type %u does not exist/not implemented.",uiType,uiData); - break; - } + 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]; - if (m_auiEncounter[1] == DONE && m_auiEncounter[2] == DONE && m_auiEncounter[3] == DONE && - m_auiEncounter[4] == DONE && m_auiEncounter[5] != IN_PROGRESS) - DoUseDoorOrButton(m_uiMalacrassEntranceGUID); + m_strInstData = saveStream.str(); - if (uiData == DONE || (uiType == TYPE_EVENT_RUN && uiData == IN_PROGRESS)) - { - OUT_SAVE_INST_DATA; + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} - 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]; +void instance_zulaman::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - strInstData = saveStream.str(); + OUT_LOAD_INST_DATA(chrIn); - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } + 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]; - const char* Save() + // Skip m_auiEncounter[7], to start the time event properly if needed + for (uint8 i = 0; i < MAX_ENCOUNTER - 1; ++i) { - return strInstData.c_str(); + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } - void Load(const char* chrIn) - { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + // Restart TYPE_EVENT_RUN if was already started + if (m_auiEncounter[TYPE_RUN_EVENT_TIME] != 0 && m_auiEncounter[TYPE_EVENT_RUN] != DONE && m_auiEncounter[TYPE_EVENT_RUN] != FAIL) + SetData(TYPE_EVENT_RUN, IN_PROGRESS); - OUT_LOAD_INST_DATA(chrIn); + OUT_LOAD_INST_DATA_COMPLETE; +} - 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]; +uint32 instance_zulaman::GetData(uint32 uiType) const +{ + switch (uiType) + { + case TYPE_EVENT_RUN: + case TYPE_AKILZON: + case TYPE_NALORAKK: + case TYPE_JANALAI: + case TYPE_HALAZZI: + case TYPE_ZULJIN: + case TYPE_MALACRASS: + case TYPE_RUN_EVENT_TIME: + return m_auiEncounter[uiType]; + case TYPE_RAND_VENDOR_1: return m_auiRandVendor[0]; + case TYPE_RAND_VENDOR_2: return m_auiRandVendor[1]; + default: + return 0; + } +} - //not changing m_uiEncounter[0], TYPE_EVENT_RUN must not reset to NOT_STARTED - for(uint8 i = 1; i < MAX_ENCOUNTER; ++i) +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()) { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->AI()->AttackStart(pTarget); - OUT_LOAD_INST_DATA_COMPLETE; + // 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); + } + } } - uint32 GetData(uint32 uiType) + m_bIsBearPhaseInProgress = true; +} + +bool instance_zulaman::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource conditionSourceType) const +{ + switch (uiInstanceConditionId) { - switch(uiType) + 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 { - case TYPE_EVENT_RUN: - return m_auiEncounter[0]; - case TYPE_AKILZON: - return m_auiEncounter[1]; - case TYPE_NALORAKK: - return m_auiEncounter[2]; - case TYPE_JANALAI: - return m_auiEncounter[3]; - case TYPE_HALAZZI: - return m_auiEncounter[4]; - case TYPE_ZULJIN: - return m_auiEncounter[5]; - case TYPE_MALACRASS: - return m_auiEncounter[6]; - - case DATA_J_EGGS_LEFT: - return m_uiEggsRemainingCount_Left; - case DATA_J_EGGS_RIGHT: - return m_uiEggsRemainingCount_Right; - - case TYPE_RAND_VENDOR_1: - return m_auiRandVendor[0]; - case TYPE_RAND_VENDOR_2: - return m_auiRandVendor[1]; + 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; } - return 0; } - uint64 GetData64(uint32 uiData) + 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); +} + +void instance_zulaman::DoTimeRunSay(RunEventSteps uiData) +{ + switch (uiData) { - switch(uiData) - { - case DATA_AKILZON: - return m_uiAkilzonGUID; - case DATA_NALORAKK: - return m_uiNalorakkGUID; - case DATA_JANALAI: - return m_uiJanalaiGUID; - case DATA_HALAZZI: - return m_uiHalazziGUID; - case DATA_SPIRIT_LYNX: - return m_uiSpiritLynxGUID; - case DATA_ZULJIN: - return m_uiZuljinGUID; - case DATA_MALACRASS: - return m_uiMalacrassGUID; - case DATA_HARRISON: - return m_uiHarrisonGUID; - case DATA_GO_GONG: - return m_uiStrangeGongGUID; - case DATA_GO_ENTRANCE: - return m_uiMassiveGateGUID; - case DATA_GO_MALACRASS_GATE: - return m_uiMalacrassEntranceGUID; - } - return 0; + case RUN_START: DoOrSimulateScriptTextForThisInstance(SAY_INST_BEGIN, NPC_MALACRASS); break; + case RUN_FAIL: DoOrSimulateScriptTextForThisInstance(urand(0, 1) ? SAY_INST_SACRIF1 : SAY_INST_SACRIF2, NPC_MALACRASS); break; + case RUN_DONE: DoOrSimulateScriptTextForThisInstance(SAY_INST_COMPLETE, NPC_MALACRASS); break; + case RUN_PROGRESS: + // This function is on progress called before the data is set to the array + switch (GetKilledPreBosses() + 1) + { + case 1: DoOrSimulateScriptTextForThisInstance(SAY_INST_PROGRESS_1, NPC_MALACRASS); break; + case 2: DoOrSimulateScriptTextForThisInstance(SAY_INST_PROGRESS_2, NPC_MALACRASS); break; + case 3: DoOrSimulateScriptTextForThisInstance(SAY_INST_PROGRESS_3, NPC_MALACRASS); break; + } + break; + case RUN_FAIL_SOON: + switch (GetKilledPreBosses()) + { + case 0: DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_1, NPC_MALACRASS); break; + case 1: DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_2, NPC_MALACRASS); break; + case 2: DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_3, NPC_MALACRASS); break; + case 3: DoOrSimulateScriptTextForThisInstance(SAY_INST_WARN_4, NPC_MALACRASS); break; + } + break; } +} + +void instance_zulaman::DoChestEvent(BossToChestIndex uiIndex) +{ + // Store Order of this kill + m_aEventNpcInfo[uiIndex].uiSavePosition = GetKilledPreBosses() + 1; + + // Do Yell + DoTimeRunSay(RUN_PROGRESS); + + // related NPC: m_aEventNpcInfo[uiIndex].npGuid + // related Chest: m_aEventNpcInfo[uiIndex] // Not yet stored, because likely unneeded +} - void Update(uint32 uiDiff) +void instance_zulaman::Update(uint32 uiDiff) +{ + if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) { - if (GetData(TYPE_EVENT_RUN) == IN_PROGRESS) + if (m_uiEventTimer <= uiDiff) { - if (m_uiEventTimer <= uiDiff) + if (m_auiEncounter[TYPE_RUN_EVENT_TIME] == 5) // TODO, verify 5min for warning texts + DoTimeRunSay(RUN_FAIL_SOON); + + if (m_auiEncounter[TYPE_RUN_EVENT_TIME] == 0) { - if (m_uiEventMinuteStep == 0) - { - debug_log("SD2: Instance Zulaman: event time reach end, event failed."); - m_auiEncounter[0] = FAIL; - return; - } + debug_log("SD2: Instance Zulaman: event time reach end, event failed."); + SetData(TYPE_EVENT_RUN, FAIL); + return; + } - --m_uiEventMinuteStep; - DoUpdateWorldState(WORLD_STATE_COUNTER, m_uiEventMinuteStep); - debug_log("SD2: Instance Zulaman: minute decrease to %u.",m_uiEventMinuteStep); + --m_auiEncounter[TYPE_RUN_EVENT_TIME]; + 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; - } - else - m_uiEventTimer -= uiDiff; + m_uiEventTimer = MINUTE * IN_MILLISECONDS; } + else + m_uiEventTimer -= uiDiff; } -}; +} InstanceData* GetInstanceData_instance_zulaman(Map* pMap) { @@ -357,6 +529,7 @@ InstanceData* GetInstanceData_instance_zulaman(Map* pMap) void AddSC_instance_zulaman() { Script* pNewScript; + pNewScript = new Script; pNewScript->Name = "instance_zulaman"; pNewScript->GetInstanceData = &GetInstanceData_instance_zulaman; diff --git a/scripts/eastern_kingdoms/zulaman/zulaman.cpp b/scripts/eastern_kingdoms/zulaman/zulaman.cpp index 1dbd94c614..b44d60fdaa 100644 --- a/scripts/eastern_kingdoms/zulaman/zulaman.cpp +++ b/scripts/eastern_kingdoms/zulaman/zulaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -37,7 +37,7 @@ enum { SPELL_REMOVE_AMANI_CURSE = 43732, SPELL_PUSH_MOJO = 43923, - ENTRY_FOREST_FROG = 24396 + NPC_FOREST_FROG = 24396 }; struct MANGOS_DLL_DECL npc_forest_frogAI : public ScriptedAI @@ -57,45 +57,45 @@ struct MANGOS_DLL_DECL npc_forest_frogAI : public ScriptedAI if (m_pInstance) { uint32 cEntry = 0; - switch(urand(0, 10)) + switch (urand(0, 10)) { - case 0: cEntry = 24024; break; //Kraz - 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() == ENTRY_FOREST_FROG) + 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,11 +118,11 @@ 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 { npc_harrison_jones_zaAI(Creature* pCreature) : npc_escortAI(pCreature) @@ -133,29 +133,28 @@ 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); - if (GameObject* pEntranceDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_GO_GONG))) - pEntranceDoor->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + 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: DoScriptText(SAY_OPEN_ENTRANCE, m_creature); break; - case 4: - m_pInstance->SetData(TYPE_EVENT_RUN,IN_PROGRESS); - //TODO: Spawn group of Amani'shi Savage and make them run to entrance + case 4: + m_pInstance->SetData(TYPE_EVENT_RUN, IN_PROGRESS); + // TODO: Spawn group of Amani'shi Savage and make them run to entrance break; } } @@ -172,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); } @@ -183,22 +182,22 @@ bool GossipHello_npc_harrison_jones_za(Player* pPlayer, Creature* pCreature) ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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->GetGUID()); + 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(); - + pPlayer->CLOSE_GOSSIP_MENU(); } return true; @@ -213,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 GOHello_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(); @@ -223,15 +222,15 @@ bool GOHello_go_strange_gong(Player* pPlayer, GameObject* pGo) if (pInstance->GetData(TYPE_EVENT_RUN) == SPECIAL) { - if (Creature* pCreature = pGo->GetMap()->GetCreature(pInstance->GetData64(DATA_HARRISON))) + if (Creature* pCreature = pInstance->GetSingleCreatureFromStorage(NPC_HARRISON)) { if (npc_harrison_jones_zaAI* pHarrisonAI = dynamic_cast(pCreature->AI())) 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_UNK1); + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); return false; } @@ -241,22 +240,22 @@ bool GOHello_go_strange_gong(Player* pPlayer, GameObject* pGo) void AddSC_zulaman() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_forest_frog"; - newscript->GetAI = &GetAI_npc_forest_frog; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_harrison_jones_za"; - newscript->GetAI = &GetAI_npc_harrison_jones_za; - newscript->pGossipHello = &GossipHello_npc_harrison_jones_za; - newscript->pGossipSelect = &GossipSelect_npc_harrison_jones_za; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_strange_gong"; - newscript->pGOHello = &GOHello_go_strange_gong; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_forest_frog"; + pNewScript->GetAI = &GetAI_npc_forest_frog; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_harrison_jones_za"; + pNewScript->GetAI = &GetAI_npc_harrison_jones_za; + pNewScript->pGossipHello = &GossipHello_npc_harrison_jones_za; + pNewScript->pGossipSelect = &GossipSelect_npc_harrison_jones_za; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_strange_gong"; + pNewScript->pGOUse = &GOUse_go_strange_gong; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/zulaman.h b/scripts/eastern_kingdoms/zulaman/zulaman.h index cc85875f1c..6c2be2aba0 100644 --- a/scripts/eastern_kingdoms/zulaman/zulaman.h +++ b/scripts/eastern_kingdoms/zulaman/zulaman.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,10 +7,12 @@ enum InstanceZA { - MAX_ENCOUNTER = 7, + MAX_ENCOUNTER = 8, MAX_VENDOR = 2, + MAX_CHESTS = 4, + MAX_BEAR_WAVES = 4, - SAY_INST_RELEASE = -1568067, + SAY_INST_RELEASE = -1568067, // TODO Event NYI SAY_INST_BEGIN = -1568068, SAY_INST_PROGRESS_1 = -1568069, SAY_INST_PROGRESS_2 = -1568070, @@ -23,38 +25,172 @@ 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, - TYPE_EVENT_RUN = 1, - TYPE_AKILZON = 2, - TYPE_NALORAKK = 3, - TYPE_JANALAI = 4, - TYPE_HALAZZI = 5, - TYPE_MALACRASS = 6, - TYPE_ZULJIN = 7, + TYPE_EVENT_RUN = 0, + TYPE_AKILZON = 1, + TYPE_NALORAKK = 2, + TYPE_JANALAI = 3, + TYPE_HALAZZI = 4, + TYPE_MALACRASS = 5, + TYPE_ZULJIN = 6, + TYPE_RUN_EVENT_TIME = 7, // Must be MAX_ENCOUNTER -1 TYPE_RAND_VENDOR_1 = 8, TYPE_RAND_VENDOR_2 = 9, - DATA_AKILZON = 10, - DATA_NALORAKK = 11, - DATA_JANALAI = 12, - DATA_HALAZZI = 13, - DATA_MALACRASS = 14, - DATA_ZULJIN = 15, - DATA_HARRISON = 16, - DATA_SPIRIT_LYNX = 17, + NPC_AKILZON = 23574, + NPC_NALORAKK = 23576, + NPC_JANALAI = 23578, + NPC_HALAZZI = 23577, + NPC_MALACRASS = 24239, + 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 + NPC_TANZAR = 23790, // at bear + NPC_KRAZ = 24024, // at phoenix + NPC_ASHLI = 24001, // at lynx + NPC_HARKOR = 23999, // at eagle + // unused (TODO or TODO with DB-tools) + NPC_TANZAR_CORPSE = 24442, + NPC_KRAZ_CORPSE = 24444, + 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, + NPC_DRAGONHAWK_SPIRIT = 23879, + + GO_STRANGE_GONG = 187359, + GO_MASSIVE_GATE = 186728, + GO_WIND_DOOR = 186858, + GO_LYNX_TEMPLE_ENTRANCE = 186304, + GO_LYNX_TEMPLE_EXIT = 186303, + GO_HEXLORD_ENTRANCE = 186305, + GO_WOODEN_DOOR = 186306, + GO_FIRE_DOOR = 186859, + + GO_TANZARS_TRUNK = 186648, + GO_KRAZS_PACKAGE = 186667, + GO_ASHLIS_BAG = 186672, + GO_HARKORS_SATCHEL = 187021, +}; + +enum BossToChestIndex +{ + INDEX_NALORAKK = 0, + INDEX_JANALAI = 1, + INDEX_HALAZZI = 2, + INDEX_AKILZON = 3 +}; + +enum RunEventSteps +{ + RUN_START = 1, + RUN_FAIL = 2, + RUN_DONE = 3, + RUN_PROGRESS = 4, + RUN_FAIL_SOON = 5 +}; + +struct TimeEventNpcInfo +{ + TimeEventNpcInfo() : uiSavePosition(0) {} + + uint8 uiSavePosition; // stores in what order this npc was saved (0 means unsaved) + ObjectGuid npGuid; +}; + +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 MANGOS_DLL_DECL instance_zulaman : public ScriptedInstance +{ + public: + instance_zulaman(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 OnCreatureEvade(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; + + bool IsBearPhaseInProgress() { return m_bIsBearPhaseInProgress; } + void SetBearEventProgress(bool bIsInProgress) { m_bIsBearPhaseInProgress = bIsInProgress; } + void SendNextBearWave(Unit* pTarget); + + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource conditionSourceType) const override; + + void Update(uint32 uiDiff) override; + + private: + uint8 GetKilledPreBosses(); + void DoTimeRunSay(RunEventSteps uiData); + void DoChestEvent(BossToChestIndex uiIndex); - DATA_J_EGGS_RIGHT = 19, - DATA_J_EGGS_LEFT = 20, + std::string m_strInstData; + uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint32 m_auiRandVendor[MAX_VENDOR]; + TimeEventNpcInfo m_aEventNpcInfo[MAX_CHESTS]; - DATA_GO_GONG = 21, - DATA_GO_MALACRASS_GATE = 22, - DATA_GO_ENTRANCE = 23, + uint32 m_uiEventTimer; + uint32 m_uiGongCount; - NPC_EGG = 23817, - NPC_SPIRIT_LYNX = 24143 + 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 14cfcf20df..483bd7a201 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,43 +16,28 @@ /* ScriptData SDName: Boss_Arlokk -SD%Complete: 95 -SDComment: Wrong cleave and red aura is missing. +SD%Complete: 80 +SDComment: Vanish spell is replaced by workaround; Timers SDCategory: Zul'Gurub EndScriptData */ #include "precompiled.h" #include "zulgurub.h" -bool GOHello_go_gong_of_bethekk(Player* pPlayer, GameObject* pGo) -{ - if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) - { - if (pInstance->GetData(TYPE_ARLOKK) == DONE || pInstance->GetData(TYPE_ARLOKK) == IN_PROGRESS) - return true; - - pInstance->SetData(TYPE_ARLOKK, IN_PROGRESS); - } - - return false; -} - enum { SAY_AGGRO = -1309011, SAY_FEAST_PANTHER = -1309012, SAY_DEATH = -1309013, - SPELL_SHADOWWORDPAIN = 23952, + SPELL_SHADOW_WORD_PAIN = 23952, SPELL_GOUGE = 24698, - SPELL_MARK = 24210, - SPELL_CLEAVE = 26350, //Perhaps not right. Not a red aura... + SPELL_MARK_ARLOKK = 24210, + SPELL_RAVAGE = 24213, + SPELL_TRASH = 3391, + SPELL_WHIRLWIND = 24236, SPELL_PANTHER_TRANSFORM = 24190, - MODEL_ID_NORMAL = 15218, - MODEL_ID_PANTHER = 15215, - MODEL_ID_BLANK = 11686, - NPC_ZULIAN_PROWLER = 15101 }; @@ -60,211 +45,221 @@ struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI { boss_arlokkAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_zulgurub*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; - - uint32 m_uiShadowWordPain_Timer; - uint32 m_uiGouge_Timer; - uint32 m_uiMark_Timer; - uint32 m_uiCleave_Timer; - uint32 m_uiVanish_Timer; - uint32 m_uiVisible_Timer; - - uint32 m_uiSummon_Timer; - uint32 m_uiSummonCount; + instance_zulgurub* m_pInstance; - uint64 m_uiMarkedGUID; + uint32 m_uiShadowWordPainTimer; + uint32 m_uiGougeTimer; + uint32 m_uiMarkTimer; + uint32 m_uiRavageTimer; + uint32 m_uiTrashTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiVanishTimer; + uint32 m_uiVisibleTimer; + uint32 m_uiTransformTimer; + uint32 m_uiSummonTimer; bool m_bIsPhaseTwo; - bool m_bIsVanished; void Reset() { - m_uiShadowWordPain_Timer = 8000; - m_uiGouge_Timer = 14000; - m_uiMark_Timer = 35000; - m_uiCleave_Timer = 4000; - m_uiVanish_Timer = 60000; - m_uiVisible_Timer = 6000; - - m_uiSummon_Timer = 5000; - m_uiSummonCount = 0; + m_uiShadowWordPainTimer = 8000; + m_uiGougeTimer = 14000; + m_uiMarkTimer = 5000; + m_uiRavageTimer = 12000; + m_uiTrashTimer = 20000; + m_uiWhirlwindTimer = 15000; + m_uiTransformTimer = 30000; + m_uiVanishTimer = 5000; + m_uiVisibleTimer = 0; + m_uiSummonTimer = 5000; m_bIsPhaseTwo = false; - m_bIsVanished = false; - - m_uiMarkedGUID = 0; - m_creature->SetDisplayId(MODEL_ID_NORMAL); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Restore visibility + if (m_creature->GetVisibility() != VISIBILITY_ON) + 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, NOT_STARTED); + 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); - - m_creature->SetDisplayId(MODEL_ID_NORMAL); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Restore visibility in case of killed by dots + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); if (m_pInstance) m_pInstance->SetData(TYPE_ARLOKK, DONE); } - void DoSummonPhanters() + void JustSummoned(Creature* pSummoned) override { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiMarkedGUID)) - { - if (pPlayer->isAlive()) - DoScriptText(SAY_FEAST_PANTHER, m_creature, pPlayer); - } - - m_creature->SummonCreature(NPC_ZULIAN_PROWLER, -11532.7998f, -1649.6734f, 41.4800f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - m_creature->SummonCreature(NPC_ZULIAN_PROWLER, -11532.9970f, -1606.4840f, 41.2979f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + // 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 JustSummoned(Creature* pSummoned) + void UpdateAI(const uint32 uiDiff) override { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiMarkedGUID)) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Summon panters every 5 seconds + if (m_uiSummonTimer < uiDiff) { - if (pPlayer->isAlive()) - pSummoned->AI()->AttackStart(pPlayer); + 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_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_OOC_DESPAWN, 30000); + } + + m_uiSummonTimer = 5000; } + else + m_uiSummonTimer -= uiDiff; - ++m_uiSummonCount; - } + if (m_uiVisibleTimer) + { + if (m_uiVisibleTimer <= uiDiff) + { + // Restore visibility + m_creature->SetVisibility(VISIBILITY_ON); - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + AttackStart(pTarget); + + m_uiVisibleTimer = 0; + } + else + m_uiVisibleTimer -= uiDiff; + + // Do nothing while vanished return; + } + // Troll phase if (!m_bIsPhaseTwo) { - if (m_uiShadowWordPain_Timer < uiDiff) + if (m_uiShadowWordPainTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - m_uiShadowWordPain_Timer = 15000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_WORD_PAIN) == CAST_OK) + m_uiShadowWordPainTimer = 15000; + } } else - m_uiShadowWordPain_Timer -= uiDiff; + m_uiShadowWordPainTimer -= uiDiff; - if (m_uiMark_Timer < uiDiff) + if (m_uiMarkTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MARK_ARLOKK, SELECT_FLAG_PLAYER)) { - if (Player* pMark = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (DoCastSpellIfCan(pTarget, SPELL_MARK_ARLOKK) == CAST_OK) { - DoCastSpellIfCan(pMark, SPELL_MARK); - m_uiMarkedGUID = pMark->GetGUID(); + DoScriptText(SAY_FEAST_PANTHER, m_creature, pTarget); + m_uiMarkTimer = 30000; } - else - { - if (m_uiMarkedGUID) - m_uiMarkedGUID = 0; + } + } + else + m_uiMarkTimer -= uiDiff; - error_log("SD2: boss_arlokk could not accuire a new target to mark."); - } + if (m_uiGougeTimer < uiDiff) + { + 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_uiGougeTimer = urand(17000, 27000); } + } + else + m_uiGougeTimer -= uiDiff; - m_uiMark_Timer = 15000; + // Transform to Panther + if (m_uiTransformTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PANTHER_TRANSFORM) == CAST_OK) + { + m_uiTransformTimer = 80000; + m_bIsPhaseTwo = true; + } } else - m_uiMark_Timer -= uiDiff; + m_uiTransformTimer -= uiDiff; } + // Panther phase else { - //Cleave_Timer - if (m_uiCleave_Timer < uiDiff) + if (m_uiRavageTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleave_Timer = 16000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_RAVAGE) == CAST_OK) + m_uiRavageTimer = urand(10000, 15000); } else - m_uiCleave_Timer -= uiDiff; + m_uiRavageTimer -= uiDiff; - //Gouge_Timer - if (m_uiGouge_Timer < uiDiff) + if (m_uiTrashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE); - - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); - - m_uiGouge_Timer = urand(17000, 27000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiTrashTimer = urand(13000, 15000); } else - m_uiGouge_Timer -= uiDiff; - } + m_uiTrashTimer -= uiDiff; - if (m_uiSummonCount <= 30) - { - if (m_uiSummon_Timer < uiDiff) + if (m_uiWhirlwindTimer < uiDiff) { - DoSummonPhanters(); - m_uiSummon_Timer = 5000; + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = 15000; } else - m_uiSummon_Timer -= uiDiff; - } - - if (m_uiVanish_Timer < uiDiff) - { - //Invisble Model - m_creature->SetDisplayId(MODEL_ID_BLANK); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - m_creature->AttackStop(); - DoResetThreat(); - - m_bIsVanished = true; - - m_uiVanish_Timer = 45000; - m_uiVisible_Timer = 6000; - } - else - m_uiVanish_Timer -= uiDiff; + m_uiWhirlwindTimer -= uiDiff; - if (m_bIsVanished) - { - if (m_uiVisible_Timer < uiDiff) + if (m_uiVanishTimer < uiDiff) { - //The Panther Model - m_creature->SetDisplayId(MODEL_ID_PANTHER); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Note: this is a workaround because we do not know the real vanish spell + m_creature->SetVisibility(VISIBILITY_OFF); + DoResetThreat(); - 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); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - AttackStart(pTarget); + m_uiVanishTimer = 85000; + m_uiVisibleTimer = 45000; + } + else + m_uiVanishTimer -= uiDiff; - m_bIsPhaseTwo = true; - m_bIsVanished = false; + // Transform back + if (m_uiTransformTimer < uiDiff) + { + m_creature->RemoveAurasDueToSpell(SPELL_PANTHER_TRANSFORM); + m_uiTransformTimer = 30000; + m_bIsPhaseTwo = false; } else - m_uiVisible_Timer -= uiDiff; + m_uiTransformTimer -= uiDiff; } - else - DoMeleeAttackIfReady(); + + DoMeleeAttackIfReady(); } }; @@ -273,17 +268,30 @@ CreatureAI* GetAI_boss_arlokk(Creature* pCreature) return new boss_arlokkAI(pCreature); } +bool GOUse_go_gong_of_bethekk(Player* /*pPlayer*/, GameObject* pGo) +{ + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) + { + if (pInstance->GetData(TYPE_ARLOKK) == DONE || pInstance->GetData(TYPE_ARLOKK) == IN_PROGRESS) + return true; + + pInstance->SetData(TYPE_ARLOKK, IN_PROGRESS); + } + + return false; +} + void AddSC_boss_arlokk() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "go_gong_of_bethekk"; - newscript->pGOHello = &GOHello_go_gong_of_bethekk; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_arlokk"; + pNewScript->GetAI = &GetAI_boss_arlokk; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_arlokk"; - newscript->GetAI = &GetAI_boss_arlokk; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_gong_of_bethekk"; + pNewScript->pGOUse = &GOUse_go_gong_of_bethekk; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp b/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp deleted file mode 100644 index 4fe633a8ad..0000000000 --- a/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_gahzranka"; - newscript->GetAI = &GetAI_boss_gahzranka; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp b/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp deleted file mode 100644 index aacb47084c..0000000000 --- a/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_grilek"; - newscript->GetAI = &GetAI_boss_grilek; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp b/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp index 9e67e35158..aa1320e773 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,31 +16,32 @@ /* ScriptData SDName: Boss_Hakkar -SD%Complete: 95 -SDComment: Blood siphon spell buggy cause of Core Issue. +SD%Complete: 100 +SDComment: SDCategory: Zul'Gurub EndScriptData */ #include "precompiled.h" #include "zulgurub.h" -#define SAY_AGGRO -1309020 -#define SAY_FLEEING -1309021 -#define SAY_MINION_DESTROY -1309022 //where does it belong? -#define SAY_PROTECT_ALTAR -1309023 //where does it belong? - -#define SPELL_BLOODSIPHON 24322 -#define SPELL_CORRUPTEDBLOOD 24328 -#define SPELL_CAUSEINSANITY 24327 //Not working disabled. -#define SPELL_WILLOFHAKKAR 24178 -#define SPELL_ENRAGE 24318 - -// The Aspects of all High Priests -#define SPELL_ASPECT_OF_JEKLIK 24687 -#define SPELL_ASPECT_OF_VENOXIS 24688 -#define SPELL_ASPECT_OF_MARLI 24686 -#define SPELL_ASPECT_OF_THEKAL 24689 -#define SPELL_ASPECT_OF_ARLOKK 24690 +enum +{ + SAY_AGGRO = -1309020, + SAY_FLEEING = -1309021, + + SPELL_BLOOD_SIPHON = 24324, // triggers 24322 or 24323 on caster + SPELL_CORRUPTED_BLOOD = 24328, + SPELL_CAUSE_INSANITY = 24327, + SPELL_WILL_OF_HAKKAR = 24178, + SPELL_ENRAGE = 24318, + + // The Aspects of all High Priests + SPELL_ASPECT_OF_JEKLIK = 24687, + SPELL_ASPECT_OF_VENOXIS = 24688, + SPELL_ASPECT_OF_MARLI = 24686, + SPELL_ASPECT_OF_THEKAL = 24689, + SPELL_ASPECT_OF_ARLOKK = 24690 +}; struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI { @@ -52,185 +53,176 @@ struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 BloodSiphon_Timer; - uint32 CorruptedBlood_Timer; - uint32 CauseInsanity_Timer; - uint32 WillOfHakkar_Timer; - uint32 Enrage_Timer; + uint32 m_uiBloodSiphonTimer; + uint32 m_uiCorruptedBloodTimer; + uint32 m_uiCauseInsanityTimer; + uint32 m_uiWillOfHakkarTimer; + uint32 m_uiEnrageTimer; - uint32 CheckJeklik_Timer; - uint32 CheckVenoxis_Timer; - uint32 CheckMarli_Timer; - uint32 CheckThekal_Timer; - uint32 CheckArlokk_Timer; - - uint32 AspectOfJeklik_Timer; - uint32 AspectOfVenoxis_Timer; - uint32 AspectOfMarli_Timer; - uint32 AspectOfThekal_Timer; - uint32 AspectOfArlokk_Timer; - - bool Enraged; + uint32 m_uiAspectOfJeklikTimer; + uint32 m_uiAspectOfVenoxisTimer; + uint32 m_uiAspectOfMarliTimer; + uint32 m_uiAspectOfThekalTimer; + uint32 m_uiAspectOfArlokkTimer; void Reset() { - BloodSiphon_Timer = 90000; - CorruptedBlood_Timer = 25000; - CauseInsanity_Timer = 17000; - WillOfHakkar_Timer = 17000; - Enrage_Timer = 600000; - - CheckJeklik_Timer = 1000; - CheckVenoxis_Timer = 2000; - CheckMarli_Timer = 3000; - CheckThekal_Timer = 4000; - CheckArlokk_Timer = 5000; - - AspectOfJeklik_Timer = 4000; - AspectOfVenoxis_Timer = 7000; - AspectOfMarli_Timer = 12000; - AspectOfThekal_Timer = 8000; - AspectOfArlokk_Timer = 18000; - - Enraged = false; + m_uiBloodSiphonTimer = 90000; + m_uiCorruptedBloodTimer = 25000; + m_uiCauseInsanityTimer = 17000; + m_uiWillOfHakkarTimer = 17000; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_uiAspectOfJeklikTimer = 4000; + m_uiAspectOfVenoxisTimer = 7000; + m_uiAspectOfMarliTimer = 12000; + m_uiAspectOfThekalTimer = 8000; + m_uiAspectOfArlokkTimer = 18000; } - void Aggro(Unit *who) + void Aggro(Unit* /*who*/) override { DoScriptText(SAY_AGGRO, m_creature); + + // check if the priest encounters are done + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_JEKLIK) == DONE) + m_uiAspectOfJeklikTimer = 0; + if (m_pInstance->GetData(TYPE_VENOXIS) == DONE) + m_uiAspectOfVenoxisTimer = 0; + if (m_pInstance->GetData(TYPE_MARLI) == DONE) + m_uiAspectOfMarliTimer = 0; + if (m_pInstance->GetData(TYPE_THEKAL) == DONE) + m_uiAspectOfThekalTimer = 0; + if (m_pInstance->GetData(TYPE_ARLOKK) == DONE) + m_uiAspectOfArlokkTimer = 0; + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //BloodSiphon_Timer - if (BloodSiphon_Timer < diff) + if (m_uiBloodSiphonTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BLOODSIPHON); - BloodSiphon_Timer = 90000; - }else BloodSiphon_Timer -= diff; - - //CorruptedBlood_Timer - if (CorruptedBlood_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_SIPHON) == CAST_OK) + m_uiBloodSiphonTimer = 90000; + } + else + m_uiBloodSiphonTimer -= uiDiff; + + // Corrupted Blood Timer + if (m_uiCorruptedBloodTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CORRUPTEDBLOOD); - CorruptedBlood_Timer = urand(30000, 45000); - }else CorruptedBlood_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CORRUPTED_BLOOD) == CAST_OK) + m_uiCorruptedBloodTimer = urand(30000, 45000); + } + } + else + m_uiCorruptedBloodTimer -= uiDiff; - //CauseInsanity_Timer - /*if (CauseInsanity_Timer < diff) + // Cause Insanity Timer + if (m_uiCauseInsanityTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_CAUSEINSANITY); - - CauseInsanity_Timer = urand(35000, 43000); - }else CauseInsanity_Timer -= diff;*/ - - //WillOfHakkar_Timer - if (WillOfHakkar_Timer < diff) + if (m_creature->getThreatManager().getThreatList().size() > 1) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CAUSE_INSANITY) == CAST_OK) + m_uiCauseInsanityTimer = urand(10000, 15000); + } + else // Solo case, check again later + m_uiCauseInsanityTimer = urand(35000, 43000); + } + else + m_uiCauseInsanityTimer -= uiDiff; + + // Will Of Hakkar Timer + if (m_uiWillOfHakkarTimer < uiDiff) { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_WILL_OF_HAKKAR) == CAST_OK) + m_uiWillOfHakkarTimer = urand(25000, 35000); + } + else // solo attempt, try again later + m_uiWillOfHakkarTimer = 25000; + } + else + m_uiWillOfHakkarTimer -= uiDiff; - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_WILLOFHAKKAR); - - WillOfHakkar_Timer = urand(25000, 35000); - }else WillOfHakkar_Timer -= diff; - - if (!Enraged && Enrage_Timer < diff) + if (m_uiEnrageTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - Enraged = true; - }else Enrage_Timer -= diff; - - //Checking if Jeklik is dead. If not we cast her Aspect - if (CheckJeklik_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + } + else + m_uiEnrageTimer -= uiDiff; + + // Checking if Jeklik is dead. If not we cast her Aspect + if (m_uiAspectOfJeklikTimer) { - if (m_pInstance) + if (m_uiAspectOfJeklikTimer <= uiDiff) { - if (m_pInstance->GetData(TYPE_JEKLIK) != DONE) - { - if (AspectOfJeklik_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ASPECT_OF_JEKLIK); - AspectOfJeklik_Timer = urand(10000, 14000); - }else AspectOfJeklik_Timer -= diff; - } + if (DoCastSpellIfCan(m_creature, SPELL_ASPECT_OF_JEKLIK) == CAST_OK) + m_uiAspectOfJeklikTimer = urand(10000, 14000); } - CheckJeklik_Timer = 1000; - }else CheckJeklik_Timer -= diff; + else + m_uiAspectOfJeklikTimer -= uiDiff; + } - //Checking if Venoxis is dead. If not we cast his Aspect - if (CheckVenoxis_Timer < diff) + // Checking if Venoxis is dead. If not we cast his Aspect + if (m_uiAspectOfVenoxisTimer) { - if (m_pInstance) + if (m_uiAspectOfVenoxisTimer <= uiDiff) { - if (m_pInstance->GetData(TYPE_VENOXIS) != DONE) - { - if (AspectOfVenoxis_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ASPECT_OF_VENOXIS); - AspectOfVenoxis_Timer = 8000; - }else AspectOfVenoxis_Timer -= diff; - } + if (DoCastSpellIfCan(m_creature, SPELL_ASPECT_OF_VENOXIS) == CAST_OK) + m_uiAspectOfVenoxisTimer = 8000; } - CheckVenoxis_Timer = 1000; - }else CheckVenoxis_Timer -= diff; + else + m_uiAspectOfVenoxisTimer -= uiDiff; + } - //Checking if Marli is dead. If not we cast her Aspect - if (CheckMarli_Timer < diff) + // Checking if Marli is dead. If not we cast her Aspect + if (m_uiAspectOfMarliTimer) { - if (m_pInstance) + if (m_uiAspectOfMarliTimer <= uiDiff) { - if (m_pInstance->GetData(TYPE_MARLI) != DONE) - { - if (AspectOfMarli_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ASPECT_OF_MARLI); - AspectOfMarli_Timer = 10000; - }else AspectOfMarli_Timer -= diff; - - } + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ASPECT_OF_MARLI) == CAST_OK) + m_uiAspectOfMarliTimer = 10000; } - CheckMarli_Timer = 1000; - }else CheckMarli_Timer -= diff; + else + m_uiAspectOfMarliTimer -= uiDiff; + } - //Checking if Thekal is dead. If not we cast his Aspect - if (CheckThekal_Timer < diff) + // Checking if Thekal is dead. If not we cast his Aspect + if (m_uiAspectOfThekalTimer) { - if (m_pInstance) + if (m_uiAspectOfThekalTimer <= uiDiff) { - if (m_pInstance->GetData(TYPE_THEKAL) != DONE) - { - if (AspectOfThekal_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_ASPECT_OF_THEKAL); - AspectOfThekal_Timer = 15000; - }else AspectOfThekal_Timer -= diff; - } + if (DoCastSpellIfCan(m_creature, SPELL_ASPECT_OF_THEKAL) == CAST_OK) + m_uiAspectOfThekalTimer = 15000; } - CheckThekal_Timer = 1000; - }else CheckThekal_Timer -= diff; + else + m_uiAspectOfThekalTimer -= uiDiff; + } - //Checking if Arlokk is dead. If yes we cast her Aspect - if (CheckArlokk_Timer < diff) + // Checking if Arlokk is dead. If yes we cast her Aspect + if (m_uiAspectOfArlokkTimer) { - if (m_pInstance) + if (m_uiAspectOfArlokkTimer <= uiDiff) { - if (m_pInstance->GetData(TYPE_ARLOKK) != DONE) + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ASPECT_OF_ARLOKK) == CAST_OK) { - if (AspectOfArlokk_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_ASPECT_OF_ARLOKK); - DoResetThreat(); - - AspectOfArlokk_Timer = urand(10000, 15000); - }else AspectOfArlokk_Timer -= diff; + DoResetThreat(); + m_uiAspectOfArlokkTimer = urand(10000, 15000); } } - CheckArlokk_Timer = 1000; - }else CheckArlokk_Timer -= diff; + else + m_uiAspectOfArlokkTimer -= uiDiff; + } DoMeleeAttackIfReady(); } @@ -243,9 +235,10 @@ CreatureAI* GetAI_boss_hakkar(Creature* pCreature) void AddSC_boss_hakkar() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_hakkar"; - newscript->GetAI = &GetAI_boss_hakkar; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_hakkar"; + pNewScript->GetAI = &GetAI_boss_hakkar; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp b/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp index 1e7642624e..e30801fcf3 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,65 +22,94 @@ SDCategory: Zul'Gurub EndScriptData */ #include "precompiled.h" -#include "zulgurub.h" -#define SPELL_MANABURN 26046 -#define SPELL_SLEEP 24664 +enum +{ + SPELL_CHAIN_BURN = 24684, + SPELL_SLEEP = 24664, + SPELL_EARTH_SHOCK = 24685, + SPELL_SUMMON_ILLUSION_1 = 24681, + SPELL_SUMMON_ILLUSION_2 = 24728, + SPELL_SUMMON_ILLUSION_3 = 24729, +}; struct MANGOS_DLL_DECL boss_hazzarahAI : public ScriptedAI { - boss_hazzarahAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_hazzarahAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 ManaBurn_Timer; - uint32 Sleep_Timer; - uint32 Illusions_Timer; + uint32 m_uiManaBurnTimer; + uint32 m_uiSleepTimer; + uint32 m_uiEarthShockTimer; + uint32 m_uiIllusionsTimer; void Reset() { - ManaBurn_Timer = urand(4000, 10000); - Sleep_Timer = urand(10000, 18000); - Illusions_Timer = urand(10000, 18000); + m_uiManaBurnTimer = urand(4000, 10000); + m_uiSleepTimer = urand(10000, 18000); + m_uiEarthShockTimer = urand(7000, 14000); + m_uiIllusionsTimer = urand(10000, 18000); + } + + 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 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //ManaBurn_Timer - if (ManaBurn_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MANABURN); - ManaBurn_Timer = urand(8000, 16000); - }else ManaBurn_Timer -= diff; - - //Sleep_Timer - if (Sleep_Timer < diff) + // ManaBurn_Timer + if (m_uiManaBurnTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SLEEP); - Sleep_Timer = urand(12000, 20000); - }else Sleep_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_CHAIN_BURN, SELECT_FLAG_POWER_MANA)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHAIN_BURN) == CAST_OK) + m_uiManaBurnTimer = urand(8000, 16000); + } + } + else + m_uiManaBurnTimer -= uiDiff; - //Illusions_Timer - if (Illusions_Timer < diff) + // Sleep_Timer + if (m_uiSleepTimer < uiDiff) { - //We will summon 3 illusions that will spawn on a random gamer and attack this gamer - //We will just use one model for the beginning - for(int i = 0; i < 3; ++i) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - if (Creature* pIllusion = m_creature->SummonCreature(15163, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000)) - pIllusion->AI()->AttackStart(pTarget); - } + if (DoCastSpellIfCan(pTarget, SPELL_SLEEP) == CAST_OK) + m_uiSleepTimer = urand(12000, 20000); } + } + else + m_uiSleepTimer -= uiDiff; + + // Earthshock + if (m_uiEarthShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EARTH_SHOCK) == CAST_OK) + m_uiEarthShockTimer = urand(9000, 16000); + } + else + m_uiEarthShockTimer -= uiDiff; - Illusions_Timer = urand(15000, 25000); - }else Illusions_Timer -= diff; + // Illusions_Timer + if (m_uiIllusionsTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_ILLUSION_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_ILLUSION_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_ILLUSION_3, CAST_TRIGGERED); + + m_uiIllusionsTimer = urand(15000, 25000); + } + else + m_uiIllusionsTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_hazzarah(Creature* pCreature) { return new boss_hazzarahAI(pCreature); @@ -88,9 +117,10 @@ CreatureAI* GetAI_boss_hazzarah(Creature* pCreature) void AddSC_boss_hazzarah() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_hazzarah"; - newscript->GetAI = &GetAI_boss_hazzarah; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_hazzarah"; + pNewScript->GetAI = &GetAI_boss_hazzarah; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp b/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp index 720fecdc87..085507fd53 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,28 +17,50 @@ /* 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 */ #include "precompiled.h" #include "zulgurub.h" -#define SAY_AGGRO -1309002 -#define SAY_RAIN_FIRE -1309003 -#define SAY_DEATH -1309004 - -#define SPELL_CHARGE 22911 -#define SPELL_SONICBURST 23918 -#define SPELL_SCREECH 6605 -#define SPELL_SHADOW_WORD_PAIN 23952 -#define SPELL_MIND_FLAY 23953 -#define SPELL_CHAIN_MIND_FLAY 26044 //Right ID unknown. So disabled -#define SPELL_GREATERHEAL 23954 -#define SPELL_BAT_FORM 23966 - -// Batriders Spell -#define SPELL_BOMB 40332 //Wrong ID but Magmadars bomb is not working... +enum +{ + SAY_AGGRO = -1309002, + SAY_RAIN_FIRE = -1309003, + SAY_SHRIEK = -1309026, + SAY_HEAL = -1309027, + SAY_DEATH = -1309004, + + // Bat spells + SPELL_CHARGE = 22911, + 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_BLOOD_LEECH = 22644, + SPELL_GREATERHEAL = 23954, + + // Common spells + SPELL_GREEN_CHANNELING = 13540, // visual for idle mode + SPELL_BAT_FORM = 23966, + + // Batriders Spell + 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 { @@ -50,152 +72,230 @@ struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 Charge_Timer; - uint32 SonicBurst_Timer; - uint32 Screech_Timer; - uint32 SpawnBats_Timer; - uint32 ShadowWordPain_Timer; - uint32 MindFlay_Timer; - uint32 ChainMindFlay_Timer; - uint32 GreaterHeal_Timer; - uint32 SpawnFlyingBats_Timer; + uint32 m_uiChargeTimer; + uint32 m_uiSwoopTimer; + uint32 m_uiSonicBurstTimer; + uint32 m_uiSpawnBatsTimer; + uint32 m_uiShadowWordPainTimer; + uint32 m_uiMindFlayTimer; + uint32 m_uiChainMindFlayTimer; + uint32 m_uiGreaterHealTimer; + uint32 m_uiFlyingBatsTimer; - bool PhaseTwo; + bool m_bIsPhaseOne; + + GuidList m_lBombRiderGuidsList; void Reset() { - Charge_Timer = 20000; - SonicBurst_Timer = 8000; - Screech_Timer = 13000; - SpawnBats_Timer = 60000; - ShadowWordPain_Timer = 6000; - MindFlay_Timer = 11000; - ChainMindFlay_Timer = 26000; - GreaterHeal_Timer = 50000; - SpawnFlyingBats_Timer = 10000; - - PhaseTwo = false; + m_uiChargeTimer = 20000; + m_uiSwoopTimer = 5000; + m_uiSonicBurstTimer = 8000; + m_uiSpawnBatsTimer = 50000; + m_uiShadowWordPainTimer = 6000; + m_uiMindFlayTimer = 11000; + m_uiChainMindFlayTimer = 26000; + m_uiGreaterHealTimer = 20000; + m_uiFlyingBatsTimer = 30000; + + m_bIsPhaseOne = true; + + DoCastSpellIfCan(m_creature, SPELL_GREEN_CHANNELING); + SetCombatMovement(false); } - void Aggro(Unit *who) + 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* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + DoDespawnBombRiders(); if (m_pInstance) m_pInstance->SetData(TYPE_JEKLIK, DONE); } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + DoDespawnBombRiders(); - if (m_creature->GetHealthPercent() > 50.0f) + if (m_pInstance) + m_pInstance->SetData(TYPE_JEKLIK, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FRENZIED_BAT) { - if (Charge_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_CHARGE); + 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()); + } - Charge_Timer = urand(15000, 30000); - }else Charge_Timer -= diff; + pSummoned->SetLevitate(true); + } - if (SonicBurst_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SONICBURST); - SonicBurst_Timer = urand(8000, 13000); - }else SonicBurst_Timer -= diff; + 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); - if (Screech_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SCREECH); - Screech_Timer = urand(18000, 26000); - }else Screech_Timer -= diff; + ScriptedAI::EnterEvadeMode(); + } - if (SpawnBats_Timer < diff) - { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; - Creature* Bat = NULL; - Bat = m_creature->SummonCreature(11368, -12291.6220f, -1380.2640f, 144.8304f, 5.483f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (target && Bat) Bat ->AI()->AttackStart(target); + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + } - Bat = m_creature->SummonCreature(11368, -12289.6220f, -1380.2640f, 144.8304f, 5.483f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (target && Bat) Bat ->AI()->AttackStart(target); + // Wrapper to despawn the bomb riders on evade / death + void DoDespawnBombRiders() + { + if (m_lBombRiderGuidsList.empty()) + return; - Bat = m_creature->SummonCreature(11368, -12293.6220f, -1380.2640f, 144.8304f, 5.483f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (target && Bat) Bat ->AI()->AttackStart(target); + 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) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - Bat = m_creature->SummonCreature(11368, -12291.6220f, -1380.2640f, 144.8304f, 5.483f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (target && Bat) Bat ->AI()->AttackStart(target); + // 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; + } + + 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; - Bat = m_creature->SummonCreature(11368, -12289.6220f, -1380.2640f, 144.8304f, 5.483f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (target && Bat) Bat ->AI()->AttackStart(target); + if (m_uiSwoopTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SWOOP) == CAST_OK) + m_uiSwoopTimer = urand(4000, 9000); + } + else + m_uiSwoopTimer -= uiDiff; - Bat = m_creature->SummonCreature(11368, -12293.6220f, -1380.2640f, 144.8304f, 5.483f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (target && Bat) Bat ->AI()->AttackStart(target); + if (m_uiSonicBurstTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SONIC_BURST) == CAST_OK) + m_uiSonicBurstTimer = urand(8000, 13000); + } + else + m_uiSonicBurstTimer -= uiDiff; - SpawnBats_Timer = 60000; - }else SpawnBats_Timer -= diff; + if (m_uiSpawnBatsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FRENZIED_BATS) == CAST_OK) + { + DoScriptText(SAY_SHRIEK, m_creature); + m_uiSpawnBatsTimer = 60000; + } + } + else + m_uiSpawnBatsTimer -= uiDiff; } + // Troll phase else { - if (PhaseTwo) + if (m_uiShadowWordPainTimer < uiDiff) { - if (PhaseTwo && ShadowWordPain_Timer < diff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - DoCastSpellIfCan(target, SPELL_SHADOW_WORD_PAIN); - ShadowWordPain_Timer = urand(12000, 18000); - } - }ShadowWordPain_Timer -=diff; + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_WORD_PAIN) == CAST_OK) + m_uiShadowWordPainTimer = urand(12000, 18000); + } + } + else + m_uiShadowWordPainTimer -= uiDiff; - if (MindFlay_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIND_FLAY); - MindFlay_Timer = 16000; - }MindFlay_Timer -=diff; + if (m_uiMindFlayTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIND_FLAY) == CAST_OK) + m_uiMindFlayTimer = 16000; + } + else + m_uiMindFlayTimer -= uiDiff; - if (ChainMindFlay_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_MIND_FLAY); - ChainMindFlay_Timer = urand(15000, 30000); - }ChainMindFlay_Timer -=diff; + if (m_uiChainMindFlayTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_LEECH) == CAST_OK) + m_uiChainMindFlayTimer = urand(15000, 30000); + } + else + m_uiChainMindFlayTimer -= uiDiff; - if (GreaterHeal_Timer < diff) + if (m_uiGreaterHealTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GREATERHEAL, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature,SPELL_GREATERHEAL); - GreaterHeal_Timer = urand(25000, 35000); - }GreaterHeal_Timer -=diff; + DoScriptText(SAY_HEAL, m_creature); + m_uiGreaterHealTimer = urand(25000, 35000); + } + } + else + m_uiGreaterHealTimer -= uiDiff; - if (SpawnFlyingBats_Timer < diff) + if (m_uiFlyingBatsTimer) + { + if (m_uiFlyingBatsTimer <= uiDiff) { - Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - Creature* FlyingBat = m_creature->SummonCreature(14965, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+15, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (FlyingBat) + // Note: the bat riders summoning and movement may need additional research + for (uint8 i = 0; i < 3; ++i) { - if (target) - FlyingBat->AI()->AttackStart(target); + 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); - SpawnFlyingBats_Timer = urand(10000, 15000); - } else SpawnFlyingBats_Timer -=diff; - } - else - { - m_creature->SetDisplayId(15219); - DoResetThreat(); - PhaseTwo = true; + m_uiFlyingBatsTimer = 0; + } + else + m_uiFlyingBatsTimer -= uiDiff; } } @@ -203,57 +303,85 @@ struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI } }; -//Flying Bat -struct MANGOS_DLL_DECL mob_batriderAI : public ScriptedAI +struct MANGOS_DLL_DECL 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 Bomb_Timer; - uint32 Check_Timer; + uint32 m_uiInfectedBiteTimer; + uint32 m_uiBattleCommandTimer; void Reset() { - Bomb_Timer = 2000; - Check_Timer = 1000; + m_uiInfectedBiteTimer = 6500; + m_uiBattleCommandTimer = 8000; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_bHasDoneConcoction = false; + + DoCastSpellIfCan(m_creature, SPELL_TRASH); } - void UpdateAI (const uint32 diff) + 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; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // Don't attack if is summoned by Jeklik + if (m_bIsSummon) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Bomb_Timer - if (Bomb_Timer < diff) + if (!m_bHasDoneConcoction && m_creature->GetHealthPercent() < 50.0f) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - DoCastSpellIfCan(target, SPELL_BOMB); - Bomb_Timer = 5000; - } - }else Bomb_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_UNSTABLE_CONCOCTION) == CAST_OK) + m_bHasDoneConcoction = true; + } - //Check_Timer - if (Check_Timer < diff) + if (m_uiInfectedBiteTimer < uiDiff) { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_JEKLIK) == DONE) - { - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - return; - } - } - Check_Timer = 1000; - }else Check_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INFECTED_BITE) == CAST_OK) + m_uiInfectedBiteTimer = 6500; + } + else + m_uiInfectedBiteTimer -= uiDiff; + + if (m_uiBattleCommandTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BATTLE_COMMAND) == CAST_OK) + m_uiBattleCommandTimer = 25000; + } + else + m_uiBattleCommandTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -264,21 +392,22 @@ 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() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_jeklik"; - newscript->GetAI = &GetAI_boss_jeklik; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_batrider"; - newscript->GetAI = &GetAI_mob_batrider; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_jeklik"; + pNewScript->GetAI = &GetAI_boss_jeklik; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 971e59c0dc..f7553ba855 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,27 +17,37 @@ /* ScriptData SDName: Boss_Jin'do the Hexxer SD%Complete: 85 -SDComment: Mind Control not working because of core bug. Shades visible for all. +SDComment: Mind Control not working because of core bug. Shades invisible is removed as of Attacking (core bug) - MANY HACKZ!! SDCategory: Zul'Gurub EndScriptData */ #include "precompiled.h" #include "zulgurub.h" -#define SAY_AGGRO -1309014 +enum +{ + SAY_AGGRO = -1309014, + + SPELL_BRAINWASH_TOTEM = 24262, + SPELL_POWERFULL_HEALING_WARD = 24309, + SPELL_HEX = 24053, + SPELL_DELUSIONS_OF_JINDO = 24306, + SPELL_SHADE_OF_JINDO = 24308, // Spell was removed from DBC around TBC; will summon npcs manually! -#define SPELL_BRAINWASHTOTEM 24262 -#define SPELL_POWERFULLHEALINGWARD 24309 //We will not use this spell. We will summon a totem by script cause the spell totems will not cast. -#define SPELL_HEX 24053 -#define SPELL_DELUSIONSOFJINDO 24306 -#define SPELL_SHADEOFJINDO 24308 //We will not use this spell. We will summon a shade by script. + SPELL_HEALING_WARD_HEAL = 24311, -//Healing Ward Spell -#define SPELL_HEAL 38588 //Totems are not working right. Right heal spell ID is 24311 but this spell is not casting... + // npcs + NPC_SHADE_OF_JINDO = 14986, + NPC_SACRIFICED_TROLL = 14826, + NPC_POWERFULL_HEALING_WARD = 14987, + + MAX_SKELETONS = 9, +}; -//Shade of Jindo Spell -#define SPELL_SHADOWSHOCK 19460 -#define SPELL_INVISIBLE 24699 +static const float aPitTeleportLocs[4] = +{ + -11583.7783f, -1249.4278f, 77.5471f, 4.745f +}; struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI { @@ -49,194 +59,139 @@ struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 BrainWashTotem_Timer; - uint32 HealingWard_Timer; - uint32 Hex_Timer; - uint32 Delusions_Timer; - uint32 Teleport_Timer; + uint32 m_uiBrainWashTotemTimer; + uint32 m_uiHealingWardTimer; + uint32 m_uiHexTimer; + uint32 m_uiDelusionsTimer; + uint32 m_uiTeleportTimer; void Reset() { - BrainWashTotem_Timer = 20000; - HealingWard_Timer = 16000; - Hex_Timer = 8000; - Delusions_Timer = 10000; - Teleport_Timer = 5000; + m_uiBrainWashTotemTimer = 20000; + m_uiHealingWardTimer = 16000; + m_uiHexTimer = 8000; + m_uiDelusionsTimer = 10000; + m_uiTeleportTimer = 5000; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void UpdateAI(const uint32 diff) + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_POWERFULL_HEALING_WARD) + m_uiHealingWardTimer = 15000; // how long delay? + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //BrainWashTotem_Timer - if (BrainWashTotem_Timer < diff) + // Brain Wash Totem Timer + if (m_uiBrainWashTotemTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BRAINWASHTOTEM); - BrainWashTotem_Timer = urand(18000, 26000); - }else BrainWashTotem_Timer -= diff; - - //HealingWard_Timer - if (HealingWard_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_BRAINWASH_TOTEM) == CAST_OK) + m_uiBrainWashTotemTimer = urand(18000, 26000); + } + else + m_uiBrainWashTotemTimer -= uiDiff; + + // Healing Ward Timer + if (m_uiHealingWardTimer) { - //DoCastSpellIfCan(m_creature, SPELL_POWERFULLHEALINGWARD); - m_creature->SummonCreature(14987, m_creature->GetPositionX()+3, m_creature->GetPositionY()-2, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,30000); - HealingWard_Timer = urand(14000, 20000); - }else HealingWard_Timer -= diff; + if (m_uiHealingWardTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POWERFULL_HEALING_WARD) == CAST_OK) + m_uiHealingWardTimer = 0; + } + else + m_uiHealingWardTimer -= uiDiff; + } - //Hex_Timer - if (Hex_Timer < diff) + // Hex Timer + if (m_uiHexTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEX); - - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); - - Hex_Timer = urand(12000, 20000); - }else Hex_Timer -= diff; - - //Casting the delusion curse with a shade. So shade will attack the same target with the curse. - if (Delusions_Timer < diff) + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEX) == CAST_OK) + m_uiHexTimer = urand(12000, 20000); + } + else + m_uiHexTimer -= uiDiff; + + // Casting the delusion curse with a shade. So shade will attack the same target with the curse. + if (m_uiDelusionsTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + // random target except the tank + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); + + if (DoCastSpellIfCan(pTarget, SPELL_DELUSIONS_OF_JINDO) == CAST_OK) { - DoCastSpellIfCan(target, SPELL_DELUSIONSOFJINDO); + 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_OOC_DESPAWN, 15000)) + pSummoned->AI()->AttackStart(pTarget); - Creature *Shade = m_creature->SummonCreature(14986, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Shade) - Shade->AI()->AttackStart(target); + m_uiDelusionsTimer = urand(4000, 12000); } + } + else + m_uiDelusionsTimer -= uiDiff; - Delusions_Timer = urand(4000, 12000); - }else Delusions_Timer -= diff; - - //Teleporting a random gamer and spawning 9 skeletons that will attack this gamer - if (Teleport_Timer < diff) + // Teleporting a random player and spawning 9 skeletons that will attack this player + if (m_uiTeleportTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoTeleportPlayer(target, -11583.7783f, -1249.4278f, 77.5471f, 4.745f); - - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(target,-100); - - Creature *Skeletons; - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()-2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()-4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = m_creature->SummonCreature(14826, target->GetPositionX()+3, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - } - - Teleport_Timer = urand(15000, 23000); - }else Teleport_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -//Healing Ward -struct MANGOS_DLL_DECL mob_healing_wardAI : public ScriptedAI -{ - mob_healing_wardAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 Heal_Timer; - - void Reset() - { - Heal_Timer = 2000; - } + DoTeleportPlayer(pTarget, aPitTeleportLocs[0], aPitTeleportLocs[1], aPitTeleportLocs[2], aPitTeleportLocs[3]); - void UpdateAI (const uint32 diff) - { - //Heal_Timer - if (Heal_Timer < diff) - { - if (m_pInstance) - { - if (Unit *pJindo = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_JINDO))) + // summon 9 skeletons in the pit at random points + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_SKELETONS; ++i) { - if (pJindo->isAlive()) - DoCastSpellIfCan(pJindo, SPELL_HEAL); + 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_OOC_DESPAWN, 15000)) + pSummoned->AI()->AttackStart(pTarget); } - } - Heal_Timer = 3000; - }else Heal_Timer -= diff; - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + m_uiTeleportTimer = urand(15000, 23000); + } + } + else + m_uiTeleportTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Shade of Jindo -struct MANGOS_DLL_DECL mob_shade_of_jindoAI : public ScriptedAI +// HACK script! Should not need to have totems in sd2 +struct MANGOS_DLL_DECL mob_healing_wardAI : public ScriptedAI { - mob_shade_of_jindoAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; + mob_healing_wardAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 ShadowShock_Timer; + uint32 m_uiHealTimer; void Reset() { - ShadowShock_Timer = 1000; - m_creature->CastSpell(m_creature, SPELL_INVISIBLE,true); + m_uiHealTimer = 3000; // Timer unknown, sources go over 1s, per tick to 3s, keep 3s as in original script } - void UpdateAI (const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} - //ShadowShock_Timer - if (ShadowShock_Timer < diff) + void UpdateAI(const uint32 uiDiff) override + { + // Heal Timer + if (m_uiHealTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWSHOCK); - ShadowShock_Timer = 2000; - }else ShadowShock_Timer -= diff; - - DoMeleeAttackIfReady(); + DoCastSpellIfCan(m_creature, SPELL_HEALING_WARD_HEAL); + m_uiHealTimer = 3000; + } + else + m_uiHealTimer -= uiDiff; } }; @@ -250,27 +205,17 @@ 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_jindo"; - newscript->GetAI = &GetAI_boss_jindo; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_healing_ward"; - newscript->GetAI = &GetAI_mob_healing_ward; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_shade_of_jindo"; - newscript->GetAI = &GetAI_mob_shade_of_jindo; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_jindo"; + pNewScript->GetAI = &GetAI_boss_jindo; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_healing_ward"; + pNewScript->GetAI = &GetAI_mob_healing_ward; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp b/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp index e2eeeca3c4..7b972ade99 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,115 +47,120 @@ 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 }; -struct SpawnLocations +static LOCATION aSpirits[] = { - float fX, fY, fZ, fAng; + { -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 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} -}; - -static SpawnLocations aMandokirDownstairsPos = {-12196.30f, -1948.37f, 130.31f, 3.77f}; - struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI { boss_mandokirAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_uiOhganGUID = 0; Reset(); } 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; - uint64 m_uiWatchTarget; - uint64 m_uiOhganGUID; + ObjectGuid m_watchTargetGuid; void Reset() { - 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_bRaptorDead = false; - m_bMandokirDownstairs = false; + m_fTargetThreat = 0.0f; + } - m_fTargetThreat = 0.0f; - m_uiWatchTarget = 0; + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); - if (Creature* pOhgan = m_creature->GetMap()->GetCreature(m_uiOhganGUID)) - pOhgan->ForcedDespawn(); + for (uint8 i = 0; i < countof(aSpirits); ++i) + m_creature->SummonCreature(NPC_CHAINED_SPIRIT, aSpirits[i].x, aSpirits[i].y, aSpirits[i].z, aSpirits[i].o, 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_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); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_OHGAN, DONE); + } - std::list lSpirits; //despawn spirits - GetCreatureListWithEntryInGrid(lSpirits, m_creature, NPC_CHAINED_SPIRIT, DEFAULT_VISIBILITY_INSTANCE); + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); - if (!lSpirits.empty()) - { - for(std::list::iterator iter = lSpirits.begin(); iter != lSpirits.end(); ++iter) - { - if ((*iter) && (*iter)->isAlive()) - (*iter)->ForcedDespawn(); - } - } + // 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_creature->SetLootRecipient(NULL); - m_bMandokirDownstairs = false; + Reset(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) { @@ -167,113 +172,85 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI if (m_pInstance) { - if (Creature* jTemp = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_JINDO))) + if (Creature* pJindo = m_pInstance->GetSingleCreatureFromStorage(NPC_JINDO)) { - if (jTemp->isAlive()) - DoScriptText(SAY_GRATS_JINDO, jTemp); + if (pJindo->isAlive()) + DoScriptText(SAY_GRATS_JINDO, pJindo); } } 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); - - m_creature->SetInCombatWithZone(); - - 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_uiOhganGUID = pSummoned->GetGUID(); - 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_uiOhganGUID = 0; + { + 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) { DoScriptText(SAY_WATCH, m_creature, pTarget); DoScriptText(SAY_WATCH_WHISPER, m_creature, pTarget); - m_uiWatchTarget = pTarget->GetGUID(); + 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->GetDurationIndex()); } } - 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->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - 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 (m_uiWatchTarget) + // If someone is watched + if (m_watchTargetGuid) { - Player* pWatchTarget = m_creature->GetMap()->GetPlayer(m_uiWatchTarget); + 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)) @@ -282,7 +259,7 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI DoCastSpellIfCan(pWatchTarget, SPELL_CHARGE); } - m_uiWatchTarget = 0; + m_watchTargetGuid.Clear(); } else { @@ -293,103 +270,83 @@ 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_uiWatchTarget) + 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()); - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pTarget, ATTACK_DISTANCE)) + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && m_creature->CanReachWithMeleeAttack(pTarget)) ++uiTargetInRangeCount; } 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 - if (m_creature->getVictim()->GetHealthPercent() < 50.0f) + // Mortal Strike if target below 50% hp + if (m_creature->getVictim() && 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 +// Ohgan struct MANGOS_DLL_DECL 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() { - 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) { @@ -401,19 +358,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(); } @@ -431,15 +388,15 @@ CreatureAI* GetAI_mob_ohgan(Creature* pCreature) void AddSC_boss_mandokir() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_mandokir"; - newscript->GetAI = &GetAI_boss_mandokir; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_mandokir"; + pNewScript->GetAI = &GetAI_boss_mandokir; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_ohgan"; - newscript->GetAI = &GetAI_mob_ohgan; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_ohgan"; + pNewScript->GetAI = &GetAI_mob_ohgan; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp b/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp index 21593e15b4..82357f1508 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,29 +26,29 @@ 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 @@ -56,286 +56,180 @@ struct MANGOS_DLL_DECL 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() { - 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; + m_uiTransformTimer -= 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; - - 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(); - } - - 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_pInstance && m_pInstance->GetData(TYPE_MARLI) != DONE) - { - DoCastSpellIfCan(m_creature,SPELL_LEVELUP); - m_creature->SetLevel(m_creature->getLevel() + 1); - } - m_uiLevelUp_Timer = 3000; - } - else - m_uiLevelUp_Timer -= uiDiff; + m_uiTrashTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -346,22 +240,12 @@ 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* newscript; - - newscript = new Script; - newscript->Name = "boss_marli"; - newscript->GetAI = &GetAI_boss_marli; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "mob_spawn_of_marli"; - newscript->GetAI = &GetAI_mob_spawn_of_marli; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_marli"; + pNewScript->GetAI = &GetAI_boss_marli; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp b/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp index 36c01b60a5..0627786613 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,114 +22,100 @@ SDCategory: Zul'Gurub EndScriptData */ #include "precompiled.h" -#include "zulgurub.h" -#define SPELL_AMBUSH 24337 -#define SPELL_THOUSANDBLADES 24649 - -#define EQUIP_ID_MAIN_HAND 0 //was item display id 31818, but this id does not exist +enum +{ + SPELL_THOUSAND_BLADES = 24649, + SPELL_VANISH = 24699, + SPELL_GOUGE = 24698, + SPELL_TRASH = 3391 +}; struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI { - boss_renatakiAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_renatakiAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 Invisible_Timer; - uint32 Ambush_Timer; - uint32 Visible_Timer; - uint32 Aggro_Timer; - uint32 ThousandBlades_Timer; - - bool Invisible; - bool Ambushed; + uint32 m_uiVanishTimer; + uint32 m_uiAmbushTimer; + uint32 m_uiGougeTimer; + uint32 m_uiThousandBladesTimer; void Reset() { - Invisible_Timer = urand(8000, 18000); - Ambush_Timer = 3000; - Visible_Timer = 4000; - Aggro_Timer = urand(15000, 25000); - ThousandBlades_Timer = urand(4000, 8000); - - Invisible = false; - Ambushed = false; + m_uiVanishTimer = urand(25000, 30000); + m_uiAmbushTimer = 0; + m_uiGougeTimer = urand(15000, 25000); + m_uiThousandBladesTimer = urand(4000, 8000); } - void UpdateAI(const uint32 diff) + void EnterEvadeMode() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // If is vanished, don't evade + if (m_uiAmbushTimer) return; - //Invisible_Timer - if (Invisible_Timer < diff) - { - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - m_creature->SetDisplayId(11686); - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Invisible = true; + ScriptedAI::EnterEvadeMode(); + } - Invisible_Timer = urand(15000, 30000); - }else Invisible_Timer -= diff; + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - if (Invisible) + // Note: because the Vanish spell adds invisibility effect on the target, the timers won't be decreased during the vanish phase + if (m_uiAmbushTimer) { - if (Ambush_Timer < diff) + if (m_uiAmbushTimer <= uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - m_creature->NearTeleportTo(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f); - DoCastSpellIfCan(pTarget, SPELL_AMBUSH); - } - - Ambushed = true; - Ambush_Timer = 3000; - }else Ambush_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiAmbushTimer = 0; + } + else + m_uiAmbushTimer -= uiDiff; + + // don't do anything else while vanished + return; } - if (Ambushed) + // Invisible_Timer + if (m_uiVanishTimer < uiDiff) { - if (Visible_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_VANISH) == CAST_OK) { - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - - m_creature->SetDisplayId(15268); - SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Invisible = false; - - Visible_Timer = 4000; - }else Visible_Timer -= diff; + m_uiVanishTimer = urand(25000, 40000); + m_uiAmbushTimer = 2000; + } } + else + m_uiVanishTimer -= uiDiff; - //Resetting some aggro so he attacks other gamers - if (!Invisible) - if (Aggro_Timer < diff) + // Resetting some aggro so he attacks other gamers + if (m_uiGougeTimer < uiDiff) { - 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); + if (DoCastSpellIfCan(m_creature, SPELL_GOUGE) == CAST_OK) + { + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -50); - Aggro_Timer = urand(7000, 20000); - }else Aggro_Timer -= diff; + m_uiGougeTimer = urand(7000, 20000); + } + } + else + m_uiGougeTimer -= uiDiff; - if (!Invisible) - if (ThousandBlades_Timer < diff) + // Thausand Blades + if (m_uiThousandBladesTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_THOUSANDBLADES); - ThousandBlades_Timer = urand(7000, 12000); - }else ThousandBlades_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_THOUSAND_BLADES) == CAST_OK) + m_uiThousandBladesTimer = urand(7000, 12000); + } + else + m_uiThousandBladesTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_renataki(Creature* pCreature) { return new boss_renatakiAI(pCreature); @@ -137,9 +123,10 @@ CreatureAI* GetAI_boss_renataki(Creature* pCreature) void AddSC_boss_renataki() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_renataki"; - newscript->GetAI = &GetAI_boss_renataki; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_renataki"; + pNewScript->GetAI = &GetAI_boss_renataki; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp b/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp index 23c2ac2319..48cb3c4a32 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,35 +24,122 @@ EndScriptData */ #include "precompiled.h" #include "zulgurub.h" -#define SAY_AGGRO -1309009 -#define SAY_DEATH -1309010 - -#define SPELL_MORTALCLEAVE 22859 -#define SPELL_SILENCE 23207 -#define SPELL_FRENZY 23342 -#define SPELL_FORCEPUNCH 24189 -#define SPELL_CHARGE 24408 -#define SPELL_ENRAGE 23537 -#define SPELL_SUMMONTIGERS 24183 -#define SPELL_TIGER_FORM 24169 -#define SPELL_RESURRECT 24173 //We will not use this spell. - -//Zealot Lor'Khan Spells -#define SPELL_SHIELD 25020 -#define SPELL_BLOODLUST 24185 -#define SPELL_GREATERHEAL 24208 -#define SPELL_DISARM 22691 - -//Zealot Lor'Khan Spells -#define SPELL_SWEEPINGSTRIKES 18765 -#define SPELL_SINISTERSTRIKE 15667 -#define SPELL_GOUGE 24698 -#define SPELL_KICK 15614 -#define SPELL_BLIND 21060 - -struct MANGOS_DLL_DECL boss_thekalAI : public ScriptedAI +enum { - boss_thekalAI(Creature* pCreature) : ScriptedAI(pCreature) + SAY_AGGRO = -1309009, + SAY_DEATH = -1309010, + + SPELL_MORTAL_CLEAVE = 22859, + SPELL_SILENCE = 23207, + SPELL_FRENZY = 23128, + SPELL_FORCE_PUNCH = 24189, + SPELL_CHARGE = 24408, + SPELL_ENRAGE = 23537, + SPELL_SUMMON_TIGERS = 24183, + SPELL_TIGER_FORM = 24169, + SPELL_RESURRECT = 24173, + + // Zealot Lor'Khan Spells + SPELL_SHIELD = 25020, + SPELL_BLOODLUST = 24185, + SPELL_GREATER_HEAL = 24208, + SPELL_DISARM = 22691, + + // Zealot Lor'Khan Spells + SPELL_SWEEPING_STRIKES = 18765, + SPELL_SINISTER_STRIKE = 15667, + SPELL_GOUGE = 24698, + SPELL_KICK = 15614, + SPELL_BLIND = 21060, + + PHASE_NORMAL = 1, + PHASE_FAKE_DEATH = 2, + PHASE_WAITING = 3, + PHASE_TIGER = 4, +}; + +// abstract base class for faking death +struct MANGOS_DLL_DECL boss_thekalBaseAI : public ScriptedAI +{ + boss_thekalBaseAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_uiPhase = PHASE_NORMAL; + } + + uint8 m_uiPhase; + + virtual void OnFakeingDeath() {} + virtual void OnRevive() {} + + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override + { + if (uiDamage < m_creature->GetHealth()) + return; + + // Prevent glitch if in fake death + if (m_uiPhase == PHASE_FAKE_DEATH || m_uiPhase == PHASE_WAITING) + { + uiDamage = 0; + return; + } + + // Only init fake in normal phase + if (m_uiPhase != PHASE_NORMAL) + return; + + 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(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + m_uiPhase = PHASE_FAKE_DEATH; + + OnFakeingDeath(); + } + + void Revive(bool bOnlyFlags = false) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + if (bOnlyFlags) + return; + + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_uiPhase = PHASE_NORMAL; + + DoResetThreat(); + Reset(); + + // Assume Attack + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + OnRevive(); + } + + void PreventRevive() + { + if (m_creature->IsNonMeleeSpellCasted(true)) + m_creature->InterruptNonMeleeSpells(true); + + m_uiPhase = PHASE_WAITING; + } +}; + +struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI +{ + boss_thekalAI(Creature* pCreature) : boss_thekalBaseAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -60,455 +147,502 @@ struct MANGOS_DLL_DECL boss_thekalAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 MortalCleave_Timer; - uint32 Silence_Timer; - uint32 Frenzy_Timer; - uint32 ForcePunch_Timer; - uint32 Charge_Timer; - uint32 Enrage_Timer; - uint32 SummonTigers_Timer; - uint32 Check_Timer; - uint32 Resurrect_Timer; + uint32 m_uiMortalCleaveTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiFrenzyTimer; + uint32 m_uiForcePunchTimer; + uint32 m_uiChargeTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiSummonTigersTimer; + uint32 m_uiResurrectTimer; - bool Enraged; - bool PhaseTwo; - bool WasDead; + bool m_bEnraged; void Reset() { - MortalCleave_Timer = 4000; - Silence_Timer = 9000; - Frenzy_Timer = 30000; - ForcePunch_Timer = 4000; - Charge_Timer = 12000; - Enrage_Timer = 32000; - SummonTigers_Timer = 25000; - Check_Timer = 10000; - Resurrect_Timer = 10000; - - Enraged = false; - PhaseTwo = false; - WasDead = false; + m_uiMortalCleaveTimer = 4000; + m_uiSilenceTimer = 9000; + m_uiFrenzyTimer = 30000; + m_uiForcePunchTimer = 4000; + m_uiChargeTimer = 12000; + m_uiEnrageTimer = 32000; + m_uiSummonTigersTimer = 25000; + m_uiResurrectTimer = 10000; + m_uiPhase = PHASE_NORMAL; + + m_bEnraged = false; + + // remove fake death + Revive(true); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_THEKAL, DONE); + + // remove the two adds + if (Creature* pZath = m_pInstance->GetSingleCreatureFromStorage(NPC_ZATH)) + pZath->ForcedDespawn(); + if (Creature* pLorkhan = m_pInstance->GetSingleCreatureFromStorage(NPC_LORKHAN)) + pLorkhan->ForcedDespawn(); + } + + void JustReachedHome() override + { if (m_pInstance) - m_pInstance->SetData(TYPE_THEKAL, DONE); + m_pInstance->SetData(TYPE_THEKAL, FAIL); + } + + // Only call in context where m_pInstance is valid + bool CanPreventAddsResurrect() + { + // If any add is alive, return false + if (m_pInstance->GetData(TYPE_ZATH) != SPECIAL || m_pInstance->GetData(TYPE_LORKHAN) != SPECIAL) + return false; + + // Else Prevent them Resurrecting + if (Creature* pLorkhan = m_pInstance->GetSingleCreatureFromStorage(NPC_LORKHAN)) + { + if (boss_thekalBaseAI* pFakerAI = dynamic_cast(pLorkhan->AI())) + pFakerAI->PreventRevive(); + } + if (Creature* pZath = m_pInstance->GetSingleCreatureFromStorage(NPC_ZATH)) + { + if (boss_thekalBaseAI* pFakerAI = dynamic_cast(pZath->AI())) + pFakerAI->PreventRevive(); + } + + return true; } - void JustReachedHome() + void OnFakeingDeath() { + m_uiResurrectTimer = 10000; + if (m_pInstance) - m_pInstance->SetData(TYPE_THEKAL, NOT_STARTED); + { + m_pInstance->SetData(TYPE_THEKAL, SPECIAL); + + // If both Adds are already dead, don't wait 10 seconds + if (CanPreventAddsResurrect()) + m_uiResurrectTimer = 1000; + } + } + + void OnRevive() + { + if (!m_pInstance) + return; + + // Both Adds are 'dead' enter tiger phase + if (CanPreventAddsResurrect()) + { + DoCastSpellIfCan(m_creature, SPELL_TIGER_FORM, CAST_TRIGGERED); + m_uiPhase = PHASE_TIGER; + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Check_Timer for the death of LorKhan and Zath. - if (!WasDead && Check_Timer < diff) + switch (m_uiPhase) { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_LORKHAN) == SPECIAL) + case PHASE_FAKE_DEATH: + if (m_uiResurrectTimer < uiDiff) { - //Resurrect LorKhan - if (Creature *pLorKhan = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_LORKHAN))) - { - pLorKhan->SetStandState(UNIT_STAND_STATE_STAND); - pLorKhan->setFaction(14); - pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pLorKhan->SetHealth(int(pLorKhan->GetMaxHealth()*1.0)); + // resurrect him in any case + DoCastSpellIfCan(m_creature, SPELL_RESURRECT); - m_pInstance->SetData(TYPE_LORKHAN, DONE); + m_uiPhase = PHASE_WAITING; + if (m_pInstance) + { + CanPreventAddsResurrect(); + m_pInstance->SetData(TYPE_THEKAL, IN_PROGRESS); } } + else + m_uiResurrectTimer -= uiDiff; + + // No break needed here + case PHASE_WAITING: + return; - if (m_pInstance->GetData(TYPE_ZATH) == SPECIAL) + case PHASE_NORMAL: + if (m_uiMortalCleaveTimer < uiDiff) { - //Resurrect Zath - if (Creature *pZath = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_ZATH))) - { - pZath->SetStandState(UNIT_STAND_STATE_STAND); - pZath->setFaction(14); - pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pZath->SetHealth(int(pZath->GetMaxHealth()*1.0)); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_CLEAVE) == CAST_OK) + m_uiMortalCleaveTimer = urand(15000, 20000); + } + else + m_uiMortalCleaveTimer -= uiDiff; - m_pInstance->SetData(TYPE_ZATH, DONE); + if (m_uiSilenceTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = urand(20000, 25000); } } - } - Check_Timer = 5000; - }else Check_Timer -= diff; - - if (!PhaseTwo && MortalCleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTALCLEAVE); - MortalCleave_Timer = urand(15000, 20000); - }else MortalCleave_Timer -= diff; - - if (!PhaseTwo && Silence_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SILENCE); - Silence_Timer = urand(20000, 25000); - }else Silence_Timer -= diff; + else + m_uiSilenceTimer -= uiDiff; - if (!PhaseTwo && !WasDead && m_creature->GetHealthPercent() < 5.0f) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); - m_creature->AttackStop(); - - if (m_pInstance) - m_pInstance->SetData(TYPE_THEKAL, SPECIAL); + break; + case PHASE_TIGER: + if (m_uiChargeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) + { + DoResetThreat(); + AttackStart(pTarget); + m_uiChargeTimer = urand(15000, 22000); + } + } + } + else + m_uiChargeTimer -= uiDiff; - WasDead = true; - } + if (m_uiFrenzyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + m_uiFrenzyTimer = 30000; + } + else + m_uiFrenzyTimer -= uiDiff; - //Thekal will transform to Tiger if he died and was not resurrected after 10 seconds. - if (!PhaseTwo && WasDead) - { - if (Resurrect_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_TIGER_FORM); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.00f); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetHealth(int(m_creature->GetMaxHealth()*1.0)); - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 40))); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 40))); - m_creature->UpdateDamagePhysical(BASE_ATTACK); - DoResetThreat(); - PhaseTwo = true; - }else Resurrect_Timer -= diff; - } + if (m_uiForcePunchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FORCE_PUNCH) == CAST_OK) + m_uiForcePunchTimer = urand(16000, 21000); + } + else + m_uiForcePunchTimer -= uiDiff; - if (m_creature->GetHealthPercent() == 100.0f && WasDead) - { - WasDead = false; - } + if (m_uiSummonTigersTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_TIGERS) == CAST_OK) + m_uiSummonTigersTimer = 50000; + } + else + m_uiSummonTigersTimer -= uiDiff; - if (PhaseTwo) - { - if (Charge_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (!m_bEnraged && m_creature->GetHealthPercent() < 11.0f) { - DoCastSpellIfCan(target,SPELL_CHARGE); - DoResetThreat(); - AttackStart(target); + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bEnraged = true; } - Charge_Timer = urand(15000, 22000); - }else Charge_Timer -= diff; - - if (Frenzy_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_FRENZY); - Frenzy_Timer = 30000; - }else Frenzy_Timer -= diff; - - if (ForcePunch_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SILENCE); - ForcePunch_Timer = urand(16000, 21000); - }else ForcePunch_Timer -= diff; - - if (SummonTigers_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SUMMONTIGERS); - SummonTigers_Timer = urand(10000, 14000); - }else SummonTigers_Timer -= diff; - - if (m_creature->GetHealthPercent() < 11.0f && !Enraged) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - Enraged = true; - } + + break; } DoMeleeAttackIfReady(); } }; -//Zealot Lor'Khan -struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public ScriptedAI +/*###### +## mob_zealot_lorkhan +######*/ + +struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI { - mob_zealot_lorkhanAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_zealot_lorkhanAI(Creature* pCreature) : boss_thekalBaseAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - uint32 Shield_Timer; - uint32 BloodLust_Timer; - uint32 GreaterHeal_Timer; - uint32 Disarm_Timer; - uint32 Check_Timer; - - bool FakeDeath; - ScriptedInstance* m_pInstance; + uint32 m_uiShieldTimer; + uint32 m_uiBloodLustTimer; + uint32 m_uiGreaterHealTimer; + uint32 m_uiDisarmTimer; + uint32 m_uiResurrectTimer; + void Reset() { - Shield_Timer = 1000; - BloodLust_Timer = 16000; - GreaterHeal_Timer = 32000; - Disarm_Timer = 6000; - Check_Timer = 10000; - - FakeDeath = false; + m_uiShieldTimer = 1000; + m_uiBloodLustTimer = 16000; + m_uiGreaterHealTimer = 32000; + m_uiDisarmTimer = 6000; + m_uiPhase = PHASE_NORMAL; if (m_pInstance) m_pInstance->SetData(TYPE_LORKHAN, NOT_STARTED); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Revive(true); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LORKHAN, IN_PROGRESS); + } + + void OnFakeingDeath() + { + m_uiResurrectTimer = 10000; + + if (m_pInstance) + m_pInstance->SetData(TYPE_LORKHAN, SPECIAL); } - void UpdateAI (const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Shield_Timer - if (Shield_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_SHIELD); - Shield_Timer = 61000; - }else Shield_Timer -= diff; - - //BloodLust_Timer - if (BloodLust_Timer < diff) + switch (m_uiPhase) { - DoCastSpellIfCan(m_creature,SPELL_BLOODLUST); - BloodLust_Timer = urand(20000, 28000); - }else BloodLust_Timer -= diff; + case PHASE_FAKE_DEATH: + if (m_uiResurrectTimer < uiDiff) + { + if (!m_pInstance) + return; - //Casting Greaterheal to Thekal or Zath if they are in meele range. - if (GreaterHeal_Timer < diff) - { - if (m_pInstance) - { - Creature* pThekal = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_THEKAL)); - Creature* pZath = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_ZATH)); + if (m_pInstance->GetData(TYPE_THEKAL) != SPECIAL || m_pInstance->GetData(TYPE_ZATH) != SPECIAL) + { + DoCastSpellIfCan(m_creature, SPELL_RESURRECT); + m_pInstance->SetData(TYPE_LORKHAN, IN_PROGRESS); + } - switch(urand(0, 1)) - { - case 0: - if (pThekal && m_creature->IsWithinDistInMap(pThekal, ATTACK_DISTANCE)) - DoCastSpellIfCan(pThekal, SPELL_GREATERHEAL); - break; - case 1: - if (pZath && m_creature->IsWithinDistInMap(pZath, ATTACK_DISTANCE)) - DoCastSpellIfCan(pZath, SPELL_GREATERHEAL); - break; + m_uiPhase = PHASE_WAITING; } - } + else + m_uiResurrectTimer -= uiDiff; - GreaterHeal_Timer = urand(15000, 20000); - }else GreaterHeal_Timer -= diff; + // no break needed here + case PHASE_WAITING: + return; - //Disarm_Timer - if (Disarm_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DISARM); - Disarm_Timer = urand(15000, 25000); - }else Disarm_Timer -= diff; + case PHASE_NORMAL: + // Shield_Timer + if (m_uiShieldTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHIELD) == CAST_OK) + m_uiShieldTimer = 61000; + } + else + m_uiShieldTimer -= uiDiff; - //Check_Timer for the death of LorKhan and Zath. - if (!FakeDeath && Check_Timer < diff) - { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_THEKAL) == SPECIAL) + // BloodLust_Timer + if (m_uiBloodLustTimer < uiDiff) { - //Resurrect Thekal - if (Creature* pThekal = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_THEKAL))) - { - pThekal->SetStandState(UNIT_STAND_STATE_STAND); - pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pThekal->setFaction(14); - pThekal->SetHealth(int(pThekal->GetMaxHealth()*1.0)); - } + // ToDo: research if this should be cast on Thekal or Zath + if (DoCastSpellIfCan(m_creature, SPELL_BLOODLUST) == CAST_OK) + m_uiBloodLustTimer = urand(20000, 28000); } + else + m_uiBloodLustTimer -= uiDiff; - if (m_pInstance->GetData(TYPE_ZATH) == SPECIAL) + // Casting Greaterheal to Thekal or Zath if they are in meele range. + // TODO - why this range check? + if (m_uiGreaterHealTimer < uiDiff) { - //Resurrect Zath - if (Creature* pZath = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_ZATH))) + if (m_pInstance) { - pZath->SetStandState(UNIT_STAND_STATE_STAND); - pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pZath->setFaction(14); - pZath->SetHealth(int(pZath->GetMaxHealth()*1.0)); + Creature* pThekal = m_pInstance->GetSingleCreatureFromStorage(NPC_THEKAL); + Creature* pZath = m_pInstance->GetSingleCreatureFromStorage(NPC_ZATH); + + switch (urand(0, 1)) + { + case 0: + 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)) + DoCastSpellIfCan(pZath, SPELL_GREATER_HEAL); + break; + } } - } - } - - Check_Timer = 5000; - }else Check_Timer -= diff; - if (m_creature->GetHealthPercent() < 5.0f) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); - m_creature->setFaction(35); - m_creature->AttackStop(); + m_uiGreaterHealTimer = urand(15000, 20000); + } + else + m_uiGreaterHealTimer -= uiDiff; - if (m_pInstance) - m_pInstance->SetData(TYPE_LORKHAN, SPECIAL); + // Disarm_Timer + if (m_uiDisarmTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISARM) == CAST_OK) + m_uiDisarmTimer = urand(15000, 25000); + } + else + m_uiDisarmTimer -= uiDiff; - FakeDeath = true; + break; } DoMeleeAttackIfReady(); } }; -//Zealot Zath -struct MANGOS_DLL_DECL mob_zealot_zathAI : public ScriptedAI +/*###### +## npc_zealot_zath +######*/ + +struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI { - mob_zealot_zathAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_zealot_zathAI(Creature* pCreature) : boss_thekalBaseAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - uint32 SweepingStrikes_Timer; - uint32 SinisterStrike_Timer; - uint32 Gouge_Timer; - uint32 Kick_Timer; - uint32 Blind_Timer; - uint32 Check_Timer; - - bool FakeDeath; - ScriptedInstance* m_pInstance; + uint32 m_uiSweepingStrikesTimer; + uint32 m_uiSinisterStrikeTimer; + uint32 m_uiGougeTimer; + uint32 m_uiKickTimer; + uint32 m_uiBlindTimer; + uint32 m_uiResurrectTimer; + void Reset() { - SweepingStrikes_Timer = 13000; - SinisterStrike_Timer = 8000; - Gouge_Timer = 25000; - Kick_Timer = 18000; - Blind_Timer = 5000; - Check_Timer = 10000; - - FakeDeath = false; + m_uiSweepingStrikesTimer = 13000; + m_uiSinisterStrikeTimer = 8000; + m_uiGougeTimer = 25000; + m_uiKickTimer = 18000; + m_uiBlindTimer = 5000; + m_uiPhase = PHASE_NORMAL; if (m_pInstance) m_pInstance->SetData(TYPE_ZATH, NOT_STARTED); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Revive(true); } - void UpdateAI (const uint32 diff) + void Aggro(Unit* /*pWho*/) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_ZATH, IN_PROGRESS); + } - //SweepingStrikes_Timer - if (SweepingStrikes_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SWEEPINGSTRIKES); - SweepingStrikes_Timer = urand(22000, 26000); - }else SweepingStrikes_Timer -= diff; + void OnFakeingDeath() + { + m_uiResurrectTimer = 10000; - //SinisterStrike_Timer - if (SinisterStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SINISTERSTRIKE); - SinisterStrike_Timer = urand(8000, 16000); - }else SinisterStrike_Timer -= diff; + if (m_pInstance) + m_pInstance->SetData(TYPE_ZATH, SPECIAL); + } - //Gouge_Timer - if (Gouge_Timer < diff) + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GOUGE); + case PHASE_FAKE_DEATH: + if (m_uiResurrectTimer < uiDiff) + { + if (!m_pInstance) + return; - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + if (m_pInstance->GetData(TYPE_THEKAL) != SPECIAL || m_pInstance->GetData(TYPE_LORKHAN) != SPECIAL) + { + DoCastSpellIfCan(m_creature, SPELL_RESURRECT); + m_pInstance->SetData(TYPE_ZATH, IN_PROGRESS); + } - Gouge_Timer = urand(17000, 27000); - }else Gouge_Timer -= diff; + m_uiPhase = PHASE_WAITING; + } + else + m_uiResurrectTimer -= uiDiff; - //Kick_Timer - if (Kick_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KICK); - Kick_Timer = urand(15000, 25000); - }else Kick_Timer -= diff; + // no break needed here + case PHASE_WAITING: + return; - //Blind_Timer - if (Blind_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BLIND); - Blind_Timer = urand(10000, 20000); - }else Blind_Timer -= diff; + case PHASE_NORMAL: + // SweepingStrikes_Timer + if (m_uiSweepingStrikesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SWEEPING_STRIKES) == CAST_OK) + m_uiSweepingStrikesTimer = urand(22000, 26000); + } + else + m_uiSweepingStrikesTimer -= uiDiff; - //Check_Timer for the death of LorKhan and Zath. - if (!FakeDeath && Check_Timer < diff) - { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_LORKHAN) == SPECIAL) + // SinisterStrike_Timer + if (m_uiSinisterStrikeTimer < uiDiff) { - //Resurrect LorKhan - if (Creature* pLorKhan = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_LORKHAN))) - { - pLorKhan->SetStandState(UNIT_STAND_STATE_STAND); - pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pLorKhan->setFaction(14); - pLorKhan->SetHealth(int(pLorKhan->GetMaxHealth()*1.0)); - } + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SINISTER_STRIKE) == CAST_OK) + m_uiSinisterStrikeTimer = urand(8000, 16000); } + else + m_uiSinisterStrikeTimer -= uiDiff; - if (m_pInstance->GetData(TYPE_THEKAL) == SPECIAL) + // Gouge_Timer + if (m_uiGougeTimer < uiDiff) { - //Resurrect Thekal - if (Creature* pThekal = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_THEKAL))) + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE) == CAST_OK) { - pThekal->SetStandState(UNIT_STAND_STATE_STAND); - pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pThekal->setFaction(14); - pThekal->SetHealth(int(pThekal->GetMaxHealth()*1.0)); + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -100); + + m_uiGougeTimer = urand(17000, 27000); } } - } + else + m_uiGougeTimer -= uiDiff; - Check_Timer = 5000; - }else Check_Timer -= diff; - - if (m_creature->GetHealthPercent() <= 5.0f) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); - m_creature->setFaction(35); - m_creature->AttackStop(); + // Kick_Timer + if (m_uiKickTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KICK) == CAST_OK) + m_uiKickTimer = urand(15000, 25000); + } + else + m_uiKickTimer -= uiDiff; - if (m_pInstance) - m_pInstance->SetData(TYPE_ZATH, SPECIAL); + // Blind_Timer + if (m_uiBlindTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLIND) == CAST_OK) + m_uiBlindTimer = urand(10000, 20000); + } + else + m_uiBlindTimer -= uiDiff; - FakeDeath = true; + break; } DoMeleeAttackIfReady(); } }; +bool EffectDummyCreature_thekal_resurrection(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // 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 + return true; + } + + return false; +} + CreatureAI* GetAI_boss_thekal(Creature* pCreature) { return new boss_thekalAI(pCreature); @@ -526,20 +660,23 @@ CreatureAI* GetAI_mob_zealot_zath(Creature* pCreature) void AddSC_boss_thekal() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_thekal"; - newscript->GetAI = &GetAI_boss_thekal; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_zealot_lorkhan"; - newscript->GetAI = &GetAI_mob_zealot_lorkhan; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_zealot_zath"; - newscript->GetAI = &GetAI_mob_zealot_zath; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_thekal"; + pNewScript->GetAI = &GetAI_boss_thekal; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_thekal_resurrection; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_zealot_lorkhan"; + pNewScript->GetAI = &GetAI_mob_zealot_lorkhan; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_thekal_resurrection; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_zealot_zath"; + pNewScript->GetAI = &GetAI_mob_zealot_zath; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_thekal_resurrection; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp b/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp index 875a77f34c..410dc19c6d 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,22 +26,25 @@ 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 @@ -49,67 +52,43 @@ struct MANGOS_DLL_DECL 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() { - 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->IsWithinDistInMap(pTarget, ATTACK_DISTANCE)) - ++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(); } @@ -257,9 +218,10 @@ CreatureAI* GetAI_boss_venoxis(Creature* pCreature) void AddSC_boss_venoxis() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_venoxis"; - newscript->GetAI = &GetAI_boss_venoxis; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_venoxis"; + pNewScript->GetAI = &GetAI_boss_venoxis; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp b/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp deleted file mode 100644 index 38b74e6aa8..0000000000 --- a/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_wushoolay"; - newscript->GetAI = &GetAI_boss_wushoolay; - newscript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp b/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp index c0818ae3f6..362e72f36c 100644 --- a/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp +++ b/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,221 +24,238 @@ EndScriptData */ #include "precompiled.h" #include "zulgurub.h" -struct MANGOS_DLL_DECL instance_zulgurub : public ScriptedInstance +instance_zulgurub::instance_zulgurub(Map* pMap) : ScriptedInstance(pMap), + m_bHasIntroYelled(false), + m_bHasAltarYelled(false) { - instance_zulgurub(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - std::string strInstData; - // If all High Priest bosses were killed. Lorkhan, Zath and Ohgan are added too. - uint32 m_auiEncounter[MAX_ENCOUNTER]; + Initialize(); +} - // Storing Lorkhan, Zath and Thekal because we need to cast on them later. Jindo is needed for heal function too. - uint64 m_uiLorKhanGUID; - uint64 m_uiZathGUID; - uint64 m_uiThekalGUID; - uint64 m_uiJindoGUID; - uint64 m_uiHakkarGUID; +void instance_zulgurub::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_zulgurub::DoYellAtTriggerIfCan(uint32 uiTriggerId) +{ + if (uiTriggerId == AREATRIGGER_ENTER && !m_bHasIntroYelled) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiLorKhanGUID = 0; - m_uiZathGUID = 0; - m_uiThekalGUID = 0; - m_uiJindoGUID = 0; - m_uiHakkarGUID = 0; + DoOrSimulateScriptTextForThisInstance(SAY_HAKKAR_PROTECT, NPC_HAKKAR); + m_bHasIntroYelled = true; + } + else if (uiTriggerId == AREATRIGGER_ALTAR && !m_bHasAltarYelled) + { + DoOrSimulateScriptTextForThisInstance(SAY_MINION_DESTROY, NPC_HAKKAR); + m_bHasAltarYelled = true; } +} - // each time High Priest dies lower Hakkar's HP - void LowerHakkarHitPoints() +void instance_zulgurub::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - if (Creature* pHakkar = instance->GetCreature(m_uiHakkarGUID)) - { - if (pHakkar->isAlive()) - { - pHakkar->SetMaxHealth(pHakkar->GetMaxHealth() - 60000); - pHakkar->SetHealth(pHakkar->GetHealth() - 60000); - } - } + 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: + if (pCreature->GetPositionY() < -1626) + m_lLeftPantherTriggerGUIDList.push_back(pCreature->GetObjectGuid()); + else + m_lRightPantherTriggerGUIDList.push_back(pCreature->GetObjectGuid()); + break; } +} - bool IsEncounterInProgress() const +void instance_zulgurub::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - //not active in Zul'Gurub - return false; + case GO_GONG_OF_BETHEKK: + case GO_FORCEFIELD: + break; + case GO_SPIDER_EGG: + m_lSpiderEggGUIDList.push_back(pGo->GetObjectGuid()); + return; } - void OnCreatureCreate(Creature* pCreature) + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_zulgurub::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(pCreature->GetEntry()) - { - case NPC_LORKHAN: - m_uiLorKhanGUID = pCreature->GetGUID(); - break; - case NPC_ZATH: - m_uiZathGUID = pCreature->GetGUID(); - break; - case NPC_THEKAL: - m_uiThekalGUID = pCreature->GetGUID(); - break; - case NPC_JINDO: - m_uiJindoGUID = pCreature->GetGUID(); - break; - case NPC_HAKKAR: - m_uiHakkarGUID = pCreature->GetGUID(); - for(uint8 i = 0; i < 5; ++i) + case TYPE_JEKLIK: + case TYPE_VENOXIS: + 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 (m_auiEncounter[i] == DONE) - LowerHakkarHitPoints(); + if (GameObject* pEgg = instance->GetGameObject(*itr)) + { + // Note: this type of Gameobject needs to be respawned manually + pEgg->SetRespawnTime(2 * DAY); + pEgg->Respawn(); + } } - break; - } + } + break; + case TYPE_ARLOKK: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_FORCEFIELD); + if (uiData == DONE) + DoLowerHakkarHitPoints(); + 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; + break; } - void SetData(uint32 uiType, uint32 uiData) + if (uiData == DONE) { - switch(uiType) - { - case TYPE_ARLOKK: - m_auiEncounter[0] = uiData; - if (uiData == DONE) - LowerHakkarHitPoints(); - break; - case TYPE_JEKLIK: - m_auiEncounter[1] = uiData; - if (uiData == DONE) - LowerHakkarHitPoints(); - break; - case TYPE_VENOXIS: - m_auiEncounter[2] = uiData; - if (uiData == DONE) - LowerHakkarHitPoints(); - break; - case TYPE_MARLI: - m_auiEncounter[3] = uiData; - if (uiData == DONE) - LowerHakkarHitPoints(); - break; - case TYPE_THEKAL: - m_auiEncounter[4] = uiData; - if (uiData == DONE) - LowerHakkarHitPoints(); - break; - case TYPE_LORKHAN: - m_auiEncounter[5] = uiData; - break; - case TYPE_ZATH: - m_auiEncounter[6] = uiData; - break; - case TYPE_OHGAN: - m_auiEncounter[7] = uiData; - break; - case TYPE_HAKKAR: - m_auiEncounter[8] = uiData; - break; - } + OUT_SAVE_INST_DATA; - 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]; - 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_strInstData = saveStream.str(); - strInstData = saveStream.str(); + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; +// Each time High Priest dies lower Hakkar's HP +void instance_zulgurub::DoLowerHakkarHitPoints() +{ + if (Creature* pHakkar = GetSingleCreatureFromStorage(NPC_HAKKAR)) + { + if (pHakkar->isAlive() && pHakkar->GetMaxHealth() > HP_LOSS_PER_PRIEST) + { + pHakkar->SetMaxHealth(pHakkar->GetMaxHealth() - HP_LOSS_PER_PRIEST); + pHakkar->SetHealth(pHakkar->GetHealth() - HP_LOSS_PER_PRIEST); } } +} - const char* Save() +void instance_zulgurub::Load(const char* chrIn) +{ + if (!chrIn) { - return strInstData.c_str(); + OUT_LOAD_INST_DATA_FAIL; + return; } - void 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] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } - OUT_LOAD_INST_DATA(chrIn); + OUT_LOAD_INST_DATA_COMPLETE; +} - 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]; +uint32 instance_zulgurub::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + return 0; +} - OUT_LOAD_INST_DATA_COMPLETE; - } +Creature* instance_zulgurub::SelectRandomPantherTrigger(bool bIsLeft) +{ + GuidList* plTempList = bIsLeft ? &m_lLeftPantherTriggerGUIDList : &m_lRightPantherTriggerGUIDList; + std::vector vTriggers; + vTriggers.reserve(plTempList->size()); - uint32 GetData(uint32 uiType) + for (GuidList::const_iterator itr = plTempList->begin(); itr != plTempList->end(); ++itr) { - switch(uiType) - { - case TYPE_ARLOKK: - return m_auiEncounter[0]; - case TYPE_JEKLIK: - return m_auiEncounter[1]; - case TYPE_VENOXIS: - return m_auiEncounter[2]; - case TYPE_MARLI: - return m_auiEncounter[3]; - case TYPE_THEKAL: - return m_auiEncounter[4]; - case TYPE_LORKHAN: - return m_auiEncounter[5]; - case TYPE_ZATH: - return m_auiEncounter[6]; - case TYPE_OHGAN: - return m_auiEncounter[7]; - case TYPE_HAKKAR: - return m_auiEncounter[8]; - } - return 0; + if (Creature* pTemp = instance->GetCreature(*itr)) + vTriggers.push_back(pTemp); } - uint64 GetData64(uint32 uiData) - { - switch(uiData) - { - case DATA_LORKHAN: - return m_uiLorKhanGUID; - case DATA_ZATH: - return m_uiZathGUID; - case DATA_THEKAL: - return m_uiThekalGUID; - case DATA_JINDO: - return m_uiJindoGUID; - case DATA_HAKKAR: - return m_uiHakkarGUID; - } - return 0; - } -}; + if (vTriggers.empty()) + return NULL; + + return vTriggers[urand(0, vTriggers.size() - 1)]; +} InstanceData* GetInstanceData_instance_zulgurub(Map* pMap) { return new instance_zulgurub(pMap); } +bool AreaTrigger_at_zulgurub(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_ENTER || pAt->id == AREATRIGGER_ALTAR) + { + if (pPlayer->isGameMaster() || pPlayer->isDead()) + return false; + + if (instance_zulgurub* pInstance = (instance_zulgurub*)pPlayer->GetInstanceData()) + pInstance->DoYellAtTriggerIfCan(pAt->id); + } + + return false; +} + void AddSC_instance_zulgurub() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_zulgurub"; - newscript->GetInstanceData = &GetInstanceData_instance_zulgurub; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_zulgurub"; + pNewScript->GetInstanceData = &GetInstanceData_instance_zulgurub; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_zulgurub"; + pNewScript->pAreaTrigger = &AreaTrigger_at_zulgurub; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/zulgurub.h b/scripts/eastern_kingdoms/zulgurub/zulgurub.h index bab1e24b30..0442f11425 100644 --- a/scripts/eastern_kingdoms/zulgurub/zulgurub.h +++ b/scripts/eastern_kingdoms/zulgurub/zulgurub.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,29 +7,76 @@ enum { - MAX_ENCOUNTER = 9, + MAX_ENCOUNTER = 8, + MAX_PRIESTS = 5, + + TYPE_JEKLIK = 0, + TYPE_VENOXIS = 1, + TYPE_MARLI = 2, + TYPE_THEKAL = 3, + TYPE_ARLOKK = 4, + TYPE_OHGAN = 5, // Do not change, used by Acid + TYPE_LORKHAN = 6, + TYPE_ZATH = 7, NPC_LORKHAN = 11347, NPC_ZATH = 11348, NPC_THEKAL = 14509, NPC_JINDO = 11380, NPC_HAKKAR = 14834, + NPC_PANTHER_TRIGGER = 15091, + NPC_BLOODLORD_MANDOKIR = 11382, + NPC_MARLI = 14510, - TYPE_ARLOKK = 1, - TYPE_JEKLIK = 2, - TYPE_VENOXIS = 3, - TYPE_MARLI = 4, - TYPE_OHGAN = 5, - TYPE_THEKAL = 6, - TYPE_ZATH = 7, - TYPE_LORKHAN = 8, - TYPE_HAKKAR = 9, - - DATA_JINDO = 10, - DATA_LORKHAN = 11, - DATA_THEKAL = 12, - DATA_ZATH = 13, - DATA_HAKKAR = 14 + GO_SPIDER_EGG = 179985, + GO_GONG_OF_BETHEKK = 180526, + GO_FORCEFIELD = 180497, + + SAY_MINION_DESTROY = -1309022, + SAY_HAKKAR_PROTECT = -1309023, + + HP_LOSS_PER_PRIEST = 60000, + + AREATRIGGER_ENTER = 3958, + AREATRIGGER_ALTAR = 3960, +}; + +static const float aMandokirDownstairsPos[3] = { -12196.30f, -1948.37f, 130.31f}; + +class MANGOS_DLL_DECL instance_zulgurub : public ScriptedInstance +{ + public: + instance_zulgurub(Map* pMap); + ~instance_zulgurub() {} + + void Initialize() override; + // IsEncounterInProgress() const override { return false; } // not active in Zul'Gurub + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) 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 DoYellAtTriggerIfCan(uint32 uiTriggerId); + + Creature* SelectRandomPantherTrigger(bool bIsLeft); + + protected: + void DoLowerHakkarHitPoints(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + GuidList m_lRightPantherTriggerGUIDList; + GuidList m_lLeftPantherTriggerGUIDList; + GuidList m_lSpiderEggGUIDList; + + bool m_bHasIntroYelled; + bool m_bHasAltarYelled; }; #endif diff --git a/scripts/examples/example_creature.cpp b/scripts/examples/example_creature.cpp index 76ea943a12..e50964320c 100644 --- a/scripts/examples/example_creature.cpp +++ b/scripts/examples/example_creature.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -37,9 +37,8 @@ EndScriptData */ enum { - //List of text id's. The text is stored in database, also in a localized version - //(if translation not exist for the textId, default english text will be used) - //Not required to define in this way, but simplify if changes are needed. + // List of text id's. The text is stored in database, also in a localized version + // (if translation not exist for the textId, default english text will be used) SAY_AGGRO = -1999900, SAY_RANDOM_0 = -1999901, SAY_RANDOM_1 = -1999902, @@ -51,7 +50,7 @@ enum SAY_DANCE = -1999908, SAY_SALUTE = -1999909, - //List of spells. Not required to define them in this way, but will make it easier to maintain in case spellId change + // List of used spells SPELL_BUFF = 25661, SPELL_ONE = 12555, SPELL_ONE_ALT = 24099, @@ -60,57 +59,62 @@ enum SPELL_ENRAGE = 23537, SPELL_BESERK = 32309, + // Some other information we need to store + TEXT_ID_GREET = 907, FACTION_WORGEN = 24 }; -//List of gossip item texts. Items will appear in the gossip window. +// List of gossip item texts. Items will appear in the gossip window. +// Actually such gossip can already be handled in normal World-Database +// 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 { - //*** HANDLED FUNCTION *** - //This is the constructor, called only once when the creature is first created - example_creatureAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - //*** CUSTOM VARIABLES **** - //These variables are for use only by this individual script. - //Nothing else will ever call them but us. - - uint32 m_uiSay_Timer; //Timer for random chat - uint32 m_uiRebuff_Timer; //Timer for rebuffing - uint32 m_uiSpell_1_Timer; //Timer for spell 1 when in combat - uint32 m_uiSpell_2_Timer; //Timer for spell 1 when in combat - uint32 m_uiSpell_3_Timer; //Timer for spell 1 when in combat - uint32 m_uiBeserk_Timer; //Timer until we go into Beserk (enraged) mode - uint32 m_uiPhase; //The current battle phase we are in - uint32 m_uiPhase_Timer; //Timer until phase transition - - //*** HANDLED FUNCTION *** - //This is called whenever the core decides we need to evade + // *** HANDLED FUNCTION *** + // This is the constructor, called only once when the creature is first created + example_creatureAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + // *** CUSTOM VARIABLES **** + // These variables are for use only by this individual script. + // Nothing else will ever call them but us. + + uint32 m_uiSayTimer; // Timer for random chat + uint32 m_uiRebuffTimer; // Timer for rebuffing + uint32 m_uiSpellOneTimer; // Timer for spell 1 when in combat + uint32 m_uiSpellTwoTimer; // Timer for spell 1 when in combat + uint32 m_uiSpellThreeTimer; // Timer for spell 1 when in combat + uint32 m_uiBeserkTimer; // Timer until we go into Beserk (enraged) mode + uint32 m_uiPhase; // The current battle phase we are in + uint32 m_uiPhaseTimer; // Timer until phase transition + + // *** HANDLED FUNCTION *** + // This is called whenever the core decides we need to evade void Reset() { - m_uiPhase = 1; //Start in phase 1 - m_uiPhase_Timer = 60000; //60 seconds - m_uiSpell_1_Timer = 5000; //5 seconds - m_uiSpell_2_Timer = 37000; //37 seconds - m_uiSpell_3_Timer = 19000; //19 seconds - m_uiBeserk_Timer = 120000; //2 minutes + m_uiPhase = 1; // Start in phase 1 + m_uiPhaseTimer = 60000; // 60 seconds + m_uiSpellOneTimer = 5000; // 5 seconds + m_uiSpellTwoTimer = 37000; // 37 seconds + m_uiSpellThreeTimer = 19000; // 19 seconds + m_uiBeserkTimer = 120000; // 2 minutes } - //*** HANDLED FUNCTION *** - //Attack Start is called whenever someone hits us. - void Aggro(Unit* pWho) + // *** HANDLED FUNCTION *** + // Aggro is called when we enter combat, against an enemy, and haven't been in combat before + void Aggro(Unit* pWho) override { - //Say some stuff + // Say some stuff DoScriptText(SAY_AGGRO, m_creature, pWho); } - //Our Recive emote function - void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) + // *** HANDLED FUNCTION *** + // Our Recive emote function + void ReceiveEmote(Player* /*pPlayer*/, uint32 uiTextEmote) override { m_creature->HandleEmote(uiTextEmote); - switch(uiTextEmote) + switch (uiTextEmote) { case TEXTEMOTE_DANCE: DoScriptText(SAY_DANCE, m_creature); @@ -121,18 +125,18 @@ 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) + // *** 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) override { - //Out of combat timers + // Out of combat timers if (!m_creature->getVictim()) { - //Random Say timer - if (m_uiSay_Timer < uiDiff) + // Random Say timer + if (m_uiSayTimer < uiDiff) { - //Random switch between 5 outcomes - switch(urand(0, 4)) + // Random switch between 5 outcomes + switch (urand(0, 4)) { case 0: DoScriptText(SAY_RANDOM_0, m_creature); break; case 1: DoScriptText(SAY_RANDOM_1, m_creature); break; @@ -141,132 +145,147 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI case 4: DoScriptText(SAY_RANDOM_4, m_creature); break; } - m_uiSay_Timer = 45000; //Say something agian in 45 seconds + m_uiSayTimer = 45 * IN_MILLISECONDS; // Say something agian in 45 seconds } else - m_uiSay_Timer -= uiDiff; + m_uiSayTimer -= uiDiff; - //Rebuff timer - if (m_uiRebuff_Timer < uiDiff) + // Rebuff timer + if (m_uiRebuffTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_BUFF); - m_uiRebuff_Timer = 900000; //Rebuff agian in 15 minutes + // Rebuff agian in 15 minutes + m_uiRebuffTimer = 15 * MINUTE * IN_MILLISECONDS; } else - m_uiRebuff_Timer -= uiDiff; + m_uiRebuffTimer -= uiDiff; } - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Spell 1 timer - if (m_uiSpell_1_Timer < uiDiff) + // Abilities of all phases + // Spell One timer + if (m_uiSpellOneTimer < uiDiff) { - //Cast spell one on our current target. - if (rand()%50 > 10) + // Cast spell one on our current target. + 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); - m_uiSpell_1_Timer = 5000; + m_uiSpellOneTimer = 5000; } else - m_uiSpell_1_Timer -= uiDiff; + m_uiSpellOneTimer -= uiDiff; - //Spell 2 timer - if (m_uiSpell_2_Timer < uiDiff) + // Spell Two timer + if (m_uiSpellTwoTimer < uiDiff) { - //Cast spell one on our current target. - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWO); - m_uiSpell_2_Timer = 37000; + // 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 } else - m_uiSpell_2_Timer -= uiDiff; + m_uiSpellTwoTimer -= uiDiff; - //Beserk timer - if (m_uiPhase > 1) + // End of abliities of all phases + + // Phase 1 abilities + if (m_uiPhase == 1) { - //Spell 3 timer - if (m_uiSpell_3_Timer < uiDiff) + // Phase timer + if (m_uiPhaseTimer < uiDiff) { - //Cast spell one on our current target. - DoCastSpellIfCan(m_creature->getVictim(), SPELL_THREE); - - m_uiSpell_3_Timer = 19000; + // Only switch phase and display phase-switich text, if out cast was started sucessfull + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + // Go to next phase + ++m_uiPhase; + DoScriptText(SAY_PHASE, m_creature); + } } else - m_uiSpell_3_Timer -= uiDiff; - - if (m_uiBeserk_Timer < uiDiff) + m_uiPhaseTimer -= uiDiff; + } + // Phase 2 abilities + else if (m_uiPhase > 1) + { + // Spell Three timer + if (m_uiSpellThreeTimer < uiDiff) { - //Say our line then cast uber death spell - DoScriptText(SAY_BESERK, m_creature, m_creature->getVictim()); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BESERK); - - //Cast our beserk spell agian in 12 seconds if we didn't kill everyone - m_uiBeserk_Timer = 12000; + // Cast spell three on self (AoE spell with only self-target) + if (DoCastSpellIfCan(m_creature, SPELL_THREE) == CAST_OK) + m_uiSpellThreeTimer = 19000; } else - m_uiBeserk_Timer -= uiDiff; - } - else if (m_uiPhase == 1) //Phase timer - { - if (m_uiPhase_Timer < uiDiff) + m_uiSpellThreeTimer -= uiDiff; + + // Beserk timer + if (m_uiBeserkTimer < uiDiff) { - //Go to next phase - ++m_uiPhase; - DoScriptText(SAY_PHASE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); + // Cast uber death spell if possible + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BESERK) == CAST_OK) + { + // Say our line if we cast + DoScriptText(SAY_BESERK, m_creature, m_creature->getVictim()); + + // Cast our beserk spell agian in 12 seconds (if we didn't kill everyone) + m_uiBeserkTimer = 12000; + } } else - m_uiPhase_Timer -= uiDiff; + m_uiBeserkTimer -= uiDiff; } + // Normal behaviour: if possible mobs do attack with melee DoMeleeAttackIfReady(); } }; -//This is the GetAI method used by all scripts that involve AI -//It is called every time a new creature using this script is created +// This is the GetAI method used by all scripts that involve AI +// It is called every time a new creature using this script is created CreatureAI* GetAI_example_creature(Creature* pCreature) { return new example_creatureAI(pCreature); } -//This function is called when the player clicks an option on the gossip menu -bool GossipSelect_example_creature(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +// This function is called when the player opens the gossip menu +// In this case as there is nothing special about this gossip dialogue, it should be moved to world-DB +bool GossipHello_example_creature(Player* pPlayer, Creature* pCreature) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - //Set our faction to hostile twoards all - pCreature->setFaction(FACTION_WORGEN); - pCreature->AI()->AttackStart(pPlayer); - } + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_GREET, pCreature->GetObjectGuid()); return true; } -//This function is called when the player opens the gossip menu -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) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(907, pCreature->GetGUID()); + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + // Set our faction to hostile towards all + pCreature->SetFactionTemporary(FACTION_WORGEN, TEMPFACTION_RESTORE_RESPAWN); + pCreature->AI()->AttackStart(pPlayer); + } return true; } -//This is the actual function called only once durring InitScripts() -//It must define all handled functions that are to be run in this script +// This is the actual function called only once durring InitScripts() +// It must define all handled functions that are to be run in this script void AddSC_example_creature() { - Script* newscript; - - newscript = new Script; - newscript->Name = "example_creature"; - newscript->GetAI = &GetAI_example_creature; - newscript->pGossipHello = &GossipHello_example_creature; - newscript->pGossipSelect = &GossipSelect_example_creature; - newscript->RegisterSelf(false); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "example_creature"; + pNewScript->GetAI = &GetAI_example_creature; + pNewScript->pGossipHello = &GossipHello_example_creature; + pNewScript->pGossipSelect = &GossipSelect_example_creature; + pNewScript->RegisterSelf(false); } diff --git a/scripts/examples/example_escort.cpp b/scripts/examples/example_escort.cpp index 58b23cb4de..9d28d38041 100644 --- a/scripts/examples/example_escort.cpp +++ b/scripts/examples/example_escort.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -53,18 +53,25 @@ enum struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI { // CreatureAI functions - example_escortAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} + example_escortAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } uint32 m_uiDeathCoilTimer; uint32 m_uiChatTimer; - void JustSummoned(Creature* pSummoned) + // Is called after each combat, so usally only reset combat-stuff here + void Reset() + { + m_uiDeathCoilTimer = 4000; + m_uiChatTimer = 4000; + } + + 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) { @@ -73,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)) { @@ -98,13 +105,8 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI DoScriptText(SAY_AGGRO2, m_creature); } - void Reset() - { - m_uiDeathCoilTimer = 4000; - m_uiChatTimer = 4000; - } - - void JustDied(Unit* pKiller) + // Only overwrite if there is something special + void JustDied(Unit* pKiller) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -113,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 @@ -122,15 +124,15 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI } else DoScriptText(SAY_DEATH_3, m_creature); + + // Fail quest for group - if you don't implement JustDied in your script, this will automatically work + npc_escortAI::JustDied(pKiller); } - void UpdateAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { - //Must update npc_escortAI - npc_escortAI::UpdateAI(uiDiff); - - //Combat check - if (m_creature->getVictim()) + // Combat check + if (m_creature->SelectHostileTarget() && m_creature->getVictim()) { if (m_uiDeathCoilTimer < uiDiff) { @@ -140,10 +142,12 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI } else m_uiDeathCoilTimer -= uiDiff; + + DoMeleeAttackIfReady(); } else { - //Out of combat but being escorted + // Out of combat but being escorted if (HasEscortState(STATE_ESCORT_ESCORTING)) { if (m_uiChatTimer < uiDiff) @@ -175,41 +179,41 @@ CreatureAI* GetAI_example_escort(Creature* pCreature) bool GossipHello_example_escort(Player* pPlayer, Creature* pCreature) { - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); - pPlayer->PrepareGossipMenu(pCreature, 0); + 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(); if (pEscortAI) - pEscortAI->Start(true, pPlayer->GetGUID()); + pEscortAI->Start(true, pPlayer); break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->CLOSE_GOSSIP_MENU(); if (pEscortAI) - pEscortAI->Start(false, pPlayer->GetGUID()); + pEscortAI->Start(false, pPlayer); break; case GOSSIP_ACTION_INFO_DEF+3: pPlayer->CLOSE_GOSSIP_MENU(); if (pEscortAI) - pEscortAI->Start(true, pPlayer->GetGUID()); + pEscortAI->Start(true, pPlayer); break; default: return false; // nothing defined -> mangos core handling @@ -220,11 +224,12 @@ bool GossipSelect_example_escort(Player* pPlayer, Creature* pCreature, uint32 ui void AddSC_example_escort() { - Script *newscript; - newscript = new Script; - newscript->Name = "example_escort"; - newscript->GetAI = &GetAI_example_escort; - newscript->pGossipHello = &GossipHello_example_escort; - newscript->pGossipSelect = &GossipSelect_example_escort; - newscript->RegisterSelf(false); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "example_escort"; + pNewScript->GetAI = &GetAI_example_escort; + pNewScript->pGossipHello = &GossipHello_example_escort; + pNewScript->pGossipSelect = &GossipSelect_example_escort; + pNewScript->RegisterSelf(false); } diff --git a/scripts/examples/example_gossip_codebox.cpp b/scripts/examples/example_gossip_codebox.cpp index 1c2cd76546..4e7f2c7a33 100644 --- a/scripts/examples/example_gossip_codebox.cpp +++ b/scripts/examples/example_gossip_codebox.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -34,24 +34,25 @@ enum SAY_CORRECT = -1999924 }; +// Should actually be handled in SD2-database! #define GOSSIP_ITEM_1 "A quiz: what's your name?" #define GOSSIP_ITEM_2 "I'm not interested" -//This function is called when the player opens the gossip menubool +// 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->GetGUID()); + pPlayer->PlayerTalkClass->SendGossipMenu(907, pCreature->GetObjectGuid()); return true; } -//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) +// 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) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 2) { DoScriptText(SAY_NOT_INTERESTED, pCreature); pPlayer->CLOSE_GOSSIP_MENU(); @@ -66,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; } } @@ -88,12 +89,12 @@ bool GossipSelectWithCode_example_gossip_codebox(Player* pPlayer, Creature* pCre void AddSC_example_gossip_codebox() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "example_gossip_codebox"; - newscript->pGossipHello = &GossipHello_example_gossip_codebox; - newscript->pGossipSelect = &GossipSelect_example_gossip_codebox; - newscript->pGossipSelectWithCode = &GossipSelectWithCode_example_gossip_codebox; - newscript->RegisterSelf(false); + pNewScript = new Script; + pNewScript->Name = "example_gossip_codebox"; + pNewScript->pGossipHello = &GossipHello_example_gossip_codebox; + pNewScript->pGossipSelect = &GossipSelect_example_gossip_codebox; + pNewScript->pGossipSelectWithCode = &GossipSelectWithCode_example_gossip_codebox; + pNewScript->RegisterSelf(false); } diff --git a/scripts/examples/example_misc.cpp b/scripts/examples/example_misc.cpp index df21131638..a0af083acd 100644 --- a/scripts/examples/example_misc.cpp +++ b/scripts/examples/example_misc.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -28,20 +28,20 @@ enum SAY_HI = -1999925 }; -bool AT_example_areatrigger(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 GOHello_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; @@ -49,20 +49,20 @@ bool GOHello_example_go_teleporter(Player* pPlayer, GameObject* pGo) void AddSC_example_misc() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "example_areatrigger"; - newscript->pAreaTrigger = &AT_example_areatrigger; - newscript->RegisterSelf(false); + pNewScript = new Script; + pNewScript->Name = "at_example"; + pNewScript->pAreaTrigger = &AreaTrigger_at_example; + pNewScript->RegisterSelf(false); - newscript = new Script; - newscript->Name = "example_item"; - newscript->pItemUse = &ItemUse_example_item; - newscript->RegisterSelf(false); + pNewScript = new Script; + pNewScript->Name = "example_item"; + pNewScript->pItemUse = &ItemUse_example_item; + pNewScript->RegisterSelf(false); - newscript = new Script; - newscript->Name = "example_go_teleporter"; - newscript->pGOHello = &GOHello_example_go_teleporter; - newscript->RegisterSelf(false); + pNewScript = new Script; + pNewScript->Name = "example_go_teleporter"; + pNewScript->pGOUse = &GOUse_example_go_teleporter; + pNewScript->RegisterSelf(false); } diff --git a/scripts/kalimdor/ashenvale.cpp b/scripts/kalimdor/ashenvale.cpp index 925b92cb8b..44711cf8a5 100644 --- a/scripts/kalimdor/ashenvale.cpp +++ b/scripts/kalimdor/ashenvale.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Ashenvale SD%Complete: 70 -SDComment: Quest support: 6482, 6544, 6641 +SDComment: Quest support: 976, 6482, 6544, 6641 SDCategory: Ashenvale Forest EndScriptData */ @@ -25,6 +25,7 @@ EndScriptData */ npc_muglash npc_ruul_snowhoof npc_torek +npc_feero_ironhand EndContentData */ #include "precompiled.h" @@ -63,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 @@ -104,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)) { @@ -116,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()) @@ -128,10 +129,10 @@ 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? - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + // some kind of event flag? Update to player/group only? + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); SetEscortPaused(true); } break; @@ -152,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); @@ -174,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()) { @@ -209,9 +210,9 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } } @@ -223,9 +224,9 @@ CreatureAI* GetAI_npc_muglash(Creature* pCreature) return new npc_muglashAI(pCreature); } -bool GOHello_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())) { @@ -257,9 +258,9 @@ struct MANGOS_DLL_DECL npc_ruul_snowhoofAI : public npc_escortAI void Reset() {} - 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); @@ -278,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); } @@ -288,11 +289,11 @@ 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())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -338,14 +339,14 @@ struct MANGOS_DLL_DECL npc_torekAI : public npc_escortAI 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); @@ -354,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); @@ -369,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; @@ -403,11 +404,11 @@ 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())) - pEscortAI->Start(true, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(true, pPlayer, pQuest); } return true; @@ -418,30 +419,213 @@ CreatureAI* GetAI_npc_torek(Creature* pCreature) return new npc_torekAI(pCreature); } +/*#### +# npc_feero_ironhand +####*/ + +enum +{ + SAY_QUEST_START = -1000771, + SAY_FIRST_AMBUSH_START = -1000772, + SAY_FIRST_AMBUSH_END = -1000773, + SAY_SECOND_AMBUSH_START = -1000774, + SAY_SCOUT_SECOND_AMBUSH = -1000775, + SAY_SECOND_AMBUSH_END = -1000776, + SAY_FINAL_AMBUSH_START = -1000777, + SAY_BALIZAR_FINAL_AMBUSH = -1000778, + SAY_FINAL_AMBUSH_ATTACK = -1000779, + SAY_QUEST_END = -1000780, + + QUEST_SUPPLIES_TO_AUBERDINE = 976, + + NPC_DARK_STRAND_ASSASSIN = 3879, + NPC_FORSAKEN_SCOUT = 3893, + + NPC_ALIGAR_THE_TORMENTOR = 3898, + NPC_BALIZAR_THE_UMBRAGE = 3899, + NPC_CAEDAKAR_THE_VICIOUS = 3900, +}; + +/* + * Notes about the event: + * The summon coords and event sequence are guesswork based on the comments from wowhead and wowwiki + */ + +// Distance, Angle or Offset +static const float aSummonPositions[2][2] = +{ + {30.0f, 1.25f}, + {30.0f, 0.95f} +}; + +// Hardcoded positions for the last 3 mobs +static const float aEliteSummonPositions[3][4] = +{ + {4243.12f, 108.22f, 38.12f, 3.62f}, + {4240.95f, 114.04f, 38.35f, 3.56f}, + {4235.78f, 118.09f, 38.08f, 4.12f} +}; + +struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI +{ + npc_feero_ironhandAI(Creature* pCreature) : npc_escortAI(pCreature) + { + Reset(); + } + + uint8 m_uiCreaturesCount; + bool m_bIsAttacked; + + void Reset() + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiCreaturesCount = 0; + m_bIsAttacked = false; + } + } + + void WaypointReached(uint32 uiPointId) override + { + 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); + 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); + 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_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 + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_SUPPLIES_TO_AUBERDINE, m_creature); + break; + } + } + + void AttackedBy(Unit* pWho) override + { + // Yell only at the first attack + if (!m_bIsAttacked) + { + if (((Creature*)pWho)->GetEntry() == NPC_BALIZAR_THE_UMBRAGE) + { + DoScriptText(SAY_FINAL_AMBUSH_ATTACK, m_creature); + m_bIsAttacked = true; + } + } + } + + // Summon mobs at calculated points + void DoSpawnMob(uint32 uiEntry, float fDistance, float fAngle) + { + 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_OOC_DESPAWN, 20000); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + --m_uiCreaturesCount; + + if (!m_uiCreaturesCount) + { + switch (pSummoned->GetEntry()) + { + case NPC_DARK_STRAND_ASSASSIN: + DoScriptText(SAY_FIRST_AMBUSH_END, m_creature); + break; + case NPC_FORSAKEN_SCOUT: + DoScriptText(SAY_SECOND_AMBUSH_END, m_creature); + break; + case NPC_ALIGAR_THE_TORMENTOR: + case NPC_BALIZAR_THE_UMBRAGE: + case NPC_CAEDAKAR_THE_VICIOUS: + DoScriptText(SAY_QUEST_END, m_creature); + break; + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FORSAKEN_SCOUT) + { + // Only one of the scouts yells + if (m_uiCreaturesCount == 1) + DoScriptText(SAY_SCOUT_SECOND_AMBUSH, pSummoned, m_creature); + } + else if (pSummoned->GetEntry() == NPC_BALIZAR_THE_UMBRAGE) + DoScriptText(SAY_BALIZAR_FINAL_AMBUSH, pSummoned); + + ++m_uiCreaturesCount; + pSummoned->AI()->AttackStart(m_creature); + } +}; + +CreatureAI* GetAI_npc_feero_ironhand(Creature* pCreature) +{ + return new npc_feero_ironhandAI(pCreature); +} + +bool QuestAccept_npc_feero_ironhand(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_SUPPLIES_TO_AUBERDINE) + { + DoScriptText(SAY_QUEST_START, pCreature, pPlayer); + 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); + } + + return true; +} + void AddSC_ashenvale() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_muglash"; - newscript->GetAI = &GetAI_npc_muglash; - newscript->pQuestAccept = &QuestAccept_npc_muglash; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_naga_brazier"; - newscript->pGOHello = &GOHello_go_naga_brazier; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_ruul_snowhoof"; - newscript->GetAI = &GetAI_npc_ruul_snowhoofAI; - newscript->pQuestAccept = &QuestAccept_npc_ruul_snowhoof; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_torek"; - newscript->GetAI = &GetAI_npc_torek; - newscript->pQuestAccept = &QuestAccept_npc_torek; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_muglash"; + pNewScript->GetAI = &GetAI_npc_muglash; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_muglash; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_naga_brazier"; + pNewScript->pGOUse = &GOUse_go_naga_brazier; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ruul_snowhoof"; + pNewScript->GetAI = &GetAI_npc_ruul_snowhoofAI; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_ruul_snowhoof; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_torek"; + pNewScript->GetAI = &GetAI_npc_torek; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_torek; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_feero_ironhand"; + pNewScript->GetAI = &GetAI_npc_feero_ironhand; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_feero_ironhand; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/azshara.cpp b/scripts/kalimdor/azshara.cpp index 496b20e5f6..d90a80b86c 100644 --- a/scripts/kalimdor/azshara.cpp +++ b/scripts/kalimdor/azshara.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -49,20 +49,20 @@ 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 }; @@ -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 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,0,0,m_creature->GetGUID()); + // 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->GetGUID()); + 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); @@ -209,7 +209,7 @@ struct MANGOS_DLL_DECL 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; @@ -230,10 +230,10 @@ CreatureAI* GetAI_npc_depth_charge(Creature* pCreature) ## go_southfury_moonstone ######*/ -bool GOHello_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); @@ -244,58 +244,156 @@ bool GOHello_go_southfury_moonstone(Player* pPlayer, GameObject* pGo) /*###### ## mobs_spitelashes ######*/ +enum +{ + // quest related + SPELL_POLYMORPH_BACKFIRE = 28406, // summons npc 16479 + QUEST_FRAGMENTED_MAGIC = 9364, + + // npc spells + SPELL_DISARM = 6713, // warrior + SPELL_SCREECH = 3589, // screamer + SPELL_FROST_SHOCK = 12548, // serpent guard + SPELL_RENEW = 11640, // siren + SPELL_SHOOT = 6660, + SPELL_FROST_SHOT = 12551, + SPELL_FROST_NOVA = 11831, + SPELL_STRIKE = 11976, // myrmidon + + NPC_SPITELASH_WARRIOR = 6190, + NPC_SPITELASH_SCREAMER = 6193, + NPC_SPITELASH_GUARD = 6194, + NPC_SPITELASH_SIREN = 6195, + NPC_SPITELASH_MYRMIDON = 6196, + + TARGET_TYPE_RANDOM = 0, + TARGET_TYPE_VICTIM = 1, + TARGET_TYPE_SELF = 2, + TARGET_TYPE_FRIENDLY = 3, +}; + +struct SpitelashAbilityStruct +{ + uint32 m_uiCreatureEntry, m_uiSpellId; + uint8 m_uiTargetType; + uint32 m_uiInitialTimer, m_uiCooldown; +}; + +static SpitelashAbilityStruct m_aSpitelashAbility[8] = +{ + {NPC_SPITELASH_WARRIOR, SPELL_DISARM, TARGET_TYPE_VICTIM, 4000, 10000}, + {NPC_SPITELASH_SCREAMER, SPELL_SCREECH, TARGET_TYPE_SELF, 7000, 15000}, + {NPC_SPITELASH_GUARD, SPELL_FROST_SHOCK, TARGET_TYPE_VICTIM, 7000, 13000}, + {NPC_SPITELASH_SIREN, SPELL_RENEW, TARGET_TYPE_FRIENDLY, 4000, 7000}, + {NPC_SPITELASH_SIREN, SPELL_SHOOT, TARGET_TYPE_RANDOM, 3000, 9000}, + {NPC_SPITELASH_SIREN, SPELL_FROST_SHOT, TARGET_TYPE_RANDOM, 7000, 10000}, + {NPC_SPITELASH_SIREN, SPELL_FROST_NOVA, TARGET_TYPE_SELF, 10000, 15000}, + {NPC_SPITELASH_MYRMIDON, SPELL_STRIKE, TARGET_TYPE_VICTIM, 3000, 7000} +}; struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI { - mobs_spitelashesAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + mobs_spitelashesAI(Creature* pCreature) : ScriptedAI(pCreature) + { + 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; + } + + Reset(); + } + + uint32 m_uiMorphTimer; - uint32 morphtimer; - bool spellhit; + UNORDERED_MAP m_mSpellTimers; void Reset() { - morphtimer = 0; - spellhit = false; + m_uiMorphTimer = 0; + + for (UNORDERED_MAP::iterator itr = m_mSpellTimers.begin(); itr != m_mSpellTimers.end(); ++itr) + itr->second = m_aSpitelashAbility[itr->first].m_uiInitialTimer; + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // If already hit by the polymorph return + if (m_uiMorphTimer) + return; + + // 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)) + m_uiMorphTimer = 5000; } - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) + bool CanUseSpecialAbility(uint32 uiIndex) { - if (!spellhit && - Hitter->GetTypeId() == TYPEID_PLAYER && - ((Player*)Hitter)->GetQuestStatus(9364) == QUEST_STATUS_INCOMPLETE && - (Spellkind->Id==118 || Spellkind->Id== 12824 || Spellkind->Id== 12825 || Spellkind->Id== 12826)) + Unit* pTarget = NULL; + + switch (m_aSpitelashAbility[uiIndex].m_uiTargetType) { - spellhit=true; - DoCastSpellIfCan(m_creature,29124); //become a sheep + 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, m_aSpitelashAbility[uiIndex].m_uiSpellId, SELECT_FLAG_IN_LOS); + break; + case TARGET_TYPE_FRIENDLY: + pTarget = DoSelectLowestHpFriendly(10.0f); + break; } + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, m_aSpitelashAbility[uiIndex].m_uiSpellId) == CAST_OK) + return true; + } + + return false; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - // we mustn't remove the creature in the same round in which we cast the summon spell, otherwise there will be no summons - if (spellhit && morphtimer>=5000) - { - m_creature->ForcedDespawn(); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + + if (m_uiMorphTimer) + { + if (m_uiMorphTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POLYMORPH_BACKFIRE, CAST_TRIGGERED) == CAST_OK) + { + m_uiMorphTimer = 0; + m_creature->ForcedDespawn(); + } + } + else + m_uiMorphTimer -= uiDiff; } - // walk 5 seconds before summoning - if (spellhit && morphtimer<5000) + for (UNORDERED_MAP::iterator itr = m_mSpellTimers.begin(); itr != m_mSpellTimers.end(); ++itr) { - morphtimer+=diff; - if (morphtimer>=5000) + if (itr->second < uiDiff) { - DoCastSpellIfCan(m_creature,28406); //summon copies - DoCastSpellIfCan(m_creature,6924); //visual explosion + if (CanUseSpecialAbility(itr->first)) + { + itr->second = m_aSpitelashAbility[itr->first].m_uiCooldown; + break; + } } + else + itr->second -= uiDiff; } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - //TODO: add abilities for the different creatures DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_mobs_spitelashes(Creature* pCreature) { return new mobs_spitelashesAI(pCreature); @@ -308,22 +406,22 @@ CreatureAI* GetAI_mobs_spitelashes(Creature* pCreature) bool GossipHello_npc_loramus_thalipedes(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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->GetGUID()); + 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(); @@ -332,23 +430,23 @@ bool GossipSelect_npc_loramus_thalipedes(Player* pPlayer, Creature* pCreature, u case GOSSIP_ACTION_INFO_DEF+2: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Please continue", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); - pPlayer->SEND_GOSSIP_MENU(1813, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1813, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+21: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I do not understand", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - pPlayer->SEND_GOSSIP_MENU(1814, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1814, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+22: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Indeed", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 23); - pPlayer->SEND_GOSSIP_MENU(1815, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1815, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+23: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I will do this with or your help, Loramus", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 24); - pPlayer->SEND_GOSSIP_MENU(1816, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1816, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+24: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 25); - pPlayer->SEND_GOSSIP_MENU(1817, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1817, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+25: pPlayer->CLOSE_GOSSIP_MENU(); @@ -360,33 +458,33 @@ bool GossipSelect_npc_loramus_thalipedes(Player* pPlayer, Creature* pCreature, u void AddSC_azshara() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_rizzle_sprysprocket"; - newscript->GetAI = &GetAI_npc_rizzle_sprysprocket; - newscript->pGossipHello = &GossipHello_npc_rizzle_sprysprocket; - newscript->pGossipSelect = &GossipSelect_npc_rizzle_sprysprocket; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_depth_charge"; - newscript->GetAI = &GetAI_npc_depth_charge; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_southfury_moonstone"; - newscript->pGOHello = &GOHello_go_southfury_moonstone; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mobs_spitelashes"; - newscript->GetAI = &GetAI_mobs_spitelashes; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_loramus_thalipedes"; - newscript->pGossipHello = &GossipHello_npc_loramus_thalipedes; - newscript->pGossipSelect = &GossipSelect_npc_loramus_thalipedes; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_rizzle_sprysprocket"; + pNewScript->GetAI = &GetAI_npc_rizzle_sprysprocket; + pNewScript->pGossipHello = &GossipHello_npc_rizzle_sprysprocket; + pNewScript->pGossipSelect = &GossipSelect_npc_rizzle_sprysprocket; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_depth_charge"; + pNewScript->GetAI = &GetAI_npc_depth_charge; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_southfury_moonstone"; + pNewScript->pGOUse = &GOUse_go_southfury_moonstone; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mobs_spitelashes"; + pNewScript->GetAI = &GetAI_mobs_spitelashes; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_loramus_thalipedes"; + pNewScript->pGossipHello = &GossipHello_npc_loramus_thalipedes; + pNewScript->pGossipSelect = &GossipSelect_npc_loramus_thalipedes; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/azuremyst_isle.cpp b/scripts/kalimdor/azuremyst_isle.cpp index 5779d2e087..b379c486c0 100644 --- a/scripts/kalimdor/azuremyst_isle.cpp +++ b/scripts/kalimdor/azuremyst_isle.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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 +18,7 @@ /* ScriptData SDName: Azuremyst_Isle SD%Complete: 75 -SDComment: Quest support: 9283, 9528, 9537, 9554(special flight path, proper model for mount missing). Injured Draenei cosmetic only +SDComment: Quest support: 9283, 9528, 9537, Injured Draenei cosmetic only SDCategory: Azuremyst Isle EndScriptData */ @@ -26,7 +27,6 @@ npc_draenei_survivor npc_engineer_spark_overgrind npc_injured_draenei npc_magwin -npc_susurrus EndContentData */ #include "precompiled.h" @@ -56,7 +56,7 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI { npc_draenei_survivorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint64 m_uiCaster; + ObjectGuid m_casterGuid; uint32 m_uiSayThanksTimer; uint32 m_uiRunAwayTimer; @@ -64,9 +64,9 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI bool m_bCanSayHelp; - void Reset() + void Reset() override { - m_uiCaster = 0; + m_casterGuid.Clear(); m_uiSayThanksTimer = 0; m_uiRunAwayTimer = 0; @@ -82,13 +82,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; @@ -101,22 +101,22 @@ 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->SpellFamilyFlags2 & 0x080000000) + if (pSpell->GetSpellFamilyFlags().test()) { m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); m_creature->SetStandState(UNIT_STAND_STATE_STAND); m_creature->CastSpell(m_creature, SPELL_STUNNED, true); - m_uiCaster = pCaster->GetGUID(); + m_casterGuid = pCaster->GetObjectGuid(); m_uiSayThanksTimer = 5000; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiSayThanksTimer) { @@ -124,12 +124,12 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI { m_creature->RemoveAurasDueToSpell(SPELL_IRRIDATION); - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiCaster)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_casterGuid)) { 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; @@ -137,7 +137,7 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI case 3: DoScriptText(SAY_HEAL4, m_creature, pPlayer); break; } - pPlayer->TalkedToCreature(m_creature->GetEntry(),m_creature->GetGUID()); + pPlayer->TalkedToCreature(m_creature->GetEntry(), m_creature->GetObjectGuid()); } m_creature->GetMotionMaster()->Clear(); @@ -145,7 +145,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; } @@ -164,7 +165,8 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI { m_bCanSayHelp = true; m_uiSayHelpTimer = 20000; - }else m_uiSayHelpTimer -= uiDiff; + } + else m_uiSayHelpTimer -= uiDiff; } }; @@ -196,7 +198,6 @@ struct MANGOS_DLL_DECL 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(); @@ -205,16 +206,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; @@ -223,12 +222,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) { @@ -242,7 +241,7 @@ struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI } else if (m_bIsTreeEvent) { - //nothing here yet + // nothing here yet return; } @@ -270,16 +269,16 @@ bool GossipHello_npc_engineer_spark_overgrind(Player* pPlayer, Creature* pCreatu if (pPlayer->GetQuestStatus(QUEST_GNOMERCY) == QUEST_STATUS_INCOMPLETE) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); 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; @@ -293,28 +292,22 @@ struct MANGOS_DLL_DECL 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); @@ -324,27 +317,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 { - 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); @@ -363,22 +359,22 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -389,76 +385,113 @@ CreatureAI* GetAI_npc_magwinAI(Creature* pCreature) } /*###### -## npc_susurrus +## boss_prophet_velen ######*/ enum { - ITEM_WHORL_OF_AIR = 23843, - SPELL_BUFFETING_WINDS = 32474, - TAXI_PATH_ID = 506 + SPELL_HOLY_BLAST = 59700, + SPELL_HOLY_NOVA = 59701, + SPELL_HOLY_SMITE = 59703, + //SPELL_PRAYER_OF_HEALING = 59698, //on friendly + SPELL_STAFF_STRIKE = 33542, }; -#define GOSSIP_ITEM_READY "I am ready." - -bool GossipHello_npc_susurrus(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL boss_prophet_velenAI : public ScriptedAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->HasItemCount(ITEM_WHORL_OF_AIR,1,true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + boss_prophet_velenAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + uint32 m_uiHolyBlastTimer; + uint32 m_uiHolyNovaTimer; + uint32 m_uiHolySmiteTimer; + uint32 m_uiStaffStrikeTimer; + //uint32 m_uiPrayerOfHealingTimer; - return true; -} + void Reset() + { + m_uiHolyBlastTimer = 7000; + m_uiHolyNovaTimer = 12000; + m_uiHolySmiteTimer = 9000; + m_uiStaffStrikeTimer = 5000; + //m_uiPrayerOfHealingTimer= 10000; + } -bool GossipSelect_npc_susurrus(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) + void UpdateAI(const uint32 uiDiff) override { - //spellId is correct, however it gives flight a somewhat funny effect - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer,SPELL_BUFFETING_WINDS,true); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHolyBlastTimer < uiDiff) + { + Unit* pTarget = (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); + DoCast(pTarget, SPELL_HOLY_BLAST); + m_uiHolyBlastTimer = urand(7000, 11000); + } + else + m_uiHolyBlastTimer -= uiDiff; + + if (m_uiHolyNovaTimer < uiDiff) + { + DoCast(m_creature, SPELL_HOLY_NOVA); + m_uiHolyNovaTimer = urand(12000, 17000); + } + else + m_uiHolyNovaTimer -= uiDiff; + + if (m_uiHolySmiteTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_HOLY_SMITE); + m_uiHolySmiteTimer = urand(8000, 12000); + } + else + m_uiHolySmiteTimer -= uiDiff; + + if (m_uiStaffStrikeTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_STAFF_STRIKE); + m_uiStaffStrikeTimer = urand(5000, 8000); + } + else + m_uiStaffStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); } - return true; -} +}; -/*###### -## -######*/ +CreatureAI* GetAI_boss_prophet_velen(Creature* pCreature) +{ + return new boss_prophet_velenAI(pCreature); +} void AddSC_azuremyst_isle() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_draenei_survivor"; - newscript->GetAI = &GetAI_npc_draenei_survivor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_engineer_spark_overgrind"; - newscript->GetAI = &GetAI_npc_engineer_spark_overgrind; - newscript->pGossipHello = &GossipHello_npc_engineer_spark_overgrind; - newscript->pGossipSelect = &GossipSelect_npc_engineer_spark_overgrind; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_injured_draenei"; - newscript->GetAI = &GetAI_npc_injured_draenei; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_magwin"; - newscript->GetAI = &GetAI_npc_magwinAI; - newscript->pQuestAccept = &QuestAccept_npc_magwin; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_susurrus"; - newscript->pGossipHello = &GossipHello_npc_susurrus; - newscript->pGossipSelect = &GossipSelect_npc_susurrus; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_draenei_survivor"; + pNewScript->GetAI = &GetAI_npc_draenei_survivor; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_engineer_spark_overgrind"; + pNewScript->GetAI = &GetAI_npc_engineer_spark_overgrind; + pNewScript->pGossipHello = &GossipHello_npc_engineer_spark_overgrind; + pNewScript->pGossipSelect = &GossipSelect_npc_engineer_spark_overgrind; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_injured_draenei"; + pNewScript->GetAI = &GetAI_npc_injured_draenei; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_magwin"; + pNewScript->GetAI = &GetAI_npc_magwinAI; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_magwin; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_prophet_velen"; + pNewScript->GetAI = &GetAI_boss_prophet_velen; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h b/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h index 3de750926f..fb6c2ac23d 100644 --- a/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h +++ b/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,23 +7,113 @@ enum { - MAX_ENCOUNTER = 6, + ENCOUNTER_KELRIS = 0, + ENCOUNTER_SHRINE = 1, + MAX_ENCOUNTER = 2, + MAX_FIRES = 4, + MAX_COUNT_POS = 3, + SUMMONS_COUNT = 6, TYPE_KELRIS = 1, TYPE_SHRINE = 2, NPC_KELRIS = 4832, - NPC_SERVANT = 4978, + + // Shrine event + NPC_AKUMAI_SERVANT = 4978, + NPC_AKUMAI_SNAPJAW = 4825, + NPC_BARBED_CRUSTACEAN = 4823, + NPC_MURKSHALLOW_SOFTSHELL = 4977, GO_PORTAL_DOOR = 21117, GO_SHRINE_1 = 21118, GO_SHRINE_2 = 21119, GO_SHRINE_3 = 21120, GO_SHRINE_4 = 21121, +}; + +/* 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 + +* 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 +*/ + +static const LOCATION 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} +}; + +struct PosCount +{ + uint8 m_uiCount, m_uiSummonPosition; +}; + +struct SummonInformation +{ + uint8 m_uiWaveIndex; + uint32 m_uiNpcEntry; + PosCount m_aCountAndPos[MAX_COUNT_POS]; +}; + +// ASSERT m_uiSummonPosition < 6 (see aSpawnLocations) +static const SummonInformation aWaveSummonInformation[] = +{ + {0, NPC_AKUMAI_SNAPJAW, {{1, 0}, {1, 1}, {1, 5}}}, + {1, NPC_AKUMAI_SERVANT, {{1, 1}, {1, 4}, {0, 0}}}, + {2, NPC_BARBED_CRUSTACEAN, {{1, 0}, {1, 2}, {0, 0}}}, + {2, NPC_BARBED_CRUSTACEAN, {{1, 3}, {1, 4}, {0, 0}}}, + {3, NPC_MURKSHALLOW_SOFTSHELL, {{2, 0}, {1, 1}, {2, 2}}}, + {3, NPC_MURKSHALLOW_SOFTSHELL, {{1, 3}, {2, 4}, {2, 5}}} +}; + +class MANGOS_DLL_DECL instance_blackfathom_deeps : public ScriptedInstance +{ + public: + instance_blackfathom_deeps(Map* pMap); + ~instance_blackfathom_deeps() {} + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureDeath(Creature* pCreature) override; + + void Update(uint32 uiDiff) 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; + + protected: + void DoSpawnMobs(uint8 uiWaveIndex); + bool IsWaveEventFinished(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiSpawnMobsTimer[MAX_FIRES]; + uint8 m_uiWaveCounter; - DATA_TWILIGHT_LORD_KELRIS = 10, - DATA_SHRINE_OF_GELIHAST = 11, - DATA_ALTAR_OF_THE_DEEPS = 12 + GuidList m_lWaveMobsGuids[MAX_FIRES]; }; #endif diff --git a/scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp b/scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp index 8ca13025d5..b30009036f 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,202 +29,249 @@ EndScriptData */ Must kill twilight lord for shrine event to be possible */ -struct MANGOS_DLL_DECL instance_blackfathom_deeps : public ScriptedInstance +instance_blackfathom_deeps::instance_blackfathom_deeps(Map* pMap) : ScriptedInstance(pMap), + m_uiWaveCounter(0) { - instance_blackfathom_deeps(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint64 m_uiKelrisGUID; - uint64 m_uiShrineOfGelihastGUID; - uint64 m_uiAltarOfTheDeepsGUID; - uint64 m_uiPortalGUID; - uint32 m_uiSpawnServantTimer; + Initialize(); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; +void instance_blackfathom_deeps::Initialize() +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + m_auiEncounter[i] = 0; - void Initialize() + for (uint8 i = 0; i < MAX_FIRES; ++i) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiKelrisGUID = 0; - m_uiShrineOfGelihastGUID = 0; - m_uiAltarOfTheDeepsGUID = 0; - m_uiPortalGUID = 0; - m_uiSpawnServantTimer = 0; + m_uiSpawnMobsTimer[i] = 0; + m_lWaveMobsGuids[i].clear(); } +} - void OnCreatureCreate(Creature* pCreature) - { - if (pCreature->GetEntry() == NPC_KELRIS) - m_uiKelrisGUID = pCreature->GetGUID(); - } +void instance_blackfathom_deeps::OnCreatureCreate(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_KELRIS) + m_mNpcEntryGuidStore[NPC_KELRIS] = pCreature->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) +void instance_blackfathom_deeps::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pGo->GetEntry()) - { - case GO_PORTAL_DOOR: - if (m_auiEncounter[1] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - - m_uiPortalGUID = pGo->GetGUID(); - break; - case GO_SHRINE_1: - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_SHRINE_2: - if (m_auiEncounter[3] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_SHRINE_3: - if (m_auiEncounter[4] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_SHRINE_4: - if (m_auiEncounter[5] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - - case 103015: m_uiShrineOfGelihastGUID = pGo->GetGUID(); break; - case 103016: m_uiAltarOfTheDeepsGUID = pGo->GetGUID(); break; - - } + case GO_PORTAL_DOOR: + if (m_auiEncounter[1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + + m_mGoEntryGuidStore[GO_PORTAL_DOOR] = pGo->GetObjectGuid(); + break; + case GO_SHRINE_1: + case GO_SHRINE_2: + case GO_SHRINE_3: + case GO_SHRINE_4: + if (m_auiEncounter[1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + default: + break; } +} - bool CanOpenEndDoor() - { - if (m_auiEncounter[0] != DONE) - return false; +void instance_blackfathom_deeps::DoSpawnMobs(uint8 uiWaveIndex) +{ + Creature* pKelris = GetSingleCreatureFromStorage(NPC_KELRIS); + if (!pKelris || !pKelris->IsInWorld() || uiWaveIndex >= MAX_FIRES) + return; - if (m_auiEncounter[2] == DONE && m_auiEncounter[3] == DONE && m_auiEncounter[4] == DONE && m_auiEncounter[5] == DONE) - return true; + float fX_resp, fY_resp, fZ_resp; - return false; - } + pKelris->GetRespawnCoord(fX_resp, fY_resp, fZ_resp); - void SpawnServants() + for (uint8 i = 0; i < SUMMONS_COUNT; ++i) { - if (Creature* pKelris = instance->GetCreature(m_uiKelrisGUID)) - { - float fX_resp, fY_resp, fZ_resp; - pKelris->GetRespawnCoord(fX_resp, fY_resp, fZ_resp); + if (aWaveSummonInformation[i].m_uiWaveIndex != uiWaveIndex) + continue; - for(uint8 i = 0; i < 5 ; ++i) + // Summon mobs at positions + for (uint8 j = 0; j < MAX_COUNT_POS; ++j) + { + for (uint8 k = 0; k < aWaveSummonInformation[i].m_aCountAndPos[j].m_uiCount; ++k) { - // this part gets a random position at circumference point in a circle - // fRadius is how far from center to calculate. - // here we use kelris's close point coords as base and then move the summoned to the location of his respawn coords - float fRadius = 30.0f; - float fAngle = 2.0 * M_PI * rand_norm(); - - float fX, fY, fZ; - - fRadius *= sqrt(rand_norm()); + uint8 uiPos = aWaveSummonInformation[i].m_aCountAndPos[j].m_uiSummonPosition; + float fPosX = aSpawnLocations[uiPos].x; + float fPosY = aSpawnLocations[uiPos].y; + float fPosZ = aSpawnLocations[uiPos].z; + float fPosO = aSpawnLocations[uiPos].o; - pKelris->GetClosePoint(fX, fY, fZ, 0.0f, fRadius, fAngle); + // Adapt fPosY slightly in case of higher summon-counts + if (aWaveSummonInformation[i].m_aCountAndPos[j].m_uiCount > 1) + fPosY = fPosY - INTERACTION_DISTANCE / 2 + k * INTERACTION_DISTANCE / aWaveSummonInformation[i].m_aCountAndPos[j].m_uiCount; - if (Creature* pServant = pKelris->SummonCreature(NPC_SERVANT, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000)) - pServant->GetMotionMaster()->MovePoint(0, fX_resp, fY_resp, fZ_resp); + if (Creature* pSummoned = pKelris->SummonCreature(aWaveSummonInformation[i].m_uiNpcEntry, fPosX, fPosY, fPosZ, fPosO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pSummoned->GetMotionMaster()->MovePoint(0, fX_resp, fY_resp, fZ_resp); + m_lWaveMobsGuids[uiWaveIndex].push_back(pSummoned->GetObjectGuid()); + } } - } } +} - void SetData(uint32 uiType, uint32 uiData) +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) - m_auiEncounter[0] = uiData; - break; - case TYPE_SHRINE: + case TYPE_KELRIS: // EventAI must set instance data (1,3) at his death + if (m_auiEncounter[ENCOUNTER_KELRIS] != DONE && uiData == DONE) + m_auiEncounter[ENCOUNTER_KELRIS] = uiData; + break; + case TYPE_SHRINE: + m_auiEncounter[ENCOUNTER_SHRINE] = uiData; + if (uiData == IN_PROGRESS && m_uiWaveCounter < MAX_FIRES) { - switch(uiData) - { - case GO_SHRINE_1: - m_auiEncounter[2] = DONE; - break; - case GO_SHRINE_2: - m_auiEncounter[3] = DONE; - break; - case GO_SHRINE_3: - m_auiEncounter[4] = DONE; - break; - case GO_SHRINE_4: - m_auiEncounter[5] = DONE; - break; - } + m_uiSpawnMobsTimer[m_uiWaveCounter] = 3000; + ++m_uiWaveCounter; + } + else if (uiData == DONE) + DoUseDoorOrButton(GO_PORTAL_DOOR); + break; + } - m_uiSpawnServantTimer = 7500; + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; - if (CanOpenEndDoor()) - { - m_auiEncounter[1] = DONE; - DoUseDoorOrButton(m_uiPortalGUID); - } + std::ostringstream saveStream; - break; - } - } + saveStream << m_auiEncounter[ENCOUNTER_KELRIS] << " " << m_auiEncounter[ENCOUNTER_SHRINE]; + + m_strInstData = saveStream.str(); + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint32 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_KELRIS: + return m_auiEncounter[ENCOUNTER_KELRIS]; + case TYPE_SHRINE: + return m_auiEncounter[ENCOUNTER_SHRINE]; + default: + return 0; + } +} - return 0; +void instance_blackfathom_deeps::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; } - uint64 GetData64(uint32 uiData) + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[ENCOUNTER_KELRIS] >> m_auiEncounter[ENCOUNTER_SHRINE]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - switch(uiData) - { - case DATA_TWILIGHT_LORD_KELRIS: - return m_uiKelrisGUID; - case DATA_SHRINE_OF_GELIHAST: - return m_uiShrineOfGelihastGUID; - } + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_blackfathom_deeps::OnCreatureDeath(Creature* pCreature) +{ + // Only use this function if shrine event is in progress + if (m_auiEncounter[ENCOUNTER_SHRINE] != IN_PROGRESS) + return; - return 0; + switch (pCreature->GetEntry()) + { + case NPC_AKUMAI_SERVANT: + if (!m_lWaveMobsGuids[1].empty()) + m_lWaveMobsGuids[1].remove(pCreature->GetObjectGuid()); + break; + case NPC_AKUMAI_SNAPJAW: + if (!m_lWaveMobsGuids[0].empty()) + m_lWaveMobsGuids[0].remove(pCreature->GetObjectGuid()); + break; + case NPC_BARBED_CRUSTACEAN: + if (!m_lWaveMobsGuids[2].empty()) + m_lWaveMobsGuids[2].remove(pCreature->GetObjectGuid()); + break; + case NPC_MURKSHALLOW_SOFTSHELL: + if (!m_lWaveMobsGuids[3].empty()) + m_lWaveMobsGuids[3].remove(pCreature->GetObjectGuid()); + break; + default: + break; + } + + if (IsWaveEventFinished()) + SetData(TYPE_SHRINE, DONE); +} + +// Check if all the summoned event mobs are dead +bool instance_blackfathom_deeps::IsWaveEventFinished() +{ + // If not all fires are lighted return + if (m_uiWaveCounter < MAX_FIRES) + return false; + + // Check if all mobs are dead + for (uint8 i = 0; i < MAX_FIRES; ++i) + { + if (!m_lWaveMobsGuids[i].empty()) + return false; } - void Update(uint32 uiDiff) + return true; +} + +void instance_blackfathom_deeps::Update(uint32 uiDiff) +{ + // Only use this function if shrine event is in progress + if (m_auiEncounter[ENCOUNTER_SHRINE] != IN_PROGRESS) + return; + + for (uint8 i = 0; i < MAX_FIRES; ++i) { - if (m_uiSpawnServantTimer) + if (m_uiSpawnMobsTimer[i]) { - if (m_uiSpawnServantTimer <= uiDiff) + if (m_uiSpawnMobsTimer[i] <= uiDiff) { - SpawnServants(); - m_uiSpawnServantTimer = 0; + DoSpawnMobs(i); + m_uiSpawnMobsTimer[i] = 0; } else - m_uiSpawnServantTimer -= uiDiff; + m_uiSpawnMobsTimer[i] -= uiDiff; } } -}; +} InstanceData* GetInstanceData_instance_blackfathom_deeps(Map* pMap) { return new instance_blackfathom_deeps(pMap); } -bool GOHello_go_fire_of_akumai(Player* pPlayer, GameObject* pGo) +bool GOUse_go_fire_of_akumai(Player* /*pPlayer*/, GameObject* pGo) { - ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + instance_blackfathom_deeps* pInstance = (instance_blackfathom_deeps*)pGo->GetInstanceData(); if (!pInstance) return true; - if (pInstance->GetData(TYPE_KELRIS) == DONE) + if (pInstance->GetData(TYPE_SHRINE) == DONE) + return true; + + if (pInstance->GetData(TYPE_KELRIS) == DONE && pInstance->GetData(TYPE_SHRINE) != DONE) { - pInstance->SetData(TYPE_SHRINE, pGo->GetEntry()); + pInstance->SetData(TYPE_SHRINE, IN_PROGRESS); return false; } @@ -233,15 +280,15 @@ bool GOHello_go_fire_of_akumai(Player* pPlayer, GameObject* pGo) void AddSC_instance_blackfathom_deeps() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "instance_blackfathom_deeps"; - newscript->GetInstanceData = &GetInstanceData_instance_blackfathom_deeps; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "instance_blackfathom_deeps"; + pNewScript->GetInstanceData = &GetInstanceData_instance_blackfathom_deeps; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "go_fire_of_akumai"; - newscript->pGOHello = &GOHello_go_fire_of_akumai; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_fire_of_akumai"; + pNewScript->pGOUse = &GOUse_go_fire_of_akumai; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/bloodmyst_isle.cpp b/scripts/kalimdor/bloodmyst_isle.cpp index 7a4531a25d..5fe0cd9c01 100644 --- a/scripts/kalimdor/bloodmyst_isle.cpp +++ b/scripts/kalimdor/bloodmyst_isle.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,13 +17,12 @@ /* ScriptData SDName: Bloodmyst_Isle SD%Complete: 80 -SDComment: Quest support: 9670, 9756(gossip items text needed). +SDComment: Quest support: 9670 SDCategory: Bloodmyst Isle EndScriptData */ /* ContentData mob_webbed_creature -npc_captured_sunhawk_agent EndContentData */ #include "precompiled.h" @@ -32,106 +31,55 @@ EndContentData */ ## mob_webbed_creature ######*/ -//possible creatures to be spawned -const uint32 possibleSpawns[32] = {17322, 17661, 17496, 17522, 17340, 17352, 17333, 17524, 17654, 17348, 17339, 17345, 17359, 17353, 17336, 17550, 17330, 17701, 17321, 17680, 17325, 17320, 17683, 17342, 17715, 17334, 17341, 17338, 17337, 17346, 17344, 17327}; +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 MANGOS_DLL_DECL 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->GetGUID()); + 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, 31)]; + 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, 60000); + if (uiSpawnCreatureEntry) + m_creature->SummonCreature(uiSpawnCreatureEntry, 0.0f, 0.0f, 0.0f, m_creature->GetOrientation(), TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); } }; + CreatureAI* GetAI_mob_webbed_creature(Creature* pCreature) { return new mob_webbed_creatureAI(pCreature); } -/*###### -## npc_captured_sunhawk_agent -######*/ - -#define C_SUNHAWK_TRIGGER 17974 - -bool GossipHello_npc_captured_sunhawk_agent(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->HasAura(31609, EFFECT_INDEX_1) && pPlayer->GetQuestStatus(9756) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(9136, pCreature->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(9134, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_captured_sunhawk_agent(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(9137, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(9138, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(9139, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(9140, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->SEND_GOSSIP_MENU(9141, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->TalkedToCreature(C_SUNHAWK_TRIGGER, pCreature->GetGUID()); - break; - } - return true; -} - void AddSC_bloodmyst_isle() { - Script *newscript; - - newscript = new Script; - newscript->Name = "mob_webbed_creature"; - newscript->GetAI = &GetAI_mob_webbed_creature; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_captured_sunhawk_agent"; - newscript->pGossipHello = &GossipHello_npc_captured_sunhawk_agent; - newscript->pGossipSelect = &GossipSelect_npc_captured_sunhawk_agent; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_webbed_creature"; + pNewScript->GetAI = &GetAI_mob_webbed_creature; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/boss_azuregos.cpp b/scripts/kalimdor/boss_azuregos.cpp index d00086db3a..c454d89bf2 100644 --- a/scripts/kalimdor/boss_azuregos.cpp +++ b/scripts/kalimdor/boss_azuregos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,125 +17,139 @@ /* ScriptData SDName: Boss_Azuregos SD%Complete: 90 -SDComment: Teleport not included, spell reflect not effecting dots (Core problem) +SDComment: Spell reflect not effecting dots (Core problem) SDCategory: Azshara EndScriptData */ #include "precompiled.h" -#define SAY_TELEPORT -1000100 - -#define SPELL_MARKOFFROST 23182 -#define SPELL_MANASTORM 21097 -#define SPELL_CHILL 21098 -#define SPELL_FROSTBREATH 21099 -#define SPELL_REFLECT 22067 -#define SPELL_CLEAVE 8255 //Perhaps not right ID -#define SPELL_ENRAGE 23537 +enum +{ + SAY_TELEPORT = -1000100, + + SPELL_ARCANE_VACUUM = 21147, + SPELL_MARK_OF_FROST_PLAYER = 23182, + SPELL_MARK_OF_FROST_AURA = 23184, // Triggers 23186 on players that have 23182; unfortunatelly 23183 is missing from dbc + SPELL_MANA_STORM = 21097, + SPELL_CHILL = 21098, + SPELL_FROST_BREATH = 21099, + SPELL_REFLECT = 22067, + SPELL_CLEAVE = 19983, // Was 8255; this one is from wowhead and seems to be the correct one + SPELL_ENRAGE = 23537, +}; struct MANGOS_DLL_DECL boss_azuregosAI : public ScriptedAI { boss_azuregosAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 MarkOfFrost_Timer; - uint32 ManaStorm_Timer; - uint32 Chill_Timer; - uint32 Breath_Timer; - uint32 Teleport_Timer; - uint32 Reflect_Timer; - uint32 Cleave_Timer; - uint32 Enrage_Timer; - bool Enraged; + uint32 m_uiManaStormTimer; + uint32 m_uiChillTimer; + uint32 m_uiBreathTimer; + uint32 m_uiTeleportTimer; + uint32 m_uiReflectTimer; + uint32 m_uiCleaveTimer; + bool m_bEnraged; void Reset() { - MarkOfFrost_Timer = 35000; - ManaStorm_Timer = urand(5000, 17000); - Chill_Timer = urand(10000, 30000); - Breath_Timer = urand(2000, 8000); - Teleport_Timer = 30000; - Reflect_Timer = urand(15000, 30000); - Cleave_Timer = 7000; - Enrage_Timer = 0; - Enraged = false; + m_uiManaStormTimer = urand(5000, 17000); + m_uiChillTimer = urand(10000, 30000); + m_uiBreathTimer = urand(2000, 8000); + m_uiTeleportTimer = 30000; + m_uiReflectTimer = urand(15000, 30000); + m_uiCleaveTimer = 7000; + m_bEnraged = false; + } + + 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 UpdateAI(const uint32 diff) + void Aggro(Unit* /*pWho*/) override { - //Return since we have no target + // 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) override + { + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Teleport_Timer < diff) + if (m_uiTeleportTimer < uiDiff) { - DoScriptText(SAY_TELEPORT, m_creature); - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_VACUUM) == CAST_OK) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) - DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+3, pUnit->GetOrientation()); + DoScriptText(SAY_TELEPORT, m_creature); + m_uiTeleportTimer = 30000; } + } + else + m_uiTeleportTimer -= uiDiff; - DoResetThreat(); - Teleport_Timer = 30000; - }else Teleport_Timer -= diff; - - // //MarkOfFrost_Timer - // if (MarkOfFrost_Timer < diff) - // { - // DoCastSpellIfCan(m_creature->getVictim(),SPELL_MARKOFFROST); - // MarkOfFrost_Timer = 25000; - // }else MarkOfFrost_Timer -= diff; - - //Chill_Timer - if (Chill_Timer < diff) + // Chill Timer + if (m_uiChillTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CHILL); - Chill_Timer = urand(13000, 25000); - }else Chill_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_CHILL) == CAST_OK) + m_uiChillTimer = urand(13000, 25000); + } + else + m_uiChillTimer -= uiDiff; - //Breath_Timer - if (Breath_Timer < diff) + // Breath Timer + if (m_uiBreathTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBREATH); - Breath_Timer = urand(10000, 15000); - }else Breath_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_FROST_BREATH) == CAST_OK) + m_uiBreathTimer = urand(10000, 15000); + } + else + m_uiBreathTimer -= uiDiff; - //ManaStorm_Timer - if (ManaStorm_Timer < diff) + // Mana Storm Timer + if (m_uiManaStormTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_MANASTORM); - ManaStorm_Timer = urand(7500, 12500); - }else ManaStorm_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MANA_STORM) == CAST_OK) + m_uiManaStormTimer = urand(7500, 12500); + } + } + else + m_uiManaStormTimer -= uiDiff; - //Reflect_Timer - if (Reflect_Timer < diff) + // Reflect Timer + if (m_uiReflectTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_REFLECT); - Reflect_Timer = urand(20000, 35000); - }else Reflect_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_REFLECT) == CAST_OK) + m_uiReflectTimer = urand(20000, 35000); + } + else + m_uiReflectTimer -= uiDiff; - //Cleave_Timer - if (Cleave_Timer < diff) + // Cleave Timer + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 7000; + } + else + m_uiCleaveTimer -= uiDiff; - //Enrage_Timer - if (m_creature->GetHealthPercent() < 26.0f && !Enraged) + // EnrageTimer + if (!m_bEnraged && m_creature->GetHealthPercent() < 26.0f) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - Enraged = true; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bEnraged = true; } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_azuregos(Creature* pCreature) { return new boss_azuregosAI(pCreature); @@ -143,9 +157,10 @@ CreatureAI* GetAI_boss_azuregos(Creature* pCreature) void AddSC_boss_azuregos() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_azuregos"; - newscript->GetAI = &GetAI_boss_azuregos; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_azuregos"; + pNewScript->GetAI = &GetAI_boss_azuregos; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_infinite_corruptor.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_infinite_corruptor.cpp new file mode 100644 index 0000000000..2d20cb6868 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_infinite_corruptor.cpp @@ -0,0 +1,134 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" + +enum +{ + SPELL_COURSE = 60588, + SPELL_STRIKE = 60590 +}; + +struct MANGOS_DLL_DECL boss_infinite_corruptorAI : public ScriptedAI +{ + boss_infinite_corruptorAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStrikeTimer; + uint32 m_uiCourseTimer; + + void Reset() + { + m_uiCourseTimer = 7000; + m_uiStrikeTimer = 5000; + } + + void Aggro(Unit* pWho) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BONUS, SPECIAL); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BONUS, DONE); + } + + void KilledUnit(Unit* pVictim) override + { + //switch(rand()%3) + // { + // case 0: DoScriptText(SAY_EPOCH_SLAY01, m_creature); break; + // case 1: DoScriptText(SAY_EPOCH_SLAY02, m_creature); break; + // case 2: DoScriptText(SAY_EPOCH_SLAY03, m_creature); break; + // } + } + + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BONUS, IN_PROGRESS); + + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCourseTimer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_COURSE); + + m_uiCourseTimer = 17000; + }else m_uiCourseTimer -= uiDiff; + + if (m_uiStrikeTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_STRIKE); + + m_uiStrikeTimer = 5000; + }else m_uiStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_infinite_corruptor(Creature* pCreature) +{ + return new boss_infinite_corruptorAI(pCreature); +} + +void AddSC_boss_infinite_corruptor() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_infinite_corruptor"; + pNewScript->GetAI = &GetAI_boss_infinite_corruptor; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_lord_epoch.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_lord_epoch.cpp new file mode 100644 index 0000000000..89746d3c39 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_lord_epoch.cpp @@ -0,0 +1,147 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" + +enum +{ + SPELL_COURSE = 52772, + SPELL_TIME_STOP = 58848, + SPELL_TIME_WARP = 52766, + SPELL_SPIKE_N = 52771, + SPELL_SPIKE_H = 58830, + + SAY_EPOCH_DEATH = -1594119, + SAY_EPOCH_SLAY01 = -1594120, + SAY_EPOCH_SLAY02 = -1594121, + SAY_EPOCH_SLAY03 = -1594122, + SAY_EPOCH_WARP01 = -1594123, + SAY_EPOCH_WARP02 = -1594124, + SAY_EPOCH_WARP03 = -1594125 +}; + +struct MANGOS_DLL_DECL boss_lord_epochAI : public ScriptedAI +{ + boss_lord_epochAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiSpike_Timer; + uint32 m_uiWarp_Timer; + uint32 m_uiStop_Timer; + uint32 m_uiCourse_Timer; + + void Reset() + { + m_uiCourse_Timer = 9300; + m_uiStop_Timer = 21300; + m_uiWarp_Timer = 25300; + m_uiSpike_Timer = 5300; + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_EPOCH_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + switch(rand()%3) + { + case 0: DoScriptText(SAY_EPOCH_SLAY01, m_creature); break; + case 1: DoScriptText(SAY_EPOCH_SLAY02, m_creature); break; + case 2: DoScriptText(SAY_EPOCH_SLAY03, m_creature); break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCourse_Timer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_COURSE); + + m_uiCourse_Timer = 9300; + }else m_uiCourse_Timer -= uiDiff; + + if (m_uiSpike_Timer < uiDiff) + { + + DoCast(m_creature->getVictim(),m_bIsHeroic ? SPELL_SPIKE_H : SPELL_SPIKE_N); + + m_uiSpike_Timer = 5300; + }else m_uiSpike_Timer -= uiDiff; + + if (m_uiStop_Timer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_TIME_STOP); + + m_uiStop_Timer = 21300; + }else m_uiStop_Timer -= uiDiff; + + if (m_uiWarp_Timer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_TIME_WARP); + switch(rand()%3) + { + case 0: DoScriptText(SAY_EPOCH_WARP01, m_creature); break; + case 1: DoScriptText(SAY_EPOCH_WARP02, m_creature); break; + case 2: DoScriptText(SAY_EPOCH_WARP03, m_creature); break; + } + + m_uiWarp_Timer = 25300; + }else m_uiWarp_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_boss_lord_epoch(Creature* pCreature) +{ + return new boss_lord_epochAI(pCreature); +} + +void AddSC_boss_lord_epoch() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lord_epoch"; + pNewScript->GetAI = &GetAI_boss_lord_epoch; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_malganis.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_malganis.cpp new file mode 100644 index 0000000000..ea220fffa7 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_malganis.cpp @@ -0,0 +1,203 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" + +enum +{ + SAY_MALGANIS_AGGRO = -1594170, + SAY_MALGANIS_SLAY01 = -1594172, + SAY_MALGANIS_SLAY02 = -1594173, + SAY_MALGANIS_SLAY03 = -1594174, + SAY_MALGANIS_SLAY04 = -1594175, + SAY_MALGANIS_SLAY05 = -1594176, + SAY_MALGANIS_SLAY06 = -1594177, + SAY_MALGANIS_SLAY07 = -1594166, + SAY_MALGANIS_SLEEP01 = -1594185, + SAY_MALGANIS_SLEEP02 = -1594186, + SAY_MALGANIS_Sleep = -1594178, + SAY_MALGANIS_15HP = -1594179, + + SPELL_SWAMP_N = 52720, + SPELL_SWAMP_H = 58852, + SPELL_MIND_BLAST_N = 52722, + SPELL_MIND_BLAST_H = 58850, + SPELL_SLEEP_N = 52721, + SPELL_SLEEP_H = 58849, + SPELL_VAMPIRE = 52723, + SPELL_ACHIEVEMENT_CREDIT = 58630 +}; + +struct MANGOS_DLL_DECL boss_malganisAI : public ScriptedAI +{ + boss_malganisAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + Unit* pTarget; + bool Sleep; + bool Vampire; + Creature* Malganis; + Creature* Arthas; + + uint32 m_uiSwamp_Timer; + uint32 m_uiMindBlast_Timer; + uint32 m_uiSleep_Timer; + uint32 m_uiVampire_Timer; + + void Reset() + { + Sleep = false; + Vampire = false; + m_uiSwamp_Timer = 6300; + m_uiMindBlast_Timer = 11300; + m_uiSleep_Timer = 17300; + m_uiVampire_Timer = 30000; + } + + void AttackStart(Unit* pWho) override + { + if (m_pInstance->GetData(TYPE_PHASE) > 9) return; + + if (m_pInstance->GetData(TYPE_MALGANIS) != IN_PROGRESS) return; + + if (!pWho || pWho == m_creature) + return; + + ScriptedAI::AttackStart(pWho); + } + + void EnterEvadeMode() override + { + m_creature->ForcedDespawn(); + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_MALGANIS_AGGRO, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + switch(rand()%7) + { + case 0: DoScriptText(SAY_MALGANIS_SLAY01, m_creature); break; + case 1: DoScriptText(SAY_MALGANIS_SLAY02, m_creature); break; + case 2: DoScriptText(SAY_MALGANIS_SLAY03, m_creature); break; + case 3: DoScriptText(SAY_MALGANIS_SLAY04, m_creature); break; + case 4: DoScriptText(SAY_MALGANIS_SLAY05, m_creature); break; + case 5: DoScriptText(SAY_MALGANIS_SLAY06, m_creature); break; + case 6: DoScriptText(SAY_MALGANIS_SLAY07, m_creature); break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSwamp_Timer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsHeroic ? SPELL_SWAMP_H : SPELL_SWAMP_N); + m_uiSwamp_Timer = 7300; + }else m_uiSwamp_Timer -= uiDiff; + + if (m_uiMindBlast_Timer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsHeroic ? SPELL_MIND_BLAST_H : SPELL_MIND_BLAST_N); + + m_uiMindBlast_Timer = 11300; + }else m_uiMindBlast_Timer -= uiDiff; + + if (m_creature->GetHealthPercent() < 40.0f) + { + if (Sleep == false) + { + Sleep = true; + DoScriptText(SAY_MALGANIS_Sleep, m_creature); + } + if (m_uiSleep_Timer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsHeroic ? SPELL_SLEEP_H : SPELL_SLEEP_N); + switch(rand()%2) + { + case 0: DoScriptText(SAY_MALGANIS_SLEEP01, m_creature); break; + case 1: DoScriptText(SAY_MALGANIS_SLEEP02, m_creature); break; + } + m_uiSleep_Timer = 17300; + }else m_uiSleep_Timer -= uiDiff; + } + + if (m_creature->GetHealthPercent() < 25.0f) + { + if (Vampire == false) + { + Vampire = true; + DoScriptText(SAY_MALGANIS_15HP, m_creature); + DoCast(m_creature, SPELL_VAMPIRE); + } + if (m_uiVampire_Timer < uiDiff) + { + DoCast(m_creature, SPELL_VAMPIRE); + m_uiVampire_Timer = 30000; + }else m_uiVampire_Timer -= uiDiff; + } + + if (m_creature->GetHealthPercent() < 5.0f) + { + m_pInstance->SetData(TYPE_PHASE, 10); + m_pInstance->SetData(TYPE_MALGANIS, DONE); + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ACHIEVEMENT_CREDIT); + EnterEvadeMode(); + } + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_malganis(Creature* pCreature) +{ + return new boss_malganisAI(pCreature); +} + +void AddSC_boss_malganis() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_malganis"; + pNewScript->GetAI = &GetAI_boss_malganis; + pNewScript->RegisterSelf(); + +} diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_meathook.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_meathook.cpp new file mode 100644 index 0000000000..7e3f2f0569 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_meathook.cpp @@ -0,0 +1,136 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" + +enum +{ + SPELL_CHAIN_N = 52696, + SPELL_CHAIN_H = 58823, + SPELL_EXPLODED_N = 52666, + SPELL_EXPLODED_H = 58824, + SPELL_FRENZY = 58841, + + SAY_MEATHOOK_AGGRO = -1594111, + SAY_MEATHOOK_DEATH = -1594112, + SAY_MEATHOOK_SLAY01 = -1594113, + SAY_MEATHOOK_SLAY02 = -1594114, + SAY_MEATHOOK_SLAY03 = -1594115 +}; + +struct MANGOS_DLL_DECL boss_meathookAI : public ScriptedAI +{ + boss_meathookAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + m_creature->SetInCombatWithZone(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiChain_Timer; + uint32 m_uiExploded_Timer; + uint32 m_uiFrenzy_Timer; + + void Reset() + { + m_uiChain_Timer = 6300; + m_uiExploded_Timer = 5000; + m_uiFrenzy_Timer = 22300; + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_MEATHOOK_AGGRO, m_creature); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_MEATHOOK_DEATH, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_PHASE, 3); + } + + void KilledUnit(Unit* pVictim) override + { + switch(rand()%3) + { + case 0: DoScriptText(SAY_MEATHOOK_SLAY01, m_creature); break; + case 1: DoScriptText(SAY_MEATHOOK_SLAY02, m_creature); break; + case 2: DoScriptText(SAY_MEATHOOK_SLAY03, m_creature); break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiChain_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(pTarget, m_bIsHeroic ? SPELL_CHAIN_H : SPELL_CHAIN_N); + + m_uiChain_Timer = 6300; + }else m_uiChain_Timer -= uiDiff; + + if (m_uiExploded_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(pTarget, m_bIsHeroic ? SPELL_EXPLODED_H : SPELL_EXPLODED_N); + + m_uiExploded_Timer = 5000; + }else m_uiExploded_Timer -= uiDiff; + + if (m_uiFrenzy_Timer < uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_FRENZY); + + m_uiFrenzy_Timer = 23300; + }else m_uiFrenzy_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_meathook(Creature* pCreature) +{ + return new boss_meathookAI(pCreature); +} + +void AddSC_boss_meathook() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_meathook"; + pNewScript->GetAI = &GetAI_boss_meathook; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_salramm.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_salramm.cpp new file mode 100644 index 0000000000..0058d2a3ac --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_salramm.cpp @@ -0,0 +1,265 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" + +enum +{ + SAY_SALRAMM_AGGRO = -1594130, + SAY_SALRAMM_DEATH = -1594131, + SAY_SALRAMM_SLAY01 = -1594132, + SAY_SALRAMM_SLAY02 = -1594133, + SAY_SALRAMM_SLAY03 = -1594134, + SAY_SALRAMM_STEAL01 = -1594135, + SAY_SALRAMM_STEAL02 = -1594136, + SAY_SALRAMM_STEAL03 = -1594137, + SAY_SUMMON01 = -1594138, + SAY_SUMMON02 = -1594139, + SAY_BOOM01 = -1594140, + SAY_BOOM02 = -1594141, + + SPELL_SB_N = 57725, + SPELL_SB_H = 58827, + SPELL_FLESH = 58845, + SPELL_STEAL = 52708, + SPELL_GNOUL_BLOW = 58825, + SPELL_SUMMON_GNOUL = 52451, + + NPC_GNOUL = 27733, + GNOUL_IMAGE = 11686 +}; + +struct MANGOS_DLL_DECL boss_salrammAI : public ScriptedAI +{ + boss_salrammAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + m_creature->SetInCombatWithZone(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiShadowBoltTimer; + uint32 m_uiFleshTimer; + uint32 m_uiStealTimer; + uint32 m_uiSummonTimer; + + void Reset() + { + m_uiShadowBoltTimer = 5000; + m_uiFleshTimer = (urand(7000, 9000)); + m_uiStealTimer = (urand(9000, 17000)); + m_uiSummonTimer = (urand(12000, 17000)); + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_SALRAMM_AGGRO, m_creature); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_SALRAMM_DEATH, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_ENCOUNTER, DONE); + } + + void KilledUnit(Unit* pVictim) override + { + switch(rand()%3) + { + case 0: DoScriptText(SAY_SALRAMM_SLAY01, m_creature); break; + case 1: DoScriptText(SAY_SALRAMM_SLAY02, m_creature); break; + case 2: DoScriptText(SAY_SALRAMM_SLAY03, m_creature); break; + } + } + + void SpellHitTarget(Unit *pTarget, const SpellEntry *spell) + { + if (spell->Id == SPELL_GNOUL_BLOW) + if (pTarget->GetTypeId() != TYPEID_PLAYER && pTarget->GetEntry() == NPC_GNOUL) + pTarget->SetDisplayId(GNOUL_IMAGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiShadowBoltTimer < uiDiff) + { + DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_SB_H : SPELL_SB_N); + + m_uiShadowBoltTimer = (urand(5000, 6000)); + }else m_uiShadowBoltTimer -= uiDiff; + + if (m_uiFleshTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(pTarget,SPELL_FLESH); + + m_uiFleshTimer = 7300; + }else m_uiFleshTimer -= uiDiff; + + if (m_uiStealTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(pTarget,SPELL_STEAL); + + switch(rand()%3) + { + case 0: DoScriptText(SAY_SALRAMM_STEAL01, m_creature); break; + case 1: DoScriptText(SAY_SALRAMM_STEAL02, m_creature); break; + case 2: DoScriptText(SAY_SALRAMM_STEAL03, m_creature); break; + } + + m_uiStealTimer = (urand(8000, 11000)); + }else m_uiStealTimer -= uiDiff; + + if (m_uiSummonTimer < uiDiff) + { + switch(rand()%2) + { + case 0: DoScriptText(SAY_SUMMON01, m_creature); break; + case 1: DoScriptText(SAY_SUMMON02, m_creature); break; + } + + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature,SPELL_SUMMON_GNOUL); + + m_uiSummonTimer = (urand(12000, 17000)); + }else m_uiSummonTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*### +## npc_salramm_gnoul +###*/ + +struct MANGOS_DLL_DECL npc_salramm_gnoulAI : public ScriptedAI +{ + npc_salramm_gnoulAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiBlowTimer; + + void Reset() + { + m_uiBlowTimer = (urand(3000, 15000)); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBlowTimer < uiDiff) + { + if (Creature* pSalramm = m_pInstance->GetSingleCreatureFromStorage(NPC_SALRAMM)) + { + if (pSalramm->isDead()) + return; + + switch(rand()%2) + { + case 0: DoScriptText(SAY_BOOM01, pSalramm); break; + case 1: DoScriptText(SAY_BOOM02, pSalramm); break; + } + pSalramm->InterruptNonMeleeSpells(false); + pSalramm->CastSpell(m_creature, SPELL_GNOUL_BLOW, false); + } + } + else m_uiBlowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_salramm(Creature* pCreature) +{ + return new boss_salrammAI(pCreature); +} + +CreatureAI* GetAI_npc_salramm_gnoul(Creature* pCreature) +{ + return new npc_salramm_gnoulAI(pCreature); +} + +void AddSC_boss_salramm() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_salramm"; + pNewScript->GetAI = &GetAI_boss_salramm; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_salramm_gnoul"; + pNewScript->GetAI = &GetAI_npc_salramm_gnoul; + pNewScript->RegisterSelf(); +} 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 fd3228f45d..aa5f447592 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,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,222 +15,1733 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + /* ScriptData -SDName: culling_of_stratholme -SD%Complete: 5% -SDComment: Placeholder -SDCategory: Culling of Stratholme +SDName: instance_culling_of_stratholme +SD%Complete: % +SDComment: EndScriptData */ #include "precompiled.h" #include "culling_of_stratholme.h" +#include "escort_ai.h" +#include "WorldPacket.h" +#include "Weather.h" -/* ************* -** npc_chromie (gossip, quest-accept) -************* */ +/*### +## npc_arthas +###*/ enum { - QUEST_DISPELLING_ILLUSIONS = 13149, - QUEST_A_ROYAL_ESCORT = 13151, + SAY_INTRO01 = -1594071, //Arthas + SAY_INTRO02 = -1594072, //Uther + SAY_INTRO03 = -1594073, //Arthas + SAY_INTRO04 = -1594074, //Arthas + SAY_INTRO05 = -1594075, //Uther + SAY_INTRO06 = -1594076, //Arthas + SAY_INTRO07 = -1594077, //Uther + SAY_INTRO08 = -1594078, //Arthas + SAY_INTRO09 = -1594079, //Arthas + SAY_INTRO10 = -1594080, //Uther + SAY_INTRO11 = -1594081, //Arthas + SAY_INTRO12 = -1594082, //Uther + SAY_INTRO13 = -1594083, //Jaina + SAY_INTRO14 = -1594084, //Arthas + SAY_INTRO15 = -1594085, //Uther + SAY_INTRO16 = -1594086, //Arthas + SAY_INTRO17 = -1594087, //Jaina + SAY_INTRO18 = -1594088, //Arthas + + SAY_ENTER01 = -1594089, //Arthas + SAY_ENTER02 = -1594090, //Cityman + SAY_ENTER03 = -1594091, //Arthas + SAY_ENTER04 = -1594092, //Crazyman + SAY_ENTER05 = -1594093, //Crazyman2 + SAY_ENTER06 = -1594094, //Arthas + SAY_ENTER07 = -1594095, //Malganis + SAY_ENTER08 = -1594096, //Malganis + SAY_ENTER09 = -1594097, //Arthas + SAY_ENTER10 = -1594098, //Arthas + + SAY_SALRAMM_SPAWN = -1594129, + SAY_MEATHOOK_SPAWN = -1594110, + + SAY_PHASE501 = -1594142, //Arthas + SAY_PHASE502 = -1594143, //Arthas + SAY_PHASE503 = -1594144, //Human + SAY_PHASE504 = -1594145, //Arthas + SAY_PHASE505 = -1594146, //Arthas + SAY_PHASE506 = -1594147, //Human + SAY_PHASE507 = -1594148, //Arthas + SAY_PHASE508 = -1594149, //Arthas + SAY_PHASE509 = -1594150, //Arthas + SAY_PHASE510 = -1594151, //Arthas + SAY_PHASE511 = -1594152, //Arthas + SAY_PHASE512 = -1594153, //Arthas + SAY_PHASE513 = -1594154, //Arthas - ITEM_ARCANE_DISRUPTOR = 37888, + SAY_EPOCH_INTRO = -1594155, + SAY_ARTHAS_INTRO = -1594156, + SAY_EPOCH_AGGRO = -1594157, - GOSSIP_ITEM_ENTRANCE_1 = -3595000, - GOSSIP_ITEM_ENTRANCE_2 = -3595001, - GOSSIP_ITEM_ENTRANCE_3 = -3595002, + SAY_PHASE514 = -1594158, //Arthas Shkaf 01 + SAY_PHASE515 = -1594159, //Arthas Shkaf 02 + SAY_PHASE601 = -1594160, //Arthas Fire + SAY_PHASE602 = -1594161, //Arthas Picnic + SAY_PHASE603 = -1594162, //Arthas Picnic End + SAY_PHASE605 = -1594164, //Arthas mall start + SAY_PHASE606 = -1594188, - TEXT_ID_ENTRANCE_1 = 12992, - TEXT_ID_ENTRANCE_2 = 12993, - TEXT_ID_ENTRANCE_3 = 12994, - TEXT_ID_ENTRANCE_4 = 12995, + SAY_MALGANIS_ESCAPE02 = -1594180, + SAY_MALGANIS_ESCAPE01 = -1594187, + SAY_MALGANIS_OUTRO = -1594182, + SAY_ARTHAS_OUTRO01 = -1594181, + SAY_ARTHAS_OUTRO02 = -1594183, + SAY_ARTHAS_OUTRO03 = -1594184, - GOSSIP_ITEM_INN_1 = -3595003, - GOSSIP_ITEM_INN_2 = -3595004, - GOSSIP_ITEM_INN_3 = -3595005, + /*SPELL*/ + SPELL_EXORCISM_N = 52445, + SPELL_EXORCISM_H = 58822, + SPELL_HOLY_LIGHT = 52444, + SPELL_ARTHAS_AURA = 52442, - TEXT_ID_INN_1 = 12939, - TEXT_ID_INN_2 = 12949, - TEXT_ID_INN_3 = 12950, - TEXT_ID_INN_4 = 12952, +///-> marines + SPELL_HEROIC_STRIKE = 25710, + SPELL_DEFEND = 52317, +///->priest + SPELL_SMITE = 61923, + SPELL_HEAL = 62442, + + /*OTHER*/ + POINT_LAST_POINT = 0xFFFFFF, + FACTION = 2076 }; -bool GossipHello_npc_chromie(Player *pPlayer, Creature *pCreature) +#define Last1X 2083.483f +#define Last1Y 1282.313f +#define Last1Z 141.198f + +#define Last2X 2083.681f +#define Last2Y 1292.809f +#define Last2Z 141.141f + +#define Last3X 2082.158f +#define Last3Y 1290.406f +#define Last3Z 141.261f + +#define Last4X 2081.899f +#define Last4Y 1285.122f +#define Last4Z 141.302f + + float Last5X; + float Last5Y; + float Last5Z; + +const float SummonScourge[2][4] = { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + {2340.058f, 1253.570f, 132.733f, 5.09f}, //right wing + {2272.773f, 1331.824f, 124.171f, 3.12f}, //left wing +}; + +struct MANGOS_DLL_DECL npc_arthasAI : public npc_escortAI +{ + npc_arthasAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + m_creature->SetSpeedRate(MOVE_RUN, 1); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + ObjectGuid m_uiMalganisGUID; + ObjectGuid m_uiHuman01GUID; + ObjectGuid m_uiHuman02GUID; + ObjectGuid m_uiHuman03GUID; + ObjectGuid m_uiPeople01GUID; + ObjectGuid m_uiPeople02GUID; + + uint32 culling_faction; + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiHealTimer; + uint32 m_uiExorcismTimer; + uint32 m_uiSummonTimer; + uint32 m_uiWaveCount; + + Creature* Malganis; + Creature* pEpoch; + bool StartEvent; + + void Reset() + { + if (!m_pInstance) return; + + m_creature->SetSpeedRate(MOVE_RUN, 1); + + if (m_pInstance->GetData(TYPE_INTRO) == NOT_STARTED) + { + m_creature->setFaction(35); + RemoveGossip(); + } + + if (m_pInstance->GetData(TYPE_PHASE) == 11) + { + m_creature->SetVisibility(VISIBILITY_OFF); + } + } + + void RemoveGossip() + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void MoveSoldiers() + { + if (Creature* pMarine01 = m_pInstance->GetSingleCreatureFromStorage(NPC_MARINE_1)) + { + pMarine01->GetMotionMaster()->MovePoint(0, 2083.483f,1282.313f,141.198f); + pMarine01->setFaction(culling_faction); + } + if (Creature* pMarine02 = m_pInstance->GetSingleCreatureFromStorage(NPC_MARINE_2)) + { + pMarine02->GetMotionMaster()->MovePoint(0, 2083.681f,1292.809f,141.141f); + pMarine02->setFaction(culling_faction); + } + if (Creature* pMarine03 = m_pInstance->GetSingleCreatureFromStorage(NPC_MARINE_3)) + { + pMarine03->GetMotionMaster()->MovePoint(0, 2082.158f,1290.406f,141.261f); + pMarine03->setFaction(culling_faction); + } + if (Creature* pMarine04 = m_pInstance->GetSingleCreatureFromStorage(NPC_MARINE_4)) + { + pMarine04->GetMotionMaster()->MovePoint(0, 2081.899f,1285.122f,141.302f); + pMarine04->setFaction(culling_faction); + } + if (Creature* pPriest01 = m_pInstance->GetSingleCreatureFromStorage(NPC_PRIEST_1)) + { + pPriest01->GetMotionMaster()->MovePoint(0, 2081.072f,1292.233f,141.329f); + pPriest01->setFaction(culling_faction); + } + if (Creature* pPriest02 = m_pInstance->GetSingleCreatureFromStorage(NPC_PRIEST_2)) + { + pPriest02->GetMotionMaster()->MovePoint(0, 2080.632f,1283.004f,141.358f); + pPriest02->setFaction(culling_faction); + } + } + + void EnableEscort() + { + SetEscortPaused(false); + } + + void SummonPeople() + { + if (Creature* pCityman = m_creature->SummonCreature(NPC_CITY,2091.977f,1275.021f,140.757f,0.558f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,30000)) + m_uiPeople01GUID = pCityman->GetObjectGuid(); + if (Creature* pCrazyman = m_creature->SummonCreature(NPC_CRAZYMAN,2093.514f,1275.842f,140.408f,3.801f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,30000)) + m_uiPeople02GUID = pCrazyman->GetObjectGuid(); + } + + void StartAI() + { + SummonPeople(); + m_uiStep = 0; + m_uiStepTimer = 100; + StartEvent = true; + } + + void Aggro(Unit* who) + { + DoCast(m_creature, SPELL_ARTHAS_AURA); + } + + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + m_uiExorcismTimer = 7400; + m_uiHealTimer = 100; + + m_creature->SetLootRecipient(NULL); + + if (m_pInstance->GetData(TYPE_PHASE) > 4) + { + npc_escortAI::EnterEvadeMode(); + } + + if (m_pInstance->GetData(TYPE_PHASE) > 2 && m_pInstance->GetData(TYPE_PHASE) < 5) + { + m_creature->GetMotionMaster()->MovePoint(POINT_LAST_POINT, Last5X, Last5Y, Last5Z); + } + } + + void AttackStart(Unit* pWho) override + { + if (!pWho || pWho == m_creature) + return; - if (instance_culling_of_stratholme* m_pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) + if (m_pInstance && m_pInstance->GetData(TYPE_PHASE) == 4) return; + + npc_escortAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override { - switch (pCreature->GetEntry()) + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && pWho->isTargetableForAttack() && + m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) { - case NPC_CHROMIE_INN: - if (m_pInstance->GetData(TYPE_GRAIN_EVENT) != DONE) + 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()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) { - 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); + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); } - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN_1, pCreature->GetGUID()); + } + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch(uiPointId) + { + case 2: + DoScriptText(SAY_INTRO18, m_creature); + SetRun(true); + break; + case 8: + SetEscortPaused(true); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_pInstance->SetData(TYPE_INTRO, DONE); + SetRun(false); + break; + case 9: + DoScriptText(SAY_ENTER01, m_creature); + break; + case 10: + SetEscortPaused(true); + MoveSoldiers(); + m_pInstance->SetData(TYPE_PHASE, 2); + ResetStep(2000); + if (Unit* pCityman = m_pInstance->GetSingleCreatureFromStorage(NPC_CITY)) + { + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pCityman->GetObjectGuid()); + pCityman->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + pCityman->GetMotionMaster()->MovePoint(0, 2088.625f,1279.191f,140.743f); + } + break; + case 14: + if (Creature* pHuman01 = m_creature->SummonCreature(NPC_CITY,2397.308f,1207.565f,134.038f,5.593f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,30000)) + m_uiHuman01GUID = pHuman01->GetObjectGuid(); + if (Creature* pHuman02 = m_creature->SummonCreature(NPC_CITY,2400.770f,1207.362f,134.038f,3.454f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,30000)) + m_uiHuman02GUID = pHuman02->GetObjectGuid(); + if (Creature* pHuman03 = m_creature->SummonCreature(NPC_CITY,2400.547f,1204.892f,134.038f,2.479f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,30000)) + m_uiHuman03GUID = pHuman03->GetObjectGuid(); + break; + case 20: + SetEscortPaused(true); + m_creature->setFaction(35); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + SetRun(false); + break; + case 21: + DoScriptText(SAY_PHASE502, m_creature); + break; + case 22: + SetEscortPaused(true); + m_pInstance->SetData(TYPE_PHASE, 6); + ResetStep(1000); + break; + case 25: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H); + m_creature->SummonCreature(NPC_TIME_RIFT,2428.901f, 1192.164f, 148.076f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + DoScriptText(SAY_PHASE508, m_creature); + break; + case 26: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + DoScriptText(SAY_PHASE509, m_creature); 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->SEND_GOSSIP_MENU(TEXT_ID_ENTRANCE_1, pCreature->GetGUID()); + case 29: + m_creature->SummonCreature(NPC_TIME_RIFT,2413.773f, 1137.820f, 148.076f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_TIME_RIFT,2404.990f, 1175.121f, 148.076f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + DoScriptText(SAY_PHASE510, m_creature); + break; + case 30: + DoScriptText(SAY_PHASE513, m_creature); + break; + case 31: + ResetStep(1000); + m_pInstance->SetData(TYPE_PHASE, 7); + break; + case 32: + SetEscortPaused(true); + m_pInstance->SetData(TYPE_PHASE, 8); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + SetRun(false); + break; + case 36: + DoScriptText(SAY_PHASE514, m_creature); + break; + case 37: + if (GameObject* pGate = m_pInstance->GetSingleGameObjectFromStorage(GO_SHKAF_GATE)) + pGate->SetGoState(GO_STATE_ACTIVE); + SetRun(true); + DoScriptText(SAY_PHASE515, m_creature); + break; + case 45: + DoScriptText(SAY_PHASE601, m_creature); + break; + case 48: + DoScriptText(SAY_PHASE602, m_creature); + break; + case 51: + SetEscortPaused(true); + m_pInstance->SetData(TYPE_PHASE, 9); + DoScriptText(SAY_PHASE606, m_creature); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + case 53: + SetEscortPaused(true); + m_creature->StopMoving(); + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->setFaction(FACTION); + DoScriptText(SAY_PHASE605, m_creature); + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + { + m_pInstance->SetData(TYPE_MALGANIS, IN_PROGRESS); + pMalganis->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->AI()->AttackStart(pMalganis); + pMalganis->AI()->AttackStart(m_creature); + } break; } } - return true; -} -bool GossipSelect_npc_chromie(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 uiAction) -{ - switch (pCreature->GetEntry()) + void JumpNextStep(uint32 Timer) { - case NPC_CHROMIE_INN: - switch (uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INN_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN_2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INN_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN_3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN_4, pCreature->GetGUID()); - if (!pPlayer->HasItemCount(ITEM_ARCANE_DISRUPTOR, 1)) - { - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_ARCANE_DISRUPTOR, 1)) + m_uiStepTimer = Timer; + m_uiStep++; + } + + void ResetStep(uint32 Timer) + { + m_uiStep = 0; + m_uiStepTimer = Timer; + } + + void IntroEvent() + { + switch(m_uiStep) + { + case 0: + DoScriptText(SAY_INTRO01, m_creature); + JumpNextStep(2000); + break; + case 1: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + DoScriptText(SAY_INTRO02, pUther); + JumpNextStep(8000); + break; + case 2: + m_creature->SetWalk(true); + DoScriptText(SAY_INTRO03, m_creature); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 1908.334f, 1315.354f, 149.551f); + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + pUther->GetMotionMaster()->MovePoint(0, 1903.600f, 1296.678f, 143.383f); + JumpNextStep(2000); + break; + case 3: + if (Creature* pJaina = m_pInstance->GetSingleCreatureFromStorage(NPC_JAINA)) + pJaina->GetMotionMaster()->MovePoint(0, 1899.641f, 1298.684f, 143.831f); + JumpNextStep(7000); + break; + case 4: + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MovePoint(0, 1911.087f, 1314.263f, 150.026f); + JumpNextStep(1000); + break; + case 5: + DoScriptText(SAY_INTRO04, m_creature); + JumpNextStep(10000); + break; + case 6: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + DoScriptText(SAY_INTRO05, pUther); + JumpNextStep(1000); + break; + case 7: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pUther->GetObjectGuid()); + DoScriptText(SAY_INTRO06, m_creature); + JumpNextStep(4000); + break; + case 8: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + DoScriptText(SAY_INTRO07, pUther); + JumpNextStep(6000); + break; + case 9: + DoScriptText(SAY_INTRO08, m_creature); + JumpNextStep(4000); + break; + case 10: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + DoScriptText(SAY_INTRO09, pUther); + JumpNextStep(8000); + break; + case 11: + DoScriptText(SAY_INTRO10, m_creature); + JumpNextStep(4000); + break; + case 12: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + DoScriptText(SAY_INTRO11, pUther); + JumpNextStep(4000); + break; + case 13: + DoScriptText(SAY_INTRO12, m_creature); + JumpNextStep(11000); + break; + case 14: + if (Creature* pJaina = m_pInstance->GetSingleCreatureFromStorage(NPC_JAINA)) + DoScriptText(SAY_INTRO13, pJaina); + JumpNextStep(3000); + break; + case 15: + DoScriptText(SAY_INTRO14, m_creature); + JumpNextStep(9000); + break; + case 16: + if (Creature* pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + DoScriptText(SAY_INTRO15, pUther); + JumpNextStep(5000); + break; + case 17: + if (Creature* pJaina = m_pInstance->GetSingleCreatureFromStorage(NPC_JAINA)) + { + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pJaina->GetObjectGuid()); + pJaina->GetMotionMaster()->MovePoint(0, 1794.357f,1272.183f,140.558f); + } + JumpNextStep(1000); + break; + case 18: + DoScriptText(SAY_INTRO16, m_creature); + JumpNextStep(1000); + break; + case 19: + if (Creature* pJaina = m_pInstance->GetSingleCreatureFromStorage(NPC_JAINA)) + DoScriptText(SAY_INTRO17, pJaina); + JumpNextStep(3000); + break; + case 20: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + ((npc_arthasAI*)m_creature->AI())->Start(false); + JumpNextStep(3000); + break; + } + } + + void EnterEvent() + { + switch(m_uiStep) + { + case 0: + if (Unit* pCityman = m_pInstance->GetSingleCreatureFromStorage(NPC_CITY)) + DoScriptText(SAY_ENTER02, pCityman); + JumpNextStep(4000); + break; + case 1: + m_creature->GetMotionMaster()->MovePoint(0, 2087.689f,1280.344f,140.73f); + DoScriptText(SAY_ENTER03, m_creature); + JumpNextStep(3000); + break; + case 2: + if (Unit* pCityman = m_pInstance->GetSingleCreatureFromStorage(NPC_CITY)) + DoScriptText(SAY_ENTER04, pCityman); + m_creature->HandleEmoteCommand(37); + JumpNextStep(1000); + break; + case 3: + if (Unit* pCityman = m_pInstance->GetSingleCreatureFromStorage(NPC_CITY)) + m_creature->DealDamage(pCityman, pCityman->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (Unit* pCrazyman = m_pInstance->GetSingleCreatureFromStorage(NPC_CRAZYMAN)) + { + DoScriptText(SAY_ENTER05, pCrazyman); + pCrazyman->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pCrazyman->GetObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 2092.154f,1276.645f,140.52f); + } + JumpNextStep(3000); + break; + case 4: + m_creature->HandleEmoteCommand(37); + JumpNextStep(1000); + break; + case 5: + if (Unit* pCrazyman = m_pInstance->GetSingleCreatureFromStorage(NPC_CRAZYMAN)) + pCrazyman->DealDamage(pCrazyman, pCrazyman->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + JumpNextStep(1000); + break; + case 6: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 2091.179f,1278.065f,140.476f); + DoScriptText(SAY_ENTER06, m_creature); + JumpNextStep(3000); + break; + case 7: + if (Creature* pStalkerM = m_creature->SummonCreature(NPC_INVIS_STALKER,2117.349f,1288.624f,136.271f,1.37f,TEMPSUMMON_TIMED_DESPAWN,60000)) + pStalkerM->CastSpell(pStalkerM,63793,false); + JumpNextStep(1000); + break; + case 8: + m_pInstance->SetData(TYPE_ENCOUNTER, IN_PROGRESS); + if (Creature* pTempMalganis = m_creature->SummonCreature(NPC_MALGANIS,2117.349f,1288.624f,136.271f,1.37f,TEMPSUMMON_TIMED_DESPAWN,29000)) + { + m_uiMalganisGUID = pTempMalganis->GetObjectGuid(); + DoScriptText(SAY_ENTER07, pTempMalganis); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTempMalganis->GetObjectGuid()); + pTempMalganis->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + pTempMalganis->setFaction(35); + } + JumpNextStep(11000); + break; + case 9: + if (Unit* pTempMalganis = m_creature->GetMap()->GetUnit(m_uiMalganisGUID)) + DoScriptText(SAY_ENTER08, pTempMalganis); + JumpNextStep(17000); + break; + case 10: + DoScriptText(SAY_ENTER09, m_creature); + JumpNextStep(7000); + break; + case 11: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + DoScriptText(SAY_ENTER10, m_creature); + JumpNextStep(12000); + break; + case 12: + m_creature->GetMotionMaster()->MovePoint(0, 2084.584f,1278.331f,141.479f); + JumpNextStep(4000); + break; + case 13: + m_creature->GetMotionMaster()->MovePoint(0, 2087.414f,1279.293f,140.933f); + JumpNextStep(2000); + break; + case 14: + Last5X = m_creature->GetPositionX(); + Last5Y = m_creature->GetPositionY(); + Last5Z = m_creature->GetPositionZ(); + if (m_bIsHeroic) + m_pInstance->SetData(TYPE_BONUS, IN_PROGRESS); + m_uiWaveCount = 0; + SetRun(true); + m_pInstance->SetData(TYPE_WING, RIGHT); + m_creature->setFaction(FACTION); + m_uiSummonTimer = 100; + m_pInstance->SetData(TYPE_PHASE, 3); + break; + } + } + + void SummonWing() + { + m_uiWaveCount++; + m_pInstance->DoUpdateWorldState(WORLD_STATE_COS_WAVE_COUNT, m_uiWaveCount); + + switch(m_uiWaveCount) + { + case 1: + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 2: + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_FIEND,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 3: + m_pInstance->SetData(TYPE_WING, LEFT); + m_creature->SummonCreature(NPC_GHOUL,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_FIEND,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 4: + m_pInstance->SetData(TYPE_WING, RIGHT); + m_creature->SummonCreature(NPC_ACOLYTE,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_ACOLYTE,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_FIEND,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 5: + m_pInstance->SetData(TYPE_PHASE, 4); + if (Creature* pMeathook = m_creature->SummonCreature(NPC_MEATHOOK,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000)) + { + DoScriptText(SAY_MEATHOOK_SPAWN, pMeathook); + } + break; + case 6: + m_pInstance->SetData(TYPE_WING, LEFT); + m_creature->SummonCreature(NPC_GHOUL,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_FIEND,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_FIEND,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 7: + m_pInstance->SetData(TYPE_WING, RIGHT); + m_creature->SummonCreature(NPC_CONSTRUCT,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 8: + m_pInstance->SetData(TYPE_WING, LEFT); + m_creature->SummonCreature(NPC_CONSTRUCT,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2272.773f, 1331.824f, 124.171f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 9: + m_pInstance->SetData(TYPE_WING, RIGHT); + m_creature->SummonCreature(NPC_CONSTRUCT,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_FIEND,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_NECROMANCER,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + m_creature->SummonCreature(NPC_GHOUL,2340.058f, 1253.570f, 132.733f, 5.09f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000); + break; + case 10: + m_pInstance->SetData(TYPE_PHASE, 4); + if (Creature* pSalramm = m_creature->SummonCreature(NPC_SALRAMM,2196.036f, 1328.818f, 129.997f, 3.12f,TEMPSUMMON_CORPSE_TIMED_DESPAWN,29000)) + { + DoScriptText(SAY_SALRAMM_SPAWN, pSalramm); + } + break; + } + } + + void HouseEvent() + { + switch(m_uiStep) + { + case 0: + if (Creature* pHuman = m_pInstance->instance->GetCreature(m_uiHuman01GUID)) + { + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pHuman->GetObjectGuid()); + pHuman->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + DoScriptText(SAY_PHASE503, pHuman); + } + JumpNextStep(4000); + break; + case 1: + DoScriptText(SAY_PHASE504, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, 2396.035f, 1206.942f, 134.038f); + JumpNextStep(3000); + break; + case 2: + m_creature->HandleEmoteCommand(37); + JumpNextStep(2000); + break; + case 3: + DoScriptText(SAY_PHASE505, m_creature); + JumpNextStep(2000); + break; + case 4: + if (Creature* pHuman = m_pInstance->instance->GetCreature(m_uiHuman01GUID)) + DoScriptText(SAY_PHASE506, pHuman); + JumpNextStep(6000); + break; + case 5: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + if (Creature* pHuman = m_pInstance->instance->GetCreature(m_uiHuman01GUID)) + { + pHuman->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + pHuman->UpdateEntry(NPC_INFINITE_ADVERSARY); + } + if (Creature* pHuman2 = m_pInstance->instance->GetCreature(m_uiHuman02GUID)) + pHuman2->UpdateEntry(NPC_INFINITE_HUNTER); + if (Creature* pHuman3 = m_pInstance->instance->GetCreature(m_uiHuman03GUID)) + pHuman3->UpdateEntry(NPC_INFINITE_AGENT); + JumpNextStep(1000); + break; + case 6: + SetRun(true); + m_creature->GetMotionMaster()->MovePoint(0, 2384.320f, 1202.779f, 134.040f); + DoScriptText(SAY_PHASE507, m_creature); + JumpNextStep(5000); + break; + case 7: + SetEscortPaused(false); + m_creature->setFaction(FACTION); + m_pInstance->SetData(TYPE_PHASE, 5); + JumpNextStep(1000); + break; + } + } + + void EpochEvent() + { + switch(m_uiStep) + { + case 0: + m_creature->SummonCreature(NPC_TIME_RIFT_2,2445.629f,1111.500f,148.076f,3.229f,TEMPSUMMON_TIMED_DESPAWN,9000); + JumpNextStep(2000); + break; + case 1: + pEpoch = m_creature->SummonCreature(NPC_EPOCH,2445.629f,1111.500f,148.076f,3.229f,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,900000); + if (pEpoch) + { + pEpoch->setFaction(35); + DoScriptText(SAY_EPOCH_INTRO, pEpoch); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pEpoch->GetObjectGuid()); + } + JumpNextStep(20000); + break; + case 2: + DoScriptText(SAY_ARTHAS_INTRO, m_creature); + JumpNextStep(6000); + break; + case 3: + if (pEpoch) + { + DoScriptText(SAY_EPOCH_AGGRO, pEpoch); + m_creature->AI()->AttackStart(pEpoch); + pEpoch->AI()->AttackStart(m_creature); + pEpoch->setFaction(14); + } + m_pInstance->SetData(TYPE_PHASE, 5); + SetRun(false); + JumpNextStep(6000); + break; + } + } + + void MalganisEvent() + { + Map::PlayerList const &PlayerList = m_pInstance->instance->GetPlayers(); + bool bNeedSpawn = false; + + switch(m_uiStep) + { + case 0: + m_creature->setFaction(35); + m_creature->GetMotionMaster()->MovePoint(0, 2302.326f, 1491.386f, 128.362f); + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + { + DoScriptText(SAY_MALGANIS_ESCAPE01, Malganis); + pMalganis->InterruptNonMeleeSpells(false); + pMalganis->GetMotionMaster()->MovePoint(0, 2296.665f,1502.362f,128.362f); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, Malganis->GetObjectGuid()); + pMalganis->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + } + JumpNextStep(10000); + break; + case 1: + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + DoScriptText(SAY_MALGANIS_ESCAPE02, pMalganis); + JumpNextStep(10000); + break; + case 2: + DoScriptText(SAY_ARTHAS_OUTRO01, m_creature); + JumpNextStep(5000); + break; + case 3: + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + DoScriptText(SAY_MALGANIS_OUTRO, pMalganis); + JumpNextStep(20000); + break; + case 4: + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + { + Malganis->SetVisibility(VISIBILITY_OFF); + m_creature->GetMotionMaster()->MovePoint(0, pMalganis->GetPositionX(), pMalganis->GetPositionY(), pMalganis->GetPositionZ()); + } + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->SetWalk(false); + JumpNextStep(3000); + break; + case 5: + DoScriptText(SAY_ARTHAS_OUTRO02, m_creature); + JumpNextStep(6000); + break; + case 6: + m_creature->GetMotionMaster()->MovePoint(0, 2298.298f,1500.362f,128.362f); + DoScriptText(SAY_ARTHAS_OUTRO03, m_creature); + JumpNextStep(11000); + break; + case 7: + m_creature->GetMotionMaster()->MovePoint(0, 2243.311f, 1476.025f, 132.352f); + + if (!PlayerList.isEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (i->getSource()->GetQuestStatus(QUEST_A_ROYAL_ESCORT) == QUEST_STATUS_INCOMPLETE || + i->getSource()->GetQuestStatus(QUEST_A_ROYAL_ESCORT) == QUEST_STATUS_COMPLETE) { - pPlayer->SendNewItem(pItem, 1, true, false); - if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) - { - if (pInstance->GetData(TYPE_GRAIN_EVENT) == NOT_STARTED) - pInstance->SetData(TYPE_GRAIN_EVENT, SPECIAL); - } + bNeedSpawn = true; + break; } - } - break; + + if (bNeedSpawn) + m_creature->SummonCreature(NPC_CHROMI03, 2311.61f, 1497.85f, 128.01f, 4.14f, TEMPSUMMON_TIMED_DESPAWN, 1800000); + JumpNextStep(11000); + break; + case 8: + m_pInstance->SetData(TYPE_PHASE, 12); + m_creature->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + npc_escortAI::UpdateAI(uiDiff); + + if (!m_pInstance) return; + + if (StartEvent == true) + { + if (m_pInstance->GetData(TYPE_INTRO) != DONE) + { + if (m_uiStepTimer < uiDiff) + { + IntroEvent(); + } + else m_uiStepTimer -= uiDiff; + } + + if (m_pInstance->GetData(TYPE_PHASE) == 2) + { + if (m_uiStepTimer < uiDiff) + { + EnterEvent(); + } + else m_uiStepTimer -= uiDiff; + } + + if (m_pInstance->GetData(TYPE_PHASE) == 3) + { + if (m_uiSummonTimer < uiDiff) + { + SummonWing(); + m_uiSummonTimer = 70000; + } + else m_uiSummonTimer -= uiDiff; + } + + if (m_pInstance->GetData(TYPE_PHASE) == 4 && m_pInstance->GetData(TYPE_ENCOUNTER) == DONE) + { + m_pInstance->SetData(TYPE_PHASE, 5); + SetRun(true); + EnableEscort(); + DoScriptText(SAY_PHASE501, m_creature); + } + + if (m_pInstance->GetData(TYPE_PHASE) == 6) + { + if(m_uiStepTimer < uiDiff) + { + HouseEvent(); + } + else m_uiStepTimer -= uiDiff; + } + + if (m_pInstance->GetData(TYPE_PHASE) == 7) + { + if(m_uiStepTimer < uiDiff) + { + EpochEvent(); } - break; - case NPC_CHROMIE_ENTRANCE: - switch (uiAction) + else m_uiStepTimer -= uiDiff; + } + + } //close event! + + if (m_pInstance->GetData(TYPE_PHASE) == 10) + { + SetEscortPaused(true); + ResetStep(1000); + m_creature->AttackStop(); + m_pInstance->SetData(TYPE_PHASE, 11); + } + + if (m_pInstance->GetData(TYPE_PHASE) == 11) + { + if (m_uiStepTimer < uiDiff) { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ENTRANCE_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_ENTRANCE_2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ENTRANCE_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_ENTRANCE_3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_ENTRANCE_4, pCreature->GetGUID()); - if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) - { - if (pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == NOT_STARTED) - pInstance->DoSpawnArthasIfNeeded(); - } - break; + MalganisEvent(); } - break; + else m_uiStepTimer -= uiDiff; + } + + //} //close event! + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_pInstance->GetData(TYPE_PHASE) > 9) return; + + if (m_uiExorcismTimer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsHeroic ? SPELL_EXORCISM_H : SPELL_EXORCISM_N); + + m_uiExorcismTimer = 7300; + }else m_uiExorcismTimer -= uiDiff; + + if (m_uiHealTimer < uiDiff) + { + if (m_creature->GetHealthPercent() < 40.0f) + { + DoCast(m_creature, SPELL_HOLY_LIGHT); + m_uiHealTimer = 20000; + } + } else m_uiHealTimer -= uiDiff; + + return; } +}; + +/*### +## npc_uther +###*/ + +struct MANGOS_DLL_DECL npc_utherAI : public npc_escortAI +{ + npc_utherAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + bool StartEvent; + + ObjectGuid m_uiKnightGUID01; + ObjectGuid m_uiKnightGUID02; + ObjectGuid m_uiKnightGUID03; + + void Reset() + { + m_creature->SetVisibility(VISIBILITY_OFF); + m_uiStep = 0; + m_uiStepTimer = 100; + } + + void StartAI() + { + //m_pInstance->SetWeather(WEATHER_STATE_MEDIUM_RAIN, 0.9999f); + StartEvent = true; + m_creature->SetVisibility(VISIBILITY_ON); + ((npc_utherAI*)m_creature->AI())->Start(true); + + if (Creature* pKnight01 = m_creature->SummonCreature(NPC_KNIGHT,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,110000)) + { + m_uiKnightGUID01 = pKnight01->GetObjectGuid(); + pKnight01->SetWalk(false); + pKnight01->GetMotionMaster()->MoveFollow(m_creature,PET_FOLLOW_DIST,M_PI_F/2); + } + + if (Creature* pKnight02 = m_creature->SummonCreature(NPC_KNIGHT,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,110000)) + { + m_uiKnightGUID02 = pKnight02->GetObjectGuid(); + pKnight02->SetWalk(false); + pKnight02->GetMotionMaster()->MoveFollow(m_creature,PET_FOLLOW_DIST,M_PI_F/4); + } + + if (Creature* pKnight03 = m_creature->SummonCreature(NPC_KNIGHT,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,110000)) + { + m_uiKnightGUID03 = pKnight03->GetObjectGuid(); + pKnight03->SetWalk(false); + pKnight03->GetMotionMaster()->MoveFollow(m_creature,PET_FOLLOW_DIST,M_PI_F/3); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch(uiPointId) + { + case 3: + if (Creature* pArthas = m_pInstance->GetSingleCreatureFromStorage(NPC_ARTHAS)) + { + pArthas->SetWalk(false); + pArthas->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + pArthas->GetMotionMaster()->MovePoint(0, 1902.974f, 1291.635f, 143.337f); + } + break; + case 4: + SetRun(false); + if (Creature *pArthas = m_pInstance->GetSingleCreatureFromStorage(NPC_ARTHAS)) + ((npc_arthasAI*)pArthas->AI())->StartAI(); + break; + case 6: + m_creature->SetVisibility(VISIBILITY_OFF); + if (Creature* pJaina = m_pInstance->GetSingleCreatureFromStorage(NPC_JAINA)) + pJaina->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + npc_escortAI::UpdateAI(uiDiff); + + if (!m_pInstance) return; + + return; + } +}; + +/*### +## npc_chromi_middle +###*/ + +#define GOSSIP_ITEM_CHROMI1 "What do you think they're up to?" +#define GOSSIP_ITEM_CHROMI2 "What want me to do what?" +#define GOSSIP_ITEM_CHROMI3 "Very well, Chromie." + +enum +{ + QUEST_ROYAL_ESCORT = 13151, + GOSSIP_TEXTID_CHROMI1 = 12953, + GOSSIP_TEXTID_CHROMI2 = 12949, + GOSSIP_TEXTID_CHROMI3 = 12950, + GOSSIP_TEXTID_CHROMI4 = 12952 +}; + +bool GossipHello_npc_chromi_middle(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + //if (pPlayer->GetQuestStatus(QUEST_DISPELLING_ILLUSIONS) == QUEST_STATUS_INCOMPLETE) + //return false; + + ScriptedInstance* pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + if (pInstance && pInstance->GetData(TYPE_INTRO) == NOT_STARTED) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CHROMI1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_CHROMI1, pCreature->GetObjectGuid()); + return true; } -bool QuestAccept_npc_chromie(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool GossipSelect_npc_chromi_middle(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) { - switch (pQuest->GetQuestId()) + if (ScriptedInstance* m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData())) + if (m_pInstance->GetData(TYPE_INTRO) != NOT_STARTED) return true; + + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) { - case QUEST_DISPELLING_ILLUSIONS: - if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) - { - if (pInstance->GetData(TYPE_GRAIN_EVENT) == NOT_STARTED) - pInstance->SetData(TYPE_GRAIN_EVENT, SPECIAL); - } - break; - case QUEST_A_ROYAL_ESCORT: - if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) - { - if (pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == NOT_STARTED) - pInstance->DoSpawnArthasIfNeeded(); - } - break; + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CHROMI2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_CHROMI2, pCreature->GetObjectGuid()); + } + + if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CHROMI3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_CHROMI3, pCreature->GetObjectGuid()); } + + if (uiAction == GOSSIP_ACTION_INFO_DEF+3) + { + if (ScriptedInstance* m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData())) + { + m_pInstance->DoUpdateWorldState(WORLD_STATE_COS_CRATE_ON, 0); + m_pInstance->SetData(TYPE_INTRO, IN_PROGRESS); + if (Creature *pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + ((npc_utherAI*)pUther->AI())->StartAI(); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_CHROMI4, pCreature->GetObjectGuid()); + } + return true; } -/* ************* -** npc_crates_bunny (spell aura effect dummy) -************* */ +struct MANGOS_DLL_DECL npc_chromi_middleAI : public ScriptedAI +{ + npc_chromi_middleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + m_bUtherHere = false; + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bUtherHere; + + void Reset() + { + m_bUtherHere = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bUtherHere && m_pInstance && pWho && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance2d(pWho) <= 15 && ((Player*)pWho)->GetQuestStatus(QUEST_A_ROYAL_ESCORT) == QUEST_STATUS_INCOMPLETE) + { + m_pInstance->DoUpdateWorldState(WORLD_STATE_COS_CRATE_ON, 0); + m_pInstance->SetData(TYPE_INTRO, IN_PROGRESS); + if (Creature *pUther = m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER)) + ((npc_utherAI*)pUther->AI())->StartAI(); + m_bUtherHere = true; + } + } +}; + +/*### +## npc_arthas_dialog +###*/ enum { - SPELL_ARCANE_DISRUPTION = 49590 + GOSSIP_MENU_ARTHAS_1 = 100001, + GOSSIP_MENU_ARTHAS_2 = 100002, + GOSSIP_MENU_ARTHAS_3 = 100003, + GOSSIP_MENU_ARTHAS_4 = 100004, + GOSSIP_MENU_ARTHAS_5 = 100005 }; -bool EffectAuraDummy_spell_aura_dummy_npc_crates_dummy(const Aura* pAura, bool bApply) +#define GOSSIP_ITEM_ARTHAS_0 "I'm ready to start Culling of Stratholme." +#define GOSSIP_ITEM_ARTHAS_1 "Yes, my Prince. We're ready." +#define GOSSIP_ITEM_ARTHAS_2 "We're only doing what is best for Loarderon your Highness." +#define GOSSIP_ITEM_ARTHAS_3 "I'm ready." +#define GOSSIP_ITEM_ARTHAS_4 "For Lordaeron!" +#define GOSSIP_ITEM_ARTHAS_5 "I'm ready to battle the dreadlord, sire." + +bool GossipHello_npc_arthas(Player* pPlayer, Creature* pCreature) { - if (pAura->GetId() == SPELL_ARCANE_DISRUPTION && pAura->GetEffIndex() == EFFECT_INDEX_0 && bApply) + ScriptedInstance* pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + + if (pInstance && pInstance->GetData(TYPE_PHASE) == 0) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ARTHAS_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ARTHAS_1, pCreature->GetObjectGuid()); + } + + if (pInstance && pInstance->GetData(TYPE_PHASE) == 5) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ARTHAS_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ARTHAS_2, pCreature->GetObjectGuid()); + } + + if (pInstance && pInstance->GetData(TYPE_PHASE) == 8) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ARTHAS_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ARTHAS_3, pCreature->GetObjectGuid()); + } + + if (pInstance && pInstance->GetData(TYPE_PHASE) == 9) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ARTHAS_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ARTHAS_4, pCreature->GetObjectGuid()); + } + + return true; +} + +bool GossipSelect_npc_arthas(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + ScriptedInstance* m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + + if (m_pInstance && m_pInstance->GetData(TYPE_PHASE) == 0) + { + m_pInstance->SetData(TYPE_PHASE, 1); + ((npc_arthasAI*)pCreature->AI())->EnableEscort(); + ((npc_arthasAI*)pCreature->AI())->RemoveGossip(); + ((npc_arthasAI*)pCreature->AI())->culling_faction = pPlayer->getFaction(); + } + + if (m_pInstance && m_pInstance->GetData(TYPE_PHASE) == 5) + { + ((npc_arthasAI*)pCreature->AI())->EnableEscort(); + ((npc_arthasAI*)pCreature->AI())->RemoveGossip(); + } + + if (m_pInstance && m_pInstance->GetData(TYPE_PHASE) == 8) + { + ((npc_arthasAI*)pCreature->AI())->EnableEscort(); + ((npc_arthasAI*)pCreature->AI())->RemoveGossip(); + } + + if (m_pInstance && m_pInstance->GetData(TYPE_PHASE) == 9) + { + ((npc_arthasAI*)pCreature->AI())->EnableEscort(); + ((npc_arthasAI*)pCreature->AI())->RemoveGossip(); + if (Creature* pMalganis = pCreature->SummonCreature(NPC_MALGANIS,2296.665f,1502.362f,128.362f,4.961f,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,900000)) + { + pMalganis->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + return true; +} + +/*### +## npc_arthas_priest +###*/ + +struct MANGOS_DLL_DECL npc_arthas_priestAI : public ScriptedAI +{ + npc_arthas_priestAI(Creature *c) : ScriptedAI(c) + { + SetCombatMovement(false); + Reset(); + } + + uint32 m_uiSmiteTimer; + uint32 m_uiHealTimer; + + void Reset() + { + m_uiSmiteTimer = 100; + m_uiHealTimer = 1000; + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MoveInLineOfSight(Unit* pWho) override { - if (Creature* pTarget = (Creature*)pAura->GetTarget()) + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && pWho->isTargetableForAttack() && + m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) { - std::list lCrateBunnyList; - if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pTarget->GetInstanceData()) + 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)) { - pInstance->GetCratesBunnyOrderedList(lCrateBunnyList); - uint8 i = 0; - for (std::list::const_iterator itr = lCrateBunnyList.begin(); itr != lCrateBunnyList.end(); ++itr) + if (!m_creature->getVictim()) { - i++; - if (*itr == pTarget) - break; + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); } - - switch (i) - { - case 1: - // Start NPC_ROGER_OWENS Event - break; - case 2: - // Start NPC_SERGEANT_MORIGAN Event - break; - case 3: - // Start NPC_JENA_ANDERSON Event - break; - case 4: - // Start NPC_MALCOM_MOORE Event - break; - case 5: - // Start NPC_BARTLEBY_BATTSON Event - break; + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSmiteTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SMITE); + m_uiSmiteTimer = 3000; + } + else m_uiSmiteTimer -= uiDiff; + + if (m_uiHealTimer < uiDiff) + { + if (m_creature->GetHealthPercent() <= 40.0f) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_HEAL); + m_uiHealTimer = 3000; + } + } + else m_uiHealTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return; + } +}; + +/*### +## npc_arthas_marine +###*/ + +struct MANGOS_DLL_DECL npc_arthas_marineAI : public ScriptedAI +{ + npc_arthas_marineAI(Creature *c) : ScriptedAI(c) + { + Reset(); + } + + uint32 m_uiHealTimer; + uint32 m_uiHeroicTimer; + uint32 m_uiDefendTimer; + + void Reset() + { + m_uiHealTimer = 3000; + m_uiHeroicTimer = 7000; + m_uiDefendTimer = 9000; + } + + void Aggro(Unit* who) + { + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (IsCombatMovement()) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + + m_creature->SetLootRecipient(NULL); - if (pInstance->GetData(TYPE_GRAIN_EVENT) != DONE) - pInstance->SetData(TYPE_GRAIN_EVENT, IN_PROGRESS); - // 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 + if (m_creature->GetEntry() == NPC_MARINE_1) + m_creature->GetMotionMaster()->MovePoint(POINT_LAST_POINT, Last1X, Last1Y, Last1Z); + if (m_creature->GetEntry() == NPC_MARINE_2) + m_creature->GetMotionMaster()->MovePoint(POINT_LAST_POINT, Last2X, Last2Y, Last2Z); + if (m_creature->GetEntry() == NPC_MARINE_3) + m_creature->GetMotionMaster()->MovePoint(POINT_LAST_POINT, Last3X, Last3Y, Last3Z); + if (m_creature->GetEntry() == NPC_MARINE_4) + m_creature->GetMotionMaster()->MovePoint(POINT_LAST_POINT, Last4X, Last4Y, Last4Z); + + Reset(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } } } } - return true; + + void UpdateAI(const uint32 uiDiff) override + { + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHealTimer < uiDiff) + { + if (m_creature->GetHealthPercent() <= 40.0f) + { + if (Creature* pHeal = GetClosestCreatureWithEntry(m_creature, NPC_PRIEST_1, 70.0f)) + { + if (pHeal->GetHealthPercent() > 40.0f) + { + pHeal->InterruptNonMeleeSpells(false); + pHeal->CastSpell(m_creature, SPELL_HEAL, false); + m_uiHealTimer = 3000; + } + } + else if (Creature* pHeal2 = GetClosestCreatureWithEntry(m_creature, NPC_PRIEST_2, 70.0f)) + { + if (pHeal2->GetHealthPercent() > 40.0f) + { + pHeal2->InterruptNonMeleeSpells(false); + pHeal2->CastSpell(m_creature, SPELL_HEAL, false); + m_uiHealTimer = 3000; + } + } + } + } + else m_uiHealTimer -= uiDiff; + + if (m_uiHeroicTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_HEROIC_STRIKE); + m_uiHeroicTimer = 7000; + } + else m_uiHeroicTimer -= uiDiff; + + if (m_uiDefendTimer < uiDiff) + { + DoCast(m_creature, SPELL_DEFEND); + m_uiDefendTimer = 9000; + } + else m_uiDefendTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return; + } +}; + +/*### +## npc_dark_conversion +###*/ + +/*enum +{ + SAY_PEOPLE01 = -1594099, + SAY_PEOPLE02 = -1594100, + SAY_PEOPLE03 = -1594101, + SAY_PEOPLE04 = -1594102, + SAY_PEOPLE05 = -1594103, +};*/ + +struct MANGOS_DLL_DECL npc_dark_conversionAI : public ScriptedAI +{ + npc_dark_conversionAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + + if (m_pInstance && m_pInstance->GetData(TYPE_ENCOUNTER) == IN_PROGRESS) + m_creature->UpdateEntry(NPC_ZOMBIE); + + Reset(); + } + +ScriptedInstance* m_pInstance; + +bool Special; +bool Conversion; +uint32 m_uiStep; +uint32 m_uiStepTimer; + + void Reset() + { + m_creature->setFaction(35); + Conversion = false; + Special = false; + m_uiStep = 1; + m_uiStepTimer = 5000; + + if (m_pInstance && m_pInstance->GetData(TYPE_ENCOUNTER) == IN_PROGRESS) + m_creature->UpdateEntry(NPC_ZOMBIE); + } + + void MalganisScared(Creature* target, float horizontalSpeed, float verticalSpeed) + { + float angle = target->GetAngle(m_creature); + float vsin = sin(angle); + float vcos = cos(angle); + + float ox, oy, oz; + m_creature->GetPosition(ox, oy, oz); + + float g = 19.23f;// seems that physic constant g(earth's gravity) in world of warcraft is about 2 times larger than real + float dh = verticalSpeed*verticalSpeed / (2*g); // maximum parabola height + float time = sqrtf(dh/(0.124976 * verticalSpeed)); //full move time in seconds // should be time = 2*Vert_speed/g, but.. + + float dis = time * horizontalSpeed; + float fx = ox + dis * vcos; + float fy = oy + dis * vsin; + float fz = oz; + + m_creature->UpdateGroundPositionZ(fx, fy, fz); + + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(0, fx, fy, fz); + } + + void DarkConversion(bool Move) + { + m_creature->UpdateEntry(NPC_ZOMBIE); + if(Move == true) + { + if(Creature* pArthas = m_pInstance->GetSingleCreatureFromStorage(NPC_ARTHAS)) + m_creature->GetMotionMaster()->MovePoint(0, pArthas->GetPositionX(), pArthas->GetPositionY(), pArthas->GetPositionZ()); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) return; + + if (m_pInstance->GetData(TYPE_ENCOUNTER) == IN_PROGRESS) + { + if (Creature* pMalganis = GetClosestCreatureWithEntry(m_creature, NPC_MALGANIS, 20.0f)) + { + if (Special == false) + { + float Dist = m_creature->GetDistance2d(pMalganis->GetPositionX(), pMalganis->GetPositionY()); + Dist = Dist + 2.0f; + MalganisScared(pMalganis, Dist, 1.0f); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); + m_uiStepTimer = 5000; + Special = true; + } + } + + if (m_uiStepTimer < uiDiff && Conversion != true) + { + Conversion = true; + if (Special != false) + DarkConversion(true); + else + DarkConversion(false); + } + else m_uiStepTimer -= uiDiff; + + } + + DoMeleeAttackIfReady(); + + return; + } +}; + +CreatureAI* GetAI_npc_chromi_middle(Creature* pCreature) +{ + return new npc_chromi_middleAI(pCreature); +} + +CreatureAI* GetAI_npc_uther(Creature* pCreature) +{ + return new npc_utherAI(pCreature); +} + +CreatureAI* GetAI_npc_arthas(Creature* pCreature) +{ + return new npc_arthasAI(pCreature); +} + +CreatureAI* GetAI_npc_arthas_priest(Creature* pCreature) +{ + return new npc_arthas_priestAI(pCreature); +} + +CreatureAI* GetAI_npc_arthas_marine(Creature* pCreature) +{ + return new npc_arthas_marineAI(pCreature); +} + +CreatureAI* GetAI_npc_dark_conversion(Creature* pCreature) +{ + return new npc_dark_conversionAI(pCreature); } void AddSC_culling_of_stratholme() { - Script* pNewScript; + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_chromi_middle"; + pNewScript->pGossipHello = &GossipHello_npc_chromi_middle; + pNewScript->pGossipSelect = &GossipSelect_npc_chromi_middle; + pNewScript->GetAI = &GetAI_npc_chromi_middle; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_uther"; + pNewScript->GetAI = &GetAI_npc_uther; + 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_arthas_priest"; + pNewScript->GetAI = &GetAI_npc_arthas_priest; + pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_chromie"; - pNewScript->pGossipHello = &GossipHello_npc_chromie; - pNewScript->pGossipSelect = &GossipSelect_npc_chromie; - pNewScript->pQuestAccept = &QuestAccept_npc_chromie; + pNewScript->Name = "npc_arthas_marine"; + pNewScript->GetAI = &GetAI_npc_arthas_marine; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "spell_dummy_npc_crates_bunny"; - pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_npc_crates_dummy; + pNewScript->Name = "npc_dark_conversion"; + pNewScript->GetAI = &GetAI_npc_dark_conversion; 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 766a92f983..ba6a15f924 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,194 +1,144 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ #ifndef DEF_CULLING_OF_STRATHOLME_H -#define DEF_CULLING_OF_STRATHOLME_H +#define DEF_CULLING_OF_STRATHOLME_H -enum +enum Data { - MAX_ENCOUNTER = 9, - - 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, - - // 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_LORDAERON_CRIER = 27913, - NPC_ZOMBIE = 27737, - - // Inn Event related NPC - NPC_MICHAEL_BELFAST = 30571, - NPC_HEARTHSINGER_FORRESTEN = 30551, - NPC_FRAS_SIABI = 30552, - NPC_FOOTMAN_JAMES = 30553, - NPC_MAL_CORRICKS = 31017, - NPC_GRYAN_STOUTMANTLE = 30561, - - // Grain Event NPCs - NPC_ROGER_OWENS = 27903, - NPC_SERGEANT_MORIGAN = 27877, - NPC_JENA_ANDERSON = 27885, - NPC_MALCOM_MOORE = 27891, // Not (yet?) spawned - NPC_BARTLEBY_BATTSON = 27907, - NPC_CRATES_BUNNY = 30996, - - // Intro Event NPCs - NPC_LORDAERON_FOOTMAN = 27745, - NPC_STRATHOLME_CITIZEN = 28167, - NPC_STRATHOLME_RESIDENT = 28169, - - // Mobs in Stratholme (to despawn) -- only here for sake of completeness handling remains open (mangos feature) + TYPE_QUEST = 1, + TYPE_INTRO = 2, + TYPE_CRATES_COUNT = 3, + TYPE_PHASE = 4, + TYPE_ENCOUNTER = 5, + TYPE_WAVE_COUNT = 6, + TYPE_WING = 7, + TYPE_BONUS = 8, + TYPE_MALGANIS = 9, + MAX_ENCOUNTERS, + + DATA_TEMPSUMMON = 10, + +///-> First quest stuff for CoS + QUEST_DISPELLING_ILLUSIONS = 13149, + + NPC_CRATE_KC_BUNNY = 30996, + NPC_CHROMI01 = 26527, + NPC_MIKE = 30571, + NPC_MAL_CORICS = 31017, + NPC_GRIAN_STONE = 30561, + NPC_JAMES = 30553, + NPC_FRAS_FRASIABI = 30552, + NPC_FORRESTER = 30551, + NPC_ROGER = 27903, + NPC_MORIGAN = 27877, + NPC_PERELLI = 27876, + NPC_JENA = 27885, + NPC_MARTHA = 27884, + NPC_MALCOLM = 27891, + NPC_DOG = 27892, + NPC_BARTLEBY = 27907, + + SPELL_ARCANE_DISRUPTION = 49590, + SPELL_CRATES_KILL_CREDIT = 58109, + + ITEM_ARCANE_DISRUPTOR = 37888, + GO_CRATE_LIGHT = 190117, + + WORLD_STATE_COS_CRATE_ON = 3479, + WORLD_STATE_COS_CRATE_COUNT = 3480, +///-> end + +///-> Second Quest stuff + QUEST_A_ROYAL_ESCORT = 13151, + + NPC_MARINE_1 = 10, + NPC_MARINE_2 = 11, + NPC_MARINE_3 = 12, + NPC_MARINE_4 = 13, + NPC_PRIEST_1 = 14, + NPC_PRIEST_2 = 15, + NPC_ARTHAS = 26499, + NPC_JAINA = 26497, + NPC_UTHER = 26528, + NPC_KNIGHT = 28612, + NPC_CHROMI02 = 27915, + NPC_CITY = 28167, + NPC_CRAZYMAN = 28169, + NPC_INVIS_STALKER = 20562, + WORLD_STATE_COS_WAVE_COUNT = 3504, + + MALGANIS_KC_BUNNY = 31006, + +///-> end + + NPC_CHROMI03 = 30997, + + NPC_INFINITE_ADVERSARY = 27742, + NPC_INFINITE_HUNTER = 27743, + NPC_INFINITE_AGENT = 27744, + NPC_TIME_RIFT = 28409, + NPC_TIME_RIFT_2 = 28439, + NPC_ZOMBIE = 27737, + NPC_GHOUL = 28249, + NPC_NECROMANCER = 28200, + NPC_STALKER = 28199, ///->??? might be typo for invis_stalker + NPC_FIEND = 27734, + NPC_GOLEM = 28201, + NPC_EGHOUL = 27729, + NPC_CONSTRUCT = 27736, + NPC_ACOLYTE = 27731, + NPC_MEATHOOK = 26529, + NPC_SALRAMM = 26530, + NPC_EPOCH = 26532, + NPC_MALGANIS = 26533, + NPC_INFINITE_CORRUPTOR = 32273, + + GO_SHKAF_GATE = 188686, + GO_MALGANIS_GATE1 = 187711, + GO_MALGANIS_GATE2 = 187723, + GO_MALGANIS_CHEST = 190663, + GO_MALGANIS_CHEST_H = 193597, + GO_EXIT = 191788, + + + WORLD_STATE_COS_TIME_ON = 3932, + WORLD_STATE_COS_TIME_COUNT = 3931, + NPC_MAGISTRATE_BARTHILAS = 30994, NPC_STEPHANIE_SINDREE = 31019, NPC_LEEKA_TURNER = 31027, NPC_SOPHIE_AAREN = 31021, NPC_ROBERT_PIERCE = 31025, NPC_GEORGE_GOODMAN = 31022, - - // Others NPCs in Stratholme + NPC_EMERY_NEILL = 30570, NPC_EDWARD_ORRICK = 31018, NPC_OLIVIA_ZENITH = 31020, - // Townhall Event NPCs - NPC_AGIATED_STRATHOLME_CITIZEN = 31126, - NPC_AGIATED_STRATHOLME_RESIDENT = 31127, - NPC_PATRICIA_O_REILLY = 31028, - - // Gameobjects - GO_DOOR_BOOKCASE = 188686, - GO_DARK_RUNED_CHEST = 190663, - GO_DARK_RUNED_CHEST_H = 193597, - - // World States - WORLD_STATE_CRATES = 3479, - WORLD_STATE_CRATES_COUNT = 3480, - WORLD_STATE_WAVE = 3504, - WORLD_STATE_TIME = 3932, - WORLD_STATE_TIME_COUNTER = 3931, - - // Areatrigger - AREATRIGGER_INN = 5291, - /* - 5085 before bridge - could be Uther SpawnPos - 5148 ini entrance - 5181 ini exit - 5249 fras siabis store - 5250 leeking shields...(store) - 5251 bar in stratholme - 5252 Aaren flowers - 5253 Angelicas boutique - 5256 townhall - 5291 Inn */ -}; - -enum eInstancePosition -{ - POS_ARTHAS_INTRO = 1, - POS_ARTHAS_WAVES = 2, - POS_ARTHAS_TOWNHALL = 3, - POS_ARTHAS_ESCORTING = 4, - POS_ARTHAS_MALGANIS = 5, - POS_INSTANCE_FINISHED = 6 -}; - -class MANGOS_DLL_DECL instance_culling_of_stratholme : public ScriptedInstance -{ - public: - instance_culling_of_stratholme(Map* pMap); - ~instance_culling_of_stratholme() {} - - void Initialize(); - - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); - - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiData); - - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); - - void Update(uint32 uiDiff); - - void GetStratAgiatedCitizenList(std::list &lList){ lList = m_lAgiatedCitizenGUIDList; }; - void GetStratAgiatedResidentList(std::list &lList){ lList = m_lAgiatedResidentGUIDList; }; - - void GetCratesBunnyOrderedList(std::list &lList); - Creature* GetStratIntroFootman(); - void GetResidentOrderedList(std::list &lList); - void DoSpawnArthasIfNeeded(); - void DoSpawnChromieIfNeeded(); - uint8 GetInstancePosition(); - void ArthasJustDied(); - - protected: - void OnPlayerEnter(Player* pPlayer); - Player* GetPlayerInMap(); - void UpdateQuestCredit(); - void DoChromieHurrySpeech(); - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint8 m_uiGrainCrateCount; - uint32 m_uiRemoveCrateStateTimer; - uint32 m_uiArthasRespawnTimer; - - uint64 m_uiChromieInnGUID; - uint64 m_uiChromieEntranceGUID; - uint64 m_uiChromieEndGUID; - uint64 m_uiHourglassGUID; - uint64 m_uiArthasGUID; - uint64 m_uiMeathookGUID; - uint64 m_uiSalrammGUID; - uint64 m_uiEpochGUID; - uint64 m_uiMalganisGUID; - uint64 m_uiCorrupterGUID; - uint64 m_uiLordaeronCrierGUID; - - uint64 m_uiBelfastGUID; - uint64 m_uiForrestenGUID; - uint64 m_uiSiabiGUID; - uint64 m_uiJamesGUID; - uint64 m_uiCorricksGUID; - uint64 m_uiStoutmantleGUID; - - uint64 m_uiOwensGUID; - uint64 m_uiMoriganGUID; - uint64 m_uiAndersonGUID; - uint64 m_uiMooreGUID; - uint64 m_uiBattsonGUID; - - uint64 m_uiOReillyGUID; - - std::list m_luiCratesBunnyGUIDs; - std::list m_luiFootmanGUIDs; - std::list m_luiResidentGUIDs; - - std::list m_lAgiatedCitizenGUIDList; - std::list m_lAgiatedResidentGUIDList; - - uint64 m_uiDoorBookcaseGUID; - uint64 m_uiDarkRunedChestGUID; + RIGHT = 1, + LEFT = 2 }; #endif diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholmeai.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholmeai.cpp new file mode 100644 index 0000000000..7d412edfb2 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholmeai.cpp @@ -0,0 +1,1176 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" +#include "escort_ai.h" +#include "WorldPacket.h" + +/*### +## npc_chromi_start +###*/ + +struct MANGOS_DLL_DECL npc_chromi_startAI : public ScriptedAI +{ + npc_chromi_startAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + m_bCounterHere = false; + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bCounterHere; + + void Reset() + { + m_bCounterHere = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bCounterHere && m_pInstance && pWho && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance2d(pWho) <= 15 && ((Player*)pWho)->GetQuestStatus(QUEST_DISPELLING_ILLUSIONS) == QUEST_STATUS_INCOMPLETE) + { + m_pInstance->DoUpdateWorldState(WORLD_STATE_COS_CRATE_ON, 1); + m_pInstance->SetData(TYPE_QUEST, IN_PROGRESS); + m_bCounterHere = true; + } + } +}; + +/*### +## npc_mike +###*/ + +enum +{ + SAY_MIKE01 = -1597270, + SAY_FORRESTER02 = -1597271, + SAY_JAMES03 = -1597272, + SAY_SIABI04 = -1597273, + SAY_MIKE05 = -1597274, + SAY_CORICKS06 = -1597275, + SAY_GRIAN07 = -1597276, + SAY_CORICKS08 = -1597277, + SAY_JAMES09 = -1597278, + SAY_FORRESTER10 = -1597279, + + EMOTE_SHOT = 5, + EMOTE_TALK = 1, + EMOTE_POINT = 25, + EMOTE_NO = 274, + EMOTE_LAUGH = 11 +}; + +struct MANGOS_DLL_DECL npc_mikeAI : public ScriptedAI +{ + npc_mikeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiPhase; + + void Reset() + { + if (m_uiPhase != 2) + { + m_uiStep = 0; + m_uiStepTimer = 100; + m_uiPhase = 0; + } + } + + void MoveInLineOfSight(Unit* who) override + { + if (!who) + return; + + if (!m_pInstance) return; + + if (who->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance2d(who) <= 15 && who->GetPositionZ() > 99.50f && m_uiPhase == 0) + { + m_creature->SetGuidValue(UNIT_FIELD_TARGET, who->GetObjectGuid()); + m_uiPhase = 1; + } + } + + void TavernEvent() + { + switch(m_uiStep) + { + case 0: + DoScriptText(SAY_MIKE01, m_creature); + m_uiStepTimer = 4000; + break; + case 1: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_uiStepTimer = 5000; + break; + case 2: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_FORRESTER)) + DoScriptText(SAY_FORRESTER02, pTemp); + m_uiStepTimer = 6000; + break; + case 3: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JAMES)) + DoScriptText(SAY_JAMES03, pTemp); + m_uiStepTimer = 5000; + break; + case 4: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_FRAS_FRASIABI)) + DoScriptText(SAY_SIABI04, pTemp); + m_uiStepTimer = 2000; + break; + case 5: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_FRAS_FRASIABI)) + pTemp->HandleEmoteCommand(EMOTE_SHOT); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiStepTimer = 5000; + break; + case 6: + m_creature->GetMotionMaster()->MovePoint(0, 1554.849f, 588.465f, 99.775f); + m_uiStepTimer = 3000; + break; + case 7: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_FRAS_FRASIABI)) + pTemp->HandleEmoteCommand(EMOTE_LAUGH); + m_uiStepTimer = 3000; + break; + case 8: + DoScriptText(SAY_MIKE05, m_creature); + m_uiStepTimer = 2000; + break; + case 9: + m_creature->HandleEmoteCommand(EMOTE_SHOT); + m_uiStepTimer = 1000; + break; + case 10: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MAL_CORICS)) + DoScriptText(SAY_CORICKS06, pTemp); + m_uiStepTimer = 4000; + break; + case 11: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MAL_CORICS)) + pTemp->HandleEmoteCommand(EMOTE_TALK); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_GRIAN_STONE)) + DoScriptText(SAY_GRIAN07, pTemp); + m_uiStepTimer = 11000; + break; + case 12: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MAL_CORICS)) + DoScriptText(SAY_CORICKS08, pTemp); + m_creature->GetMotionMaster()->MovePoint(0, 1549.609f, 575.544f, 100.052f); + m_uiStepTimer = 2000; + break; + case 13: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JAMES)) + DoScriptText(SAY_JAMES09, pTemp); + m_uiStepTimer = 2000; + break; + case 14: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JAMES)) + pTemp->HandleEmoteCommand(EMOTE_TALK); + m_uiStepTimer = 5000; + break; + case 15: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_FORRESTER)) + DoScriptText(SAY_FORRESTER10, pTemp); + m_uiPhase = 2; + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase == 1) + { + if (m_uiStepTimer < uiDiff) + { + TavernEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + return; + } +}; + +/*### +## npc_roger +###*/ + +enum +{ + SAY_ROGER01 = -1597280, + SAY_ROGER02 = -1597281, + SAY_ROGER03 = -1597282, + SAY_ROGER04 = -1597283, +}; + +struct MANGOS_DLL_DECL npc_rogerAI : public ScriptedAI +{ + npc_rogerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiPhase; + + void Reset() + { + if (m_uiPhase != 2) + { + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiStep = 0; + m_uiStepTimer = 100; + m_uiPhase = 0; + } + } + + void StartRoger() + { + m_uiPhase = 1; + } + + void FirstCrateEvent() + { + switch(m_uiStep) + { + case 0: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiStepTimer = 7000; + break; + case 1: + m_creature->GetMotionMaster()->MovePoint(0, 1590.055f, 615.727f, 99.795f); + m_uiStepTimer = 6900; + break; + case 2: + m_creature->GetMotionMaster()->MovePoint(0, 1584.039f, 622.049f, 99.907f); + m_uiStepTimer = 3900; + break; + case 3: + m_creature->GetMotionMaster()->MovePoint(0, 1578.787f, 623.924f, 99.855f); + m_uiStepTimer = 2500; + break; + case 4: + DoScriptText(SAY_ROGER01, m_creature); + m_uiStepTimer = 6000; + break; + case 5: + m_creature->GetMotionMaster()->MovePoint(0, 1579.393f, 624.018f, 99.886f); + m_uiStepTimer = 2000; + break; + case 6: + DoScriptText(SAY_ROGER02, m_creature); + m_uiStepTimer = 6000; + break; + case 7: + m_creature->GetMotionMaster()->MovePoint(0, 1579.387f, 623.198f, 99.837f); + m_uiStepTimer = 1000; + break; + case 8: + DoScriptText(SAY_ROGER03, m_creature); + m_uiStepTimer = 4000; + break; + case 9: + m_creature->GetMotionMaster()->MovePoint(0, 1575.576f, 619.935f, 99.422f); + m_uiStepTimer = 2000; + break; + case 10: + m_creature->GetMotionMaster()->MovePoint(0, 1575.833f, 620.471f, 99.466f); + m_uiStepTimer = 1000; + break; + case 11: + DoScriptText(SAY_ROGER04, m_creature); + m_uiStepTimer = 6000; + break; + case 12: + m_creature->GetMotionMaster()->MovePoint(0, 1580.215f, 624.368f, 99.924f); + m_uiStepTimer = 1900; + break; + case 13: + m_creature->GetMotionMaster()->MovePoint(0, 1587.471f, 618.181f, 99.850f); + m_uiStepTimer = 3900; + break; + case 14: + m_creature->GetMotionMaster()->MovePoint(0, 1592.646f, 590.888f, 99.151f); + m_uiStepTimer = 13000; + break; + case 15: + m_uiPhase = 2; + m_creature->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase == 1) + { + if (m_uiStepTimer < uiDiff) + { + FirstCrateEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + return; + } +}; + +/*### +## npc_morigan +###*/ + +enum +{ + SAY_MORIGAN01 = -1597284, + SAY_PERELLI02 = -1597285, + SAY_MORIGAN03 = -1597286, + SAY_PERELLI04 = -1597287, + SAY_MORIGAN05 = -1597288, + SAY_PERELLI06 = -1597289, + SAY_MORIGAN07 = -1597290, +}; + +struct MANGOS_DLL_DECL npc_moriganAI : public ScriptedAI +{ + npc_moriganAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiPhase; + + void Reset() + { + if(m_uiPhase != 2) + { + m_uiStep = 0; + m_uiStepTimer = 100; + m_uiPhase = 0; + } + } + + void StartMorigan() + { + m_uiPhase = 1; + } + + void SecondCrateEvent() + { + switch(m_uiStep) + { + case 0: + DoScriptText(SAY_MORIGAN01, m_creature); + m_uiStepTimer = 6000; + break; + case 1: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_PERELLI)) + DoScriptText(SAY_PERELLI02, pTemp); + m_uiStepTimer = 2000; + break; + case 2: + m_creature->GetMotionMaster()->MovePoint(0, 1564.138f, 668.343f, 102.058f); + m_uiStepTimer = 2000; + break; + case 3: + m_creature->GetMotionMaster()->MovePoint(0, 1567.956f, 667.776f, 102.094f); + m_uiStepTimer = 1500; + break; + case 4: + m_creature->GetMotionMaster()->MovePoint(0, 1569.615f, 668.859f, 102.180f); + m_uiStepTimer = 2000; + break; + case 5: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiStepTimer = 1000; + break; + case 6: + DoScriptText(SAY_MORIGAN03, m_creature); + m_uiStepTimer = 3000; + break; + case 7: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_PERELLI)) + { + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTemp->GetObjectGuid()); + pTemp->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + } + m_uiStepTimer = 3000; + break; + case 8: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_PERELLI)) + DoScriptText(SAY_PERELLI04, pTemp); + m_uiStepTimer = 3000; + break; + case 9: + DoScriptText(SAY_MORIGAN05, m_creature); + m_uiStepTimer = 9000; + break; + case 10: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_PERELLI)) + DoScriptText(SAY_PERELLI06, pTemp); + m_uiStepTimer = 6000; + break; + case 11: + DoScriptText(SAY_MORIGAN07, m_creature); + m_uiStepTimer = 4000; + break; + case 12: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + if(Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_PERELLI)) + pTemp->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 1576.119f, 657.675f, 102.09f); + m_uiStepTimer = 4900; + break; + case 13: + m_creature->GetMotionMaster()->MovePoint(0, 1586.040f, 646.113f, 100.910f); + m_uiStepTimer = 5900; + break; + case 14: + m_creature->GetMotionMaster()->MovePoint(0, 1609.189f, 697.134f, 106.902f); + m_uiStepTimer = 24900; + break; + case 15: + m_uiPhase = 2; + m_creature->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if(m_uiPhase == 1) + { + if(m_uiStepTimer < uiDiff) + { + SecondCrateEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + return; + } +}; + +/*### +## npc_jena +###*/ + +enum +{ + SAY_JENA01 = -1597291, + SAY_MARTHA02 = -1597292, + SAY_JENA03 = -1597293, + SAY_JENA04 = -1597294, + SAY_MARTHA05 = -1597295, + +}; + +struct MANGOS_DLL_DECL npc_jenaAI : public ScriptedAI +{ + npc_jenaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiPhase; + + void Reset() + { + if(m_uiPhase != 2) + { + m_uiStep = 0; + m_uiStepTimer = 100; + m_uiPhase = 0; + } + } + + void StartJena() + { + m_uiPhase = 1; + } + + void ThirdCrateEvent() + { + switch(m_uiStep) + { + case 0: + m_creature->GetMotionMaster()->MovePoint(0, 1605.546f, 744.869f, 114.731f); + m_uiStepTimer = 1900; + break; + case 1: + m_creature->GetMotionMaster()->MovePoint(0, 1614.967f, 743.673f, 114.063f); + m_uiStepTimer = 4900; + break; + case 2: + m_creature->GetMotionMaster()->MovePoint(0, 1623.848f, 729.251f, 112.410f); + m_uiStepTimer = 6900; + break; + case 3: + m_creature->GetMotionMaster()->MovePoint(0, 1633.460f, 726.261f, 113.518f); + m_uiStepTimer = 4000; + break; + case 4: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTemp->GetObjectGuid()); + DoScriptText(SAY_JENA01, m_creature); + m_uiStepTimer = 3000; + break; + case 5: + if(Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + { + pTemp->RemoveAurasDueToSpell(58925); + pTemp->GetMotionMaster()->MovePoint(0, 1635.918f, 724.357f, 113.561f); + } + m_uiStepTimer = 1000; + break; + case 6: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + { + pTemp->GetMotionMaster()->MovePoint(0, 1636.721f, 725.88f, 113.561f); + pTemp->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + } + m_uiStepTimer = 1000; + break; + case 7: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + DoScriptText(SAY_MARTHA02, pTemp); + m_uiStepTimer = 4000; + break; + case 8: + DoScriptText(SAY_JENA03, m_creature); + m_uiStepTimer = 3000; + break; + case 9: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 1629.278f, 727.894f, 112.636f); + m_uiStepTimer = 1500; + break; + case 10: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + { + pTemp->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + pTemp->GetMap()->CreatureRelocation(pTemp, 1640.089f, 725.766f, 113.561f, 4.77f); + pTemp->GetMotionMaster()->MovePoint(0,1640.089f, 725.766f, 113.561f); + } + m_creature->GetMotionMaster()->MovePoint(0, 1629.452f, 729.416f, 112.712f); + m_uiStepTimer = 1000; + break; + case 11: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + pTemp->GetMotionMaster()->MovePoint(0, 1640.103f, 725.522f, 113.561f); + m_uiStepTimer = 500; + break; + case 12: + if(Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + pTemp->CastSpell(pTemp, 58925, false); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiStepTimer = 1500; + break; + case 13: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiStepTimer = 1000; + break; + case 14: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTemp->GetObjectGuid()); + DoScriptText(SAY_JENA04, m_creature); + m_uiStepTimer = 3000; + break; + case 15: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_MARTHA)) + { + pTemp->RemoveAurasDueToSpell(58925); + DoScriptText(SAY_MARTHA05, pTemp); + pTemp->GetMotionMaster()->MovePoint(0, 1638.196f, 726.171f, 113.561f); + } + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 1615.590f, 719.509f, 110.311f); + m_uiStepTimer = 2000; + break; + case 16: + m_creature->GetMotionMaster()->MovePoint(0, 1596.436f, 670.809f, 103.747f); + m_uiStepTimer = 6900; + break; + case 17: + m_creature->GetMotionMaster()->MovePoint(0, 1571.549f, 609.837f, 99.767f); + m_uiStepTimer = 11000; + break; + case 18: + m_uiPhase = 2; + m_creature->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase == 1) + { + if (m_uiStepTimer < uiDiff) + { + ThirdCrateEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + return; + } +}; + +/*### +## npc_malcolm +###*/ + +enum +{ + SOUND_ID_DOG_GROWL = 1108, + SOUND_ID_DOG_HOWL = 1018, + EMOTE_DOG_HOWL = 393, + + SAY_MALCOLM01 = -1597296, + SAY_MALCOLM02 = -1597297, + SAY_MALCOLM03 = -1597298, + SAY_MALCOLM04 = -1597299, +}; + +struct MANGOS_DLL_DECL npc_malcolmAI : public ScriptedAI +{ + npc_malcolmAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiPhase; + + void Reset() + { + if (m_uiPhase != 2) + { + m_uiStep = 0; + m_uiStepTimer = 100; + m_uiPhase = 0; + } + } + + void StartMalcolm() + { + m_uiPhase = 1; + } + + void FourCrateEvent() + { + switch(m_uiStep) + { + case 0: + m_creature->GetMotionMaster()->MovePoint(0, 1614.066f, 796.722f, 121.739f); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->GetMotionMaster()->MovePoint(0, 1611.459f, 793.274f, 121.928f); + m_uiStepTimer = 5400; + break; + case 1: + DoScriptText(SAY_MALCOLM01, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, 1622.820f, 798.816f, 120.570f); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->GetMotionMaster()->MovePoint(0, 1621.467f, 794.323f, 120.323f); + m_uiStepTimer = 3400; + break; + case 2: + m_creature->GetMotionMaster()->MovePoint(0, 1626.574f, 806.781f, 120.270f); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->GetMotionMaster()->MovePoint(0, 1629.232f, 803.629f, 120.011f); + m_uiStepTimer = 3400; + break; + case 3: + m_creature->GetMotionMaster()->MovePoint(0, 1622.782f, 808.533f, 121.249f); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->GetMotionMaster()->MovePoint(0, 1629.265f, 805.245f, 120.070f); + m_uiStepTimer = 300; + break; + case 4: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->PlayDirectSound(SOUND_ID_DOG_GROWL); + m_uiStepTimer = 500; + break; + case 5: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTemp->GetObjectGuid()); + DoScriptText(SAY_MALCOLM02, m_creature); + m_uiStepTimer = 2000; + break; + case 6: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->GetMotionMaster()->MovePoint(0, 1629.163f, 809.738f, 120.369f); + m_uiStepTimer = 2000; + break; + case 7: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + { + pTemp->HandleEmoteCommand(EMOTE_DOG_HOWL); + pTemp->PlayDirectSound(SOUND_ID_DOG_HOWL); + } + m_uiStepTimer = 4000; + break; + case 8: + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 1629.922f, 807.799f, 120.122f); + m_uiStepTimer = 2900; + break; + case 9: + m_creature->GetMotionMaster()->MovePoint(0, 1632.169f, 809.851f, 120.047f); + m_uiStepTimer = 900; + break; + case 10: + m_creature->GetMotionMaster()->MovePoint(0, 1630.651f, 811.149f, 120.307f); + m_uiStepTimer = 800; + break; + case 11: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + DoScriptText(SAY_MALCOLM03, m_creature); + m_uiStepTimer = 4000; + break; + case 12: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTemp->GetObjectGuid()); + DoScriptText(SAY_MALCOLM04, m_creature); + m_uiStepTimer = 7000; + break; + case 13: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->GetMotionMaster()->MovePoint(0, 1630.692f, 808.011f, 120.083f); + m_uiStepTimer = 600; + break; + case 14: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DOG)) + pTemp->SetStandState(UNIT_STAND_STATE_SIT); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(0, 1641.452f, 812.600f, 119.948f); + m_uiStepTimer = 3900; + break; + case 15: + m_creature->GetMotionMaster()->MovePoint(0, 1657.975f, 857.352f, 119.097f); + m_uiStepTimer = 17900; + break; + case 16: + m_creature->GetMotionMaster()->MovePoint(0, 1679.852f, 912.245f, 120.533f); + m_uiStepTimer = 22900; + break; + case 17: + m_creature->GetMotionMaster()->MovePoint(0, 1699.915f, 967.110f, 121.643f); + m_uiStepTimer = 22900; + break; + case 18: + m_creature->GetMotionMaster()->MovePoint(0, 1678.393f, 1026.890f, 125.431f); + m_uiStepTimer = 24900; + break; + case 19: + m_creature->GetMotionMaster()->MovePoint(0, 1678.943f, 1093.130f, 126.899f); + m_uiStepTimer = 25900; + break; + case 20: + m_creature->GetMotionMaster()->MovePoint(0, 1700.042f, 1103.880f, 130.872f); + m_uiStepTimer = 10900; + break; + case 21: + m_uiPhase = 2; + m_creature->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase == 1) + { + if (m_uiStepTimer < uiDiff) + { + FourCrateEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + return; + } +}; + +/*### +## npc_bartleby +###*/ + +enum +{ + SAY_BARTLEBY01 = -1597300, + SAY_BARTLEBY02 = -1597301, + SAY_BARTLEBY03 = -1597302, + SAY_BARTLEBY04 = -1597303, + SAY_BARTLEBY05 = -1597304, +}; + +struct MANGOS_DLL_DECL npc_bartleby_csAI : public ScriptedAI +{ + npc_bartleby_csAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiStep; + uint32 m_uiStepTimer; + uint32 m_uiPhase; + + void Reset() + { + if(m_uiPhase != 4) + { + m_uiStep = 0; + m_uiStepTimer = 100; + m_uiPhase = 0; + } + } + + void MoveInLineOfSight(Unit* who) override + { + if (!who) + return; + + if (!m_pInstance) return; + + if (who->GetTypeId() == TYPEID_PLAYER && m_creature->GetDistance2d(who) <= 20 && m_uiPhase == 0) + { + m_uiPhase = 1; + } + } + + void StartBartleby() + { + m_uiPhase = 3; + } + + void FifthCrateEvent() + { + switch(m_uiStep) + { + case 0: + DoScriptText(SAY_BARTLEBY03, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, 1672.539f, 872.277f, 120.113f); + m_uiStepTimer = 1000; + break; + case 1: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiStepTimer = 3000; + break; + case 2: + DoScriptText(SAY_BARTLEBY04, m_creature); + m_uiStepTimer = 7000; + break; + case 3: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiStepTimer = 1000; + break; + case 4: + DoScriptText(SAY_BARTLEBY05, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, 1663.054f, 869.959f, 119.734f); + m_uiStepTimer = 2900; + break; + case 5: + m_creature->GetMotionMaster()->MovePoint(0, 1640.732f, 812.422f, 119.933f); + m_uiStepTimer = 23900; + break; + case 6: + m_creature->GetMotionMaster()->MovePoint(0, 1623.704f, 755.741f, 115.710f); + m_uiStepTimer = 22900; + break; + case 7: + m_creature->GetMotionMaster()->MovePoint(0, 1607.108f, 699.637f, 106.971f); + m_uiStepTimer = 22900; + break; + case 8: + m_creature->GetMotionMaster()->MovePoint(0, 1587.750f, 646.929f, 100.990f); + m_uiStepTimer = 20900; + break; + case 9: + m_creature->GetMotionMaster()->MovePoint(0, 1571.103f, 660.949f, 102.084f); + m_uiStepTimer = 10900; + break; + case 10: + m_uiPhase = 4; + m_creature->SetVisibility(VISIBILITY_OFF); + break; + } + } + + void SpeechEvent() + { + switch(m_uiStep) + { + case 0: + DoScriptText(SAY_BARTLEBY01, m_creature); + m_uiStepTimer = 5000; + break; + case 1: + DoScriptText(SAY_BARTLEBY02, m_creature); + if (m_uiPhase == 1) + m_uiPhase = 2; + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase == 3) + { + if (m_uiStepTimer < uiDiff) + { + FifthCrateEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + if (m_uiPhase == 1) + { + if(m_uiStepTimer < uiDiff) + { + SpeechEvent(); + m_uiStep++; + } + else m_uiStepTimer -= uiDiff; + } + + return; + } +}; + +/*### +## npc_crates +###*/ + +enum +{ + SPELL_LIGHT = 49590 +}; + +struct MANGOS_DLL_DECL npc_stratholme_cratesAI : public ScriptedAI +{ + npc_stratholme_cratesAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool Active; + + void Reset() + { + Active = false; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) return; + + if (m_creature->HasAura(SPELL_LIGHT) && Active != true) + { + if (Creature* pRoger = m_pInstance->GetSingleCreatureFromStorage(NPC_ROGER)) + { + if (m_creature->GetDistance2d(pRoger->GetPositionX(), pRoger->GetPositionY()) < 50.0f) + { + ((npc_rogerAI*)pRoger->AI())->StartRoger(); + } + } + + if (Creature* pMorigan = m_pInstance->GetSingleCreatureFromStorage(NPC_MORIGAN)) + { + if(m_creature->GetDistance2d(pMorigan->GetPositionX(), pMorigan->GetPositionY()) < 50.0f) + { + ((npc_moriganAI*)pMorigan->AI())->StartMorigan(); + } + } + + if (Creature* pJena = m_pInstance->GetSingleCreatureFromStorage(NPC_JENA)) + { + if (m_creature->GetDistance2d(pJena->GetPositionX(), pJena->GetPositionY()) < 50.0f) + { + ((npc_jenaAI*)pJena->AI())->StartJena(); + } + } + + if (Creature* pMalcolm = m_pInstance->GetSingleCreatureFromStorage(NPC_MALCOLM)) + { + if (m_creature->GetDistance2d(pMalcolm->GetPositionX(), pMalcolm->GetPositionY()) < 50.0f) + { + ((npc_malcolmAI*)pMalcolm->AI())->StartMalcolm(); + } + } + + if (Creature* pBartleby = m_pInstance->GetSingleCreatureFromStorage(NPC_BARTLEBY)) + { + if (m_creature->GetDistance2d(pBartleby->GetPositionX(), pBartleby->GetPositionY()) < 50.0f) + { + ((npc_bartleby_csAI*)pBartleby->AI())->StartBartleby(); + } + } + + m_pInstance->SetData(TYPE_CRATES_COUNT, 1); + if (GameObject* pLight = GetClosestGameObjectWithEntry(m_creature, GO_CRATE_LIGHT, 5.0f)) + pLight->SetPhaseMask(0, true); + //m_creature->SetPhaseMask(0, true); + Active = true; + } + + return; + } +}; + +CreatureAI* GetAI_npc_chromi_start(Creature* pCreature) +{ + return new npc_chromi_startAI(pCreature); +} + +CreatureAI* GetAI_npc_mike(Creature* pCreature) +{ + return new npc_mikeAI(pCreature); +} + +CreatureAI* GetAI_npc_roger(Creature* pCreature) +{ + return new npc_rogerAI(pCreature); +} + +CreatureAI* GetAI_npc_morigan(Creature* pCreature) +{ + return new npc_moriganAI(pCreature); +} + +CreatureAI* GetAI_npc_jena(Creature* pCreature) +{ + return new npc_jenaAI(pCreature); +} + +CreatureAI* GetAI_npc_malcolm(Creature* pCreature) +{ + return new npc_malcolmAI(pCreature); +} + +CreatureAI* GetAI_npc_bartleby_cs(Creature* pCreature) +{ + return new npc_bartleby_csAI(pCreature); +} + +CreatureAI* GetAI_npc_stratholme_crates(Creature* pCreature) +{ + return new npc_stratholme_cratesAI(pCreature); +} + +void AddSC_culling_of_stratholmeAI() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_chromi_start"; + pNewScript->GetAI = &GetAI_npc_chromi_start; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_mike"; + pNewScript->GetAI = &GetAI_npc_mike; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_roger"; + pNewScript->GetAI = &GetAI_npc_roger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_morigan"; + pNewScript->GetAI = &GetAI_npc_morigan; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_jena"; + pNewScript->GetAI = &GetAI_npc_jena; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_malcolm"; + pNewScript->GetAI = &GetAI_npc_malcolm; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_bartleby_cs"; + pNewScript->GetAI = &GetAI_npc_bartleby_cs; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_stratholme_crates"; + pNewScript->GetAI = &GetAI_npc_stratholme_crates; + pNewScript->RegisterSelf(); +} 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 b3bcc11d93..bc3e3858c5 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,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,560 +15,271 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + /* ScriptData -SDName: Instance_culling_of_stratholme -SD%Complete: 80% +SDName: instance_culling_of_stratholme +SD%Complete: % SDComment: -SDCategory: Culling of Stratholme EndScriptData */ #include "precompiled.h" #include "culling_of_stratholme.h" -enum -{ - MAX_ARTHAS_SPAWN_POS = 5, - SAY_CHROMIE_HURRY = -1000000 // TODO -}; - -struct sSpawnLocation -{ - float m_fX, m_fY, m_fZ, m_fO; -}; - -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} -}; - -static sSpawnLocation m_aChromieSpawnLocs[] = // need tuning, escpecially EndPositions! +struct MANGOS_DLL_DECL instance_culling_of_stratholme : public ScriptedInstance { - {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 -}; - -instance_culling_of_stratholme::instance_culling_of_stratholme(Map* pMap) : ScriptedInstance(pMap), - m_uiGrainCrateCount(0), - m_uiRemoveCrateStateTimer(0), - m_uiArthasRespawnTimer(0), - - m_uiChromieInnGUID(0), - m_uiChromieEntranceGUID(0), - m_uiChromieEndGUID(0), - m_uiHourglassGUID(0), - m_uiArthasGUID(0), - m_uiMeathookGUID(0), - m_uiSalrammGUID(0), - m_uiEpochGUID(0), - m_uiCorrupterGUID(0), - m_uiLordaeronCrierGUID(0), - - m_uiBelfastGUID(0), - m_uiForrestenGUID(0), - m_uiSiabiGUID(0), - m_uiJamesGUID(0), - m_uiCorricksGUID(0), - m_uiStoutmantleGUID(0), + instance_culling_of_stratholme(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - m_uiOwensGUID(0), - m_uiMoriganGUID(0), - m_uiAndersonGUID(0), - m_uiMooreGUID(0), - m_uiBattsonGUID(0), - - m_uiOReillyGUID(0), - - m_uiDoorBookcaseGUID(0), - m_uiDarkRunedChestGUID(0) -{ - Initialize(); -} + uint8 m_uiCratesCount; + uint32 m_auiEncounter[MAX_ENCOUNTERS]; + uint32 m_uiHeroicTimer; + uint32 m_uiLastTimer; -void instance_culling_of_stratholme::Initialize() -{ - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); -} + ObjectGuid m_uiMalChestGUID; + ObjectGuid m_uiExitGUID; -void instance_culling_of_stratholme::OnCreatureCreate(Creature* pCreature) -{ - switch(pCreature->GetEntry()) + void Initialize() override { - case NPC_CHROMIE_INN: m_uiChromieInnGUID = pCreature->GetGUID(); break; - case NPC_CHROMIE_ENTRANCE: m_uiChromieEntranceGUID = pCreature->GetGUID(); break; - case NPC_CHROMIE_END: m_uiChromieEndGUID = pCreature->GetGUID(); break; - case NPC_HOURGLASS: m_uiHourglassGUID = pCreature->GetGUID(); break; - case NPC_ARTHAS: m_uiArthasGUID = pCreature->GetGUID(); break; - case NPC_MEATHOOK: m_uiMeathookGUID = pCreature->GetGUID(); break; - case NPC_SALRAMM_THE_FLESHCRAFTER: m_uiSalrammGUID = pCreature->GetGUID(); break; - case NPC_CHRONO_LORD_EPOCH: m_uiEpochGUID = pCreature->GetGUID(); break; - case NPC_MALGANIS: m_uiMalganisGUID = pCreature->GetGUID(); break; - case NPC_MICHAEL_BELFAST: m_uiBelfastGUID = pCreature->GetGUID(); break; - case NPC_HEARTHSINGER_FORRESTEN: m_uiForrestenGUID = pCreature->GetGUID(); break; - case NPC_FRAS_SIABI: m_uiSiabiGUID = pCreature->GetGUID(); break; - case NPC_FOOTMAN_JAMES: m_uiJamesGUID = pCreature->GetGUID(); break; - case NPC_MAL_CORRICKS: m_uiCorricksGUID = pCreature->GetGUID(); break; - case NPC_GRYAN_STOUTMANTLE: m_uiStoutmantleGUID = pCreature->GetGUID(); break; - case NPC_ROGER_OWENS: m_uiOwensGUID = pCreature->GetGUID(); break; - case NPC_SERGEANT_MORIGAN: m_uiMoriganGUID = pCreature->GetGUID(); break; - case NPC_JENA_ANDERSON: m_uiAndersonGUID = pCreature->GetGUID(); break; - case NPC_MALCOM_MOORE: m_uiMooreGUID = pCreature->GetGUID(); break; - case NPC_BARTLEBY_BATTSON: m_uiBattsonGUID = pCreature->GetGUID(); break; - case NPC_PATRICIA_O_REILLY: m_uiOReillyGUID = pCreature->GetGUID(); break; - case NPC_LORDAERON_CRIER: m_uiLordaeronCrierGUID = pCreature->GetGUID(); break; - case NPC_INFINITE_CORRUPTER: m_uiCorrupterGUID = pCreature->GetGUID(); break; + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - case NPC_CRATES_BUNNY: m_luiCratesBunnyGUIDs.push_back(pCreature->GetGUID()); break; - case NPC_LORDAERON_FOOTMAN: m_luiFootmanGUIDs.push_back(pCreature->GetGUID()); break; + m_uiHeroicTimer = 1500000; + m_uiLastTimer = 1500000; - case NPC_STRATHOLME_CITIZEN: - case NPC_STRATHOLME_RESIDENT: - if (m_auiEncounter[TYPE_ARTHAS_INTRO_EVENT] == DONE) - pCreature->UpdateEntry(NPC_ZOMBIE); - else - m_luiResidentGUIDs.push_back(pCreature->GetGUID()); - break; - case NPC_AGIATED_STRATHOLME_CITIZEN: m_lAgiatedCitizenGUIDList.push_back(pCreature->GetGUID()); break; - case NPC_AGIATED_STRATHOLME_RESIDENT: m_lAgiatedResidentGUIDList.push_back(pCreature->GetGUID()); break; - } -} + DoUpdateWorldState(WORLD_STATE_COS_CRATE_COUNT, 0); + DoUpdateWorldState(WORLD_STATE_COS_CRATE_ON, 0); + DoUpdateWorldState(WORLD_STATE_COS_WAVE_COUNT, 0); + DoUpdateWorldState(WORLD_STATE_COS_TIME_COUNT, 0); + DoUpdateWorldState(WORLD_STATE_COS_TIME_ON, 0); -void instance_culling_of_stratholme::OnObjectCreate(GameObject* pGo) -{ - switch(pGo->GetEntry()) - { - case GO_DOOR_BOOKCASE: - m_uiDoorBookcaseGUID = pGo->GetGUID(); - if (m_auiEncounter[TYPE_EPOCH_EVENT] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_DARK_RUNED_CHEST: - case GO_DARK_RUNED_CHEST_H: - m_uiDarkRunedChestGUID = pGo->GetGUID(); - break; + m_uiCratesCount = 0; } -} - -Player* instance_culling_of_stratholme::GetPlayerInMap() -{ - Map::PlayerList const& players = instance->GetPlayers(); - if (!players.isEmpty()) + void OnCreatureCreate(Creature* pCreature) override { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + switch(pCreature->GetEntry()) { - if (Player* plr = itr->getSource()) - return plr; + case NPC_CHROMI01: + pCreature->SetActiveObjectState(true); + break; + case NPC_CHROMI02: + pCreature->SetActiveObjectState(true); + if (m_auiEncounter[0] == DONE) + pCreature->SetVisibility(VISIBILITY_ON); + else + pCreature->SetVisibility(VISIBILITY_OFF); + break; + case NPC_MAL_CORICS: + pCreature->SetActiveObjectState(true); + break; + case NPC_GRIAN_STONE: + pCreature->SetActiveObjectState(true); + pCreature->SetStandState(UNIT_STAND_STATE_SIT_MEDIUM_CHAIR); + break; + case NPC_JAMES: + pCreature->SetActiveObjectState(true); + pCreature->SetStandState(UNIT_STAND_STATE_SIT_MEDIUM_CHAIR); + break; + case NPC_FRAS_FRASIABI: + pCreature->SetActiveObjectState(true); + pCreature->SetStandState(UNIT_STAND_STATE_SIT_MEDIUM_CHAIR); + break; + case NPC_FORRESTER: + pCreature->SetActiveObjectState(true); + pCreature->SetStandState(UNIT_STAND_STATE_SIT_MEDIUM_CHAIR); + break; + case NPC_PERELLI: + pCreature->SetActiveObjectState(true); + break; + case NPC_MARTHA: + pCreature->CastSpell(pCreature, 58925, false); + pCreature->SetActiveObjectState(true); + break; + case NPC_DOG: + pCreature->SetActiveObjectState(true); + break; + case NPC_JAINA: + pCreature->SetActiveObjectState(true); + break; + case NPC_UTHER: + pCreature->SetActiveObjectState(true); + break; + case NPC_MARINE_1: + pCreature->SetActiveObjectState(true); + break; + case NPC_MARINE_2: + pCreature->SetActiveObjectState(true); + break; + case NPC_MARINE_3: + pCreature->SetActiveObjectState(true); + break; + case NPC_MARINE_4: + pCreature->SetActiveObjectState(true); + break; + case NPC_PRIEST_1: + pCreature->SetActiveObjectState(true); + break; + case NPC_PRIEST_2: + pCreature->SetActiveObjectState(true); + break; + case NPC_MALGANIS: + pCreature->SetActiveObjectState(true); + break; + case NPC_INFINITE_CORRUPTOR: + pCreature->SetPhaseMask(0, true); + break; } + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); } - return NULL; -} -void instance_culling_of_stratholme::UpdateQuestCredit() -{ - Map::PlayerList const& players = instance->GetPlayers(); - if (!players.isEmpty()) + void OnObjectCreate(GameObject* pGo) override { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* pPlayer = itr->getSource()) - pPlayer->KilledMonsterCredit(NPC_CRATES_BUNNY); - } + switch(pGo->GetEntry()) + { + case GO_MALGANIS_GATE1: + case GO_MALGANIS_GATE2: + case GO_MALGANIS_CHEST: + case GO_MALGANIS_CHEST_H: + break; + case GO_EXIT: + if (m_auiEncounter[TYPE_MALGANIS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } -} -void instance_culling_of_stratholme::DoChromieHurrySpeech() -{ - if (Creature* pChromie = instance->GetCreature(m_uiChromieEntranceGUID)) + void ChromiWhispers() { - 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); + Map::PlayerList const &PlayerList = instance->GetPlayers(); + if (PlayerList.isEmpty()) + return; + + if (Creature* pChromi = GetSingleCreatureFromStorage(NPC_CHROMI01)) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + pChromi->MonsterWhisper("Good work with crates! Come to me in front of Stratholme for your next assignment!", i->getSource(), false); + i->getSource()->KilledMonsterCredit(NPC_CRATE_KC_BUNNY, pChromi->GetObjectGuid()); + i->getSource()->DestroyItemCount(ITEM_ARCANE_DISRUPTOR, 1, true); } + pChromi->SetVisibility(VISIBILITY_OFF); } + if (Creature* pChromi2 = GetSingleCreatureFromStorage(NPC_CHROMI02)) + pChromi2->SetVisibility(VISIBILITY_ON); } -} -void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData) -{ - switch(uiType) + void KillMalginasCredit() { - case TYPE_GRAIN_EVENT: - m_auiEncounter[TYPE_GRAIN_EVENT] = uiData; - if (uiData == SPECIAL) - DoUpdateWorldState(WORLD_STATE_CRATES, 1); - else if (uiData == IN_PROGRESS) - { - if (m_uiGrainCrateCount >= 5) - return; - - ++m_uiGrainCrateCount; - DoUpdateWorldState(WORLD_STATE_CRATES_COUNT, m_uiGrainCrateCount); - - if (m_uiGrainCrateCount == 5) - { - UpdateQuestCredit(); - m_uiRemoveCrateStateTimer = 20000; - SetData(TYPE_GRAIN_EVENT, DONE); - } + Map::PlayerList const &PlayerList = instance->GetPlayers(); + if (PlayerList.isEmpty()) + return; + + if (Creature* pMalganis = GetSingleCreatureFromStorage(NPC_MALGANIS)) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + pMalganis->SummonCreature(NPC_CHROMI03, 2311.61f, 1497.85f, 128.01f, 4.14f, TEMPSUMMON_TIMED_DESPAWN, 1800000); + i->getSource()->KilledMonsterCredit(MALGANIS_KC_BUNNY, pMalganis->GetObjectGuid()); } - break; - case TYPE_ARTHAS_INTRO_EVENT: - m_auiEncounter[TYPE_ARTHAS_INTRO_EVENT] = uiData; - break; - case TYPE_ARTHAS_ESCORT_EVENT: - m_auiEncounter[TYPE_ARTHAS_ESCORT_EVENT] = uiData; - break; - case TYPE_MEATHOOK_EVENT: - m_auiEncounter[TYPE_MEATHOOK_EVENT] = uiData; - if (uiData == DONE) - SetData(TYPE_SALRAMM_EVENT, IN_PROGRESS); - break; - case TYPE_SALRAMM_EVENT: - m_auiEncounter[TYPE_SALRAMM_EVENT] = uiData; - if (uiData == DONE) - DoUpdateWorldState(WORLD_STATE_WAVE, 0); // Remove WaveCounter - break; - case TYPE_EPOCH_EVENT: - m_auiEncounter[TYPE_EPOCH_EVENT] = uiData; - break; - case TYPE_MALGANIS_EVENT: - m_auiEncounter[TYPE_MALGANIS_EVENT] = uiData; - if (uiData == DONE) - { - DoRespawnGameObject(m_uiDarkRunedChestGUID, 30*MINUTE); - DoSpawnChromieIfNeeded(); - } - break; - case TYPE_INFINITE_CORRUPTER_TIME: - m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] = uiData; - if (!uiData) - { - DoUpdateWorldState(WORLD_STATE_TIME, 0); // Remove Timer - DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, 0); - } - else - DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, uiData/(MINUTE*IN_MILLISECONDS)); - break; - case TYPE_INFINITE_CORRUPTER: - m_auiEncounter[TYPE_INFINITE_CORRUPTER] = 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 - break; - case DONE: - SetData(TYPE_INFINITE_CORRUPTER_TIME, 0); - break; - case SPECIAL: - DoChromieHurrySpeech(); - break; - case FAIL: - SetData(TYPE_INFINITE_CORRUPTER_TIME, 0); - if (Creature* pCorrupter = instance->GetCreature(m_uiCorrupterGUID)) - if (pCorrupter->isAlive()) - pCorrupter->ForcedDespawn(); - break; - } - break; - } - - if (uiData == DONE || (uiType == TYPE_INFINITE_CORRUPTER && uiData == FAIL)) - { - 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]; - - strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } -} - -void instance_culling_of_stratholme::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] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8]; - - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (i != TYPE_INFINITE_CORRUPTER_TIME) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; } } - // If already started counting down time, the event is "in progress" - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]) - m_auiEncounter[TYPE_INFINITE_CORRUPTER] = IN_PROGRESS; - - OUT_LOAD_INST_DATA_COMPLETE; -} - -void instance_culling_of_stratholme::OnPlayerEnter(Player* pPlayer) -{ - if (instance->GetPlayersCountExceptGMs() == 0) + void SetData(uint32 uiType, uint32 uiData) override { - 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 - } -} - -uint32 instance_culling_of_stratholme::GetData(uint32 uiType) -{ - switch(uiType) - { - case TYPE_GRAIN_EVENT: return m_auiEncounter[0]; - case TYPE_ARTHAS_INTRO_EVENT: return m_auiEncounter[1]; - case TYPE_MEATHOOK_EVENT: return m_auiEncounter[2]; - case TYPE_SALRAMM_EVENT: return m_auiEncounter[3]; - case TYPE_EPOCH_EVENT: return m_auiEncounter[4]; - case TYPE_ARTHAS_ESCORT_EVENT: return m_auiEncounter[5]; - case TYPE_MALGANIS_EVENT: return m_auiEncounter[6]; - case TYPE_INFINITE_CORRUPTER_TIME: return m_auiEncounter[7]; - case TYPE_INFINITE_CORRUPTER: return m_auiEncounter[8]; - default: return 0; - } -} - -uint64 instance_culling_of_stratholme::GetData64(uint32 uiData) -{ - switch(uiData) - { - case NPC_CHROMIE_INN: return m_uiChromieInnGUID; - case NPC_CHROMIE_ENTRANCE: return m_uiChromieEntranceGUID; - case NPC_CHROMIE_END: return m_uiChromieEndGUID; - case NPC_HOURGLASS: return m_uiHourglassGUID; - case NPC_ARTHAS: return m_uiArthasGUID; - case NPC_MEATHOOK: return m_uiMeathookGUID; - case NPC_SALRAMM_THE_FLESHCRAFTER: return m_uiSalrammGUID; - case NPC_CHRONO_LORD_EPOCH: return m_uiEpochGUID; - case NPC_MALGANIS: return m_uiMalganisGUID; - case NPC_INFINITE_CORRUPTER: return m_uiCorrupterGUID; - case NPC_MICHAEL_BELFAST: return m_uiBelfastGUID; - case NPC_HEARTHSINGER_FORRESTEN: return m_uiForrestenGUID; - case NPC_FRAS_SIABI: return m_uiSiabiGUID; - case NPC_FOOTMAN_JAMES: return m_uiJamesGUID; - case NPC_MAL_CORRICKS: return m_uiCorricksGUID; - case NPC_GRYAN_STOUTMANTLE: return m_uiStoutmantleGUID; - case NPC_ROGER_OWENS: return m_uiOwensGUID; - case NPC_SERGEANT_MORIGAN: return m_uiMoriganGUID; - case NPC_JENA_ANDERSON: return m_uiAndersonGUID; - case NPC_MALCOM_MOORE: return m_uiMooreGUID; - case NPC_BARTLEBY_BATTSON: return m_uiBattsonGUID; - case NPC_PATRICIA_O_REILLY: return m_uiOReillyGUID; - case GO_DOOR_BOOKCASE: return m_uiDoorBookcaseGUID; - default: return 0; - } -} - -uint8 instance_culling_of_stratholme::GetInstancePosition() -{ - if (m_auiEncounter[TYPE_MALGANIS_EVENT] == DONE) - return POS_INSTANCE_FINISHED; - else if (m_auiEncounter[TYPE_ARTHAS_ESCORT_EVENT] == DONE) - return POS_ARTHAS_MALGANIS; - else if (m_auiEncounter[TYPE_EPOCH_EVENT] == DONE) - return POS_ARTHAS_ESCORTING; - else if (m_auiEncounter[TYPE_SALRAMM_EVENT] == DONE) - return POS_ARTHAS_TOWNHALL; - else if (m_auiEncounter[TYPE_MEATHOOK_EVENT] == DONE) - return POS_ARTHAS_WAVES; - else if (m_auiEncounter[TYPE_ARTHAS_INTRO_EVENT] == DONE) - return POS_ARTHAS_WAVES; - else if (m_auiEncounter[TYPE_GRAIN_EVENT] == DONE) - return POS_ARTHAS_INTRO; - else - return 0; -} - -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) -{ - std::list lCratesBunnyList; - for (std::list::const_iterator itr = m_luiCratesBunnyGUIDs.begin(); itr != m_luiCratesBunnyGUIDs.end(); itr++) - { - if (Creature* pBunny = instance->GetCreature(*itr)) - lCratesBunnyList.push_back(pBunny); - } - if (lCratesBunnyList.empty()) - return; - - lCratesBunnyList.sort(sortFromEastToWest); - lList = lCratesBunnyList; -} - -Creature* instance_culling_of_stratholme::GetStratIntroFootman() -{ - std::list lFootmanList; - for (std::list::const_iterator itr = m_luiFootmanGUIDs.begin(); itr != m_luiFootmanGUIDs.end(); itr++) - { - if (Creature* pFootman = instance->GetCreature(*itr)) - lFootmanList.push_back(pFootman); - } - - if (lFootmanList.empty()) - return NULL; - else - { - lFootmanList.sort(sortFromSouthToNorth); - return *lFootmanList.begin(); - } -} - -void instance_culling_of_stratholme::GetResidentOrderedList(std::list &lList) -{ - std::list lResidentList; - for (std::list::const_iterator itr = m_luiResidentGUIDs.begin(); itr != m_luiResidentGUIDs.end(); itr++) - { - if (Creature* pResident = instance->GetCreature(*itr)) - lResidentList.push_back(pResident); - } - if (lResidentList.empty()) - return; - - lResidentList.sort(sortFromSouthToNorth); - lList = lResidentList; -} - -void instance_culling_of_stratholme::ArthasJustDied() -{ - m_uiArthasRespawnTimer = 10000; // TODO, could be instant -} - -void instance_culling_of_stratholme::DoSpawnArthasIfNeeded() -{ - Creature* pArthas = instance->GetCreature(m_uiArthasGUID); - if (pArthas && pArthas->isAlive()) - return; - - uint8 uiPosition = GetInstancePosition(); - if (uiPosition && uiPosition <= MAX_ARTHAS_SPAWN_POS) - { - 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); - } -} - -// 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() -{ - Player* pPlayer = GetPlayerInMap(); - if (!pPlayer) - return; - - if (GetInstancePosition() == POS_INSTANCE_FINISHED) - { - Creature* pChromie = instance->GetCreature(m_uiChromieEndGUID); - 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); - } - else if (GetInstancePosition() >= POS_ARTHAS_INTRO) - { - Creature* pChromie = instance->GetCreature(m_uiChromieEntranceGUID); - 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); - } -} - -void instance_culling_of_stratholme::Update(uint32 uiDiff) -{ - // 25min Run - decrease time, update worldstate every ~20s - // as the time is always saved by m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME], there is no need for an extra timer - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]) - { - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] <= uiDiff) - SetData(TYPE_INFINITE_CORRUPTER, FAIL); - else + switch(uiType) { - m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] -= uiDiff; - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]/IN_MILLISECONDS % 20 == 0) - SetData(TYPE_INFINITE_CORRUPTER_TIME, m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]); + case TYPE_QUEST: + m_auiEncounter[0] = uiData; + break; + case TYPE_CRATES_COUNT: + m_uiCratesCount = m_uiCratesCount + uiData; + if(m_uiCratesCount == 5) + { + m_auiEncounter[0] = DONE; + ChromiWhispers(); + } + DoUpdateWorldState(WORLD_STATE_COS_CRATE_COUNT, m_uiCratesCount); + break; + case TYPE_INTRO: + m_auiEncounter[1] = uiData; + break; + case TYPE_PHASE: + m_auiEncounter[2] = uiData; + break; + case TYPE_ENCOUNTER: + m_auiEncounter[3] = uiData; + break; + case TYPE_WING: + m_auiEncounter[4] = uiData; + break; + case TYPE_BONUS: + m_auiEncounter[5] = uiData; + if(uiData == IN_PROGRESS) + { + if (Creature* pCorruptor = GetSingleCreatureFromStorage(NPC_INFINITE_CORRUPTOR)) + pCorruptor->SetPhaseMask(1, true); + DoUpdateWorldState(WORLD_STATE_COS_TIME_ON, 1); + DoUpdateWorldState(WORLD_STATE_COS_TIME_COUNT, 25); + } + break; + case TYPE_MALGANIS: + m_auiEncounter[6] = uiData; + if (uiData == DONE) + { + KillMalginasCredit(); + DoUseDoorOrButton(GO_EXIT); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_MALGANIS_CHEST : GO_MALGANIS_CHEST_H, 30*MINUTE); + if (Creature* pChromi2 = GetSingleCreatureFromStorage(NPC_CHROMI02)) + pChromi2->SetVisibility(VISIBILITY_OFF); + } + break; } - - // 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) - SetData(TYPE_INFINITE_CORRUPTER, SPECIAL); } - // Small Timer, to remove Grain-Crate WorldState and Spawn Second Chromie - if (m_uiRemoveCrateStateTimer) + uint32 GetData(uint32 uiType) const override { - if (m_uiRemoveCrateStateTimer <= uiDiff) + switch(uiType) { - DoUpdateWorldState(WORLD_STATE_CRATES, 0); - DoSpawnChromieIfNeeded(); - m_uiRemoveCrateStateTimer = 0; + case TYPE_QUEST: + return m_auiEncounter[0]; + case TYPE_INTRO: + return m_auiEncounter[1]; + case TYPE_PHASE: + return m_auiEncounter[2]; + case TYPE_ENCOUNTER: + return m_auiEncounter[3]; + case TYPE_WING: + return m_auiEncounter[4]; + case TYPE_BONUS: + return m_auiEncounter[5]; + case TYPE_MALGANIS: + return m_auiEncounter[6]; } - else - m_uiRemoveCrateStateTimer -= uiDiff; + return 0; } - // Respawn Arthas after some time - if (m_uiArthasRespawnTimer) + void Update(uint32 uiDiff) override { - if (m_uiArthasRespawnTimer <= uiDiff) - { - DoSpawnArthasIfNeeded(); - m_uiArthasRespawnTimer = 0; - } - else - m_uiArthasRespawnTimer -= uiDiff; + if(m_auiEncounter[5] == IN_PROGRESS) + { + if(m_uiHeroicTimer < uiDiff) + { + m_auiEncounter[5] = FAIL; + DoUpdateWorldState(WORLD_STATE_COS_TIME_ON, 0); + if (Creature* pCorruptor = GetSingleCreatureFromStorage(NPC_INFINITE_CORRUPTOR)) + pCorruptor->SetPhaseMask(0, true); + + }else m_uiHeroicTimer -= uiDiff; + + if(m_uiHeroicTimer < m_uiLastTimer - 60000) + { + m_uiLastTimer = m_uiHeroicTimer; + uint32 tMinutes = m_uiHeroicTimer / 60000; + DoUpdateWorldState(WORLD_STATE_COS_TIME_COUNT, tMinutes); + } + } + return; } -} +}; InstanceData* GetInstanceData_instance_culling_of_stratholme(Map* pMap) { @@ -576,8 +288,7 @@ InstanceData* GetInstanceData_instance_culling_of_stratholme(Map* pMap) void AddSC_instance_culling_of_stratholme() { - Script* pNewScript; - + Script *pNewScript; pNewScript = new Script; pNewScript->Name = "instance_culling_of_stratholme"; pNewScript->GetInstanceData = &GetInstanceData_instance_culling_of_stratholme; diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/trash_culling_of_stratholme.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/trash_culling_of_stratholme.cpp new file mode 100644 index 0000000000..009740a314 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/trash_culling_of_stratholme.cpp @@ -0,0 +1,1094 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_culling_of_stratholme +SD%Complete: % +SDComment: +EndScriptData */ + +#include "precompiled.h" +#include "culling_of_stratholme.h" + +/*### +## npc_cs_gnoul +###*/ + +enum +{ + SPELL_FLESH = 52352 +}; + +struct MANGOS_DLL_DECL npc_cs_gnoulAI : public ScriptedAI +{ + npc_cs_gnoulAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiFleshTimer; + + uint32 WaypointId; + uint32 MoveTimer; + + void Reset() + { + m_creature->SetWalk(false); + MoveTimer = (urand(100, 5000)); + m_uiFleshTimer = (urand(3000, 10000)); + WaypointId = 1; + } + + void MoveToPoint(float X, float Y, float Z) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MovePoint(0, X, Y, Z); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (IsCombatMovement()) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + m_uiFleshTimer = (urand(3000, 10000)); + + m_creature->SetLootRecipient(NULL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } + } + } + } + + void JumpNextStep(uint32 Time) + { + MoveTimer = Time; + WaypointId++; + } + + void UpdateAI(const uint32 uiDiff) override + { + if ((!m_creature->SelectHostileTarget() || !m_creature->getVictim()) && m_creature->IsTemporarySummon()) + { + if(MoveTimer < uiDiff) + { + if(m_pInstance->GetData(TYPE_WING) == RIGHT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2356.659f, 1185.501f, 130.636f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2301.735f, 1179.265f, 136.944f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2234.787f, 1180.638f, 136.344f); + JumpNextStep(9000); + break; + case 4: + MoveToPoint(2178.313f, 1244.350f, 136.107f); + JumpNextStep(12000); + break; + case 5: + MoveToPoint(2163.553f, 1277.814f, 133.444f); + JumpNextStep(5000); + break; + case 6: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(5000); + break; + } + } + + if(m_pInstance->GetData(TYPE_WING) == LEFT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2188.318f, 1331.410f, 130.003f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2165.351f, 1279.156f, 133.388f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(9000); + break; + } + } + + } else MoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_uiFleshTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_FLESH); + m_uiFleshTimer = (urand(3000, 10000)); + } + else m_uiFleshTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return; + } +}; + +/*### +## npc_cs_necromancer +###*/ + +enum +{ + SPELL_SHADOW_BOLT = 15472, + SPELL_COURSE = 20812, + SPELL_DRAIN_MANA = 58770 +}; + +struct MANGOS_DLL_DECL npc_cs_necromancerAI : public ScriptedAI +{ + npc_cs_necromancerAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + SetCombatMovement(false); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiShadowBoltTimer; + uint32 m_uiCourseTimer; + + uint32 WaypointId; + uint32 MoveTimer; + + void Reset() + { + m_creature->SetWalk(false); + MoveTimer = (urand(100, 5000)); + m_uiCourseTimer = (urand(7000, 17000)); + m_uiShadowBoltTimer = (urand(3000, 10000)); + WaypointId = 1; + } + + void Aggro(Unit* pWho) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->StopMoving(); + } + + void MoveToPoint(float X, float Y, float Z) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MovePoint(0, X, Y, Z); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + } + m_creature->GetMotionMaster()->MovementExpired(false); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + m_uiShadowBoltTimer = (urand(3000, 10000)); + m_uiCourseTimer = (urand(7000, 17000)); + + m_creature->SetLootRecipient(NULL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } + } + } + } + + void JumpNextStep(uint32 Time) + { + MoveTimer = Time; + WaypointId++; + } + + void UpdateAI(const uint32 uiDiff) override + { + if ((!m_creature->SelectHostileTarget() || !m_creature->getVictim()) && m_creature->IsTemporarySummon()) + { + if(MoveTimer < uiDiff) + { + if(m_pInstance->GetData(TYPE_WING) == RIGHT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2356.659f, 1185.501f, 130.636f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2301.735f, 1179.265f, 136.944f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2234.787f, 1180.638f, 136.344f); + JumpNextStep(9000); + break; + case 4: + MoveToPoint(2178.313f, 1244.350f, 136.107f); + JumpNextStep(12000); + break; + case 5: + MoveToPoint(2163.553f, 1277.814f, 133.444f); + JumpNextStep(5000); + break; + case 6: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(5000); + break; + } + } + + if(m_pInstance->GetData(TYPE_WING) == LEFT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2188.318f, 1331.410f, 130.003f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2165.351f, 1279.156f, 133.388f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(9000); + break; + } + } + + } else MoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_uiShadowBoltTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOW_BOLT); + m_uiShadowBoltTimer = (urand(3000, 5000)); + } + else m_uiShadowBoltTimer -= uiDiff; + + if(m_uiCourseTimer < uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_COURSE); + m_uiCourseTimer = (urand(7000, 17000)); + } + else m_uiCourseTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return; + } +}; + +/*### +## npc_cs_field +###*/ + +enum +{ + SPELL_BLOW = 52491, + SPELL_SCARAB = 52496 +}; + +struct MANGOS_DLL_DECL npc_cs_fieldAI : public ScriptedAI +{ + npc_cs_fieldAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiScarabTimer; + uint32 m_uiBlowTimer; + + uint32 WaypointId; + uint32 MoveTimer; + + void Reset() + { + m_creature->SetWalk(false); + MoveTimer = (urand(100, 5000)); + m_uiBlowTimer = (urand(7000, 17000)); + m_uiScarabTimer = (urand(3000, 10000)); + WaypointId = 1; + } + + void MoveToPoint(float X, float Y, float Z) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MovePoint(0, X, Y, Z); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (IsCombatMovement()) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + m_uiScarabTimer = (urand(3000, 10000)); + m_uiBlowTimer = (urand(7000, 17000)); + + m_creature->SetLootRecipient(NULL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } + } + } + } + + void JumpNextStep(uint32 Time) + { + MoveTimer = Time; + WaypointId++; + } + + void UpdateAI(const uint32 uiDiff) override + { + if ((!m_creature->SelectHostileTarget() || !m_creature->getVictim()) && m_creature->IsTemporarySummon()) + { + if(MoveTimer < uiDiff) + { + if(m_pInstance->GetData(TYPE_WING) == RIGHT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2356.659f, 1185.501f, 130.636f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2301.735f, 1179.265f, 136.944f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2234.787f, 1180.638f, 136.344f); + JumpNextStep(9000); + break; + case 4: + MoveToPoint(2178.313f, 1244.350f, 136.107f); + JumpNextStep(12000); + break; + case 5: + MoveToPoint(2163.553f, 1277.814f, 133.444f); + JumpNextStep(5000); + break; + case 6: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(5000); + break; + } + } + + if(m_pInstance->GetData(TYPE_WING) == LEFT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2188.318f, 1331.410f, 130.003f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2165.351f, 1279.156f, 133.388f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(9000); + break; + } + } + + } else MoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_uiScarabTimer < uiDiff) + { + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_SCARAB); + m_uiScarabTimer = (urand(3000, 5000)); + } + else m_uiScarabTimer -= uiDiff; + + if(m_uiBlowTimer < uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_BLOW); + m_uiBlowTimer = (urand(7000, 17000)); + } + else m_uiBlowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return; + } +}; + +/*### +## npc_cs_alocyte +###*/ + +enum +{ + SPELL_SHADOW = 17234, + SPELL_COLD = 15244, + SPELL_FIRE = 14145, + SPELL_COURSEA = 39621 +}; + +struct MANGOS_DLL_DECL npc_cs_acolyteAI : public ScriptedAI +{ + npc_cs_acolyteAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + SetCombatMovement(false); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiColdTimer; + uint32 m_uiFireTimer; + uint32 m_uiCourseTimer; + uint32 m_uiShadowTimer; + + uint32 WaypointId; + uint32 MoveTimer; + + void Reset() + { + m_creature->SetWalk(false); + MoveTimer = (urand(100, 5000)); + m_uiColdTimer = (urand(7000, 17000)); + m_uiFireTimer = (urand(3000, 10000)); + m_uiCourseTimer = (urand(5000, 12000)); + m_uiShadowTimer = (urand(1000, 3000)); + WaypointId = 1; + } + + void MoveToPoint(float X, float Y, float Z) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MovePoint(0, X, Y, Z); + } + + void Aggro(Unit* pWho) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->StopMoving(); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + } + m_creature->GetMotionMaster()->MovementExpired(false); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + m_uiColdTimer = (urand(7000, 17000)); + m_uiFireTimer = (urand(3000, 10000)); + m_uiCourseTimer = (urand(5000, 12000)); + m_uiShadowTimer = (urand(1000, 3000)); + + m_creature->SetLootRecipient(NULL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } + } + } + } + + void JumpNextStep(uint32 Time) + { + MoveTimer = Time; + WaypointId++; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() && m_creature->IsTemporarySummon()) + { + if(MoveTimer < uiDiff) + { + if(m_pInstance->GetData(TYPE_WING) == RIGHT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2356.659f, 1185.501f, 130.636f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2301.735f, 1179.265f, 136.944f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2234.787f, 1180.638f, 136.344f); + JumpNextStep(9000); + break; + case 4: + MoveToPoint(2178.313f, 1244.350f, 136.107f); + JumpNextStep(12000); + break; + case 5: + MoveToPoint(2163.553f, 1277.814f, 133.444f); + JumpNextStep(5000); + break; + case 6: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(5000); + break; + } + } + + if(m_pInstance->GetData(TYPE_WING) == LEFT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2188.318f, 1331.410f, 130.003f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2165.351f, 1279.156f, 133.388f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(9000); + break; + } + } + + } else MoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_uiShadowTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOW); + m_uiShadowTimer = (urand(3000, 8000)); + } + else m_uiShadowTimer -= uiDiff; + + if(m_uiCourseTimer < uiDiff) + { + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_COURSEA); + m_uiCourseTimer = (urand(7000, 13000)); + } + else m_uiCourseTimer -= uiDiff; + + if(m_uiColdTimer < uiDiff) + { + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_COLD); + m_uiColdTimer = (urand(13000, 17000)); + } + else m_uiColdTimer -= uiDiff; + + if(m_uiFireTimer < uiDiff) + { + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, SPELL_FIRE); + m_uiFireTimer = (urand(6000, 11000)); + } + else m_uiFireTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return; + } +}; + +/*### +## npc_cs_butcher +###*/ + +enum +{ + SPELL_CLOUD = 52525 +}; + +struct MANGOS_DLL_DECL npc_cs_butcherAI : public ScriptedAI +{ + npc_cs_butcherAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 WaypointId; + uint32 MoveTimer; + + void Reset() + { + DoCast(m_creature, SPELL_CLOUD); + m_creature->SetWalk(false); + MoveTimer = (urand(100, 5000)); + WaypointId = 1; + } + + void MoveToPoint(float X, float Y, float Z) + { + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->GetMotionMaster()->MovePoint(0, X, Y, Z); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + if (IsCombatMovement()) + m_creature->GetMotionMaster()->MoveChase(pWho); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(); + + m_creature->SetLootRecipient(NULL); + DoCast(m_creature, SPELL_CLOUD); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && 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); + if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) + { + if (!m_creature->getVictim()) + { + AttackStart(pWho); + pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + } + else if (m_creature->GetMap()->IsDungeon()) + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } + } + } + } + + void JumpNextStep(uint32 Time) + { + MoveTimer = Time; + WaypointId++; + } + + void UpdateAI(const uint32 uiDiff) override + { + if ((!m_creature->SelectHostileTarget() || !m_creature->getVictim()) && m_creature->IsTemporarySummon()) + { + if(MoveTimer < uiDiff) + { + if(m_pInstance->GetData(TYPE_WING) == RIGHT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2356.659f, 1185.501f, 130.636f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2301.735f, 1179.265f, 136.944f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2234.787f, 1180.638f, 136.344f); + JumpNextStep(9000); + break; + case 4: + MoveToPoint(2178.313f, 1244.350f, 136.107f); + JumpNextStep(12000); + break; + case 5: + MoveToPoint(2163.553f, 1277.814f, 133.444f); + JumpNextStep(5000); + break; + case 6: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(5000); + break; + } + } + + if(m_pInstance->GetData(TYPE_WING) == LEFT) + { + switch(WaypointId) + { + case 1: + MoveToPoint(2188.318f, 1331.410f, 130.003f); + JumpNextStep(10000); + break; + case 2: + MoveToPoint(2165.351f, 1279.156f, 133.388f); + JumpNextStep(8000); + break; + case 3: + MoveToPoint(2083.952f, 1287.716f, 141.146f); + JumpNextStep(9000); + break; + } + } + + } else MoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + + return; + } +}; + +struct MANGOS_DLL_DECL npc_time_riftCSAI : public ScriptedAI +{ + npc_time_riftCSAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsRaidOrHeroicDungeon(); + m_creature->SetActiveObjectState(true); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 Step; + uint32 m_uiStepTimer; + Creature* Drakonian01; + Creature* Drakonian02; + Creature* Drakonian03; + + void Reset() + { + m_uiStepTimer = 1000; + Step = 1; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiStepTimer < uiDiff) + { + switch(Step) + { + case 1: + if (Creature* pArthas = m_pInstance->GetSingleCreatureFromStorage(NPC_ARTHAS)) + { + Drakonian01 = m_creature->SummonCreature(NPC_INFINITE_ADVERSARY,(m_creature->GetPositionX()-2)+rand()%4, (m_creature->GetPositionY()-2)+rand()%4, m_creature->GetPositionZ(),3.229f,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,900000); + Drakonian01->GetMotionMaster()->MovePoint(0, pArthas->GetPositionX(), pArthas->GetPositionY(), pArthas->GetPositionZ()); + Drakonian02 = m_creature->SummonCreature(NPC_INFINITE_HUNTER,(m_creature->GetPositionX()-2)+rand()%4, (m_creature->GetPositionY()-2)+rand()%4, m_creature->GetPositionZ(),3.229f,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,900000); + Drakonian02->GetMotionMaster()->MovePoint(0, pArthas->GetPositionX(), pArthas->GetPositionY(), pArthas->GetPositionZ()); + Drakonian03 = m_creature->SummonCreature(NPC_INFINITE_AGENT,(m_creature->GetPositionX()-2)+rand()%4, (m_creature->GetPositionY()-2)+rand()%4, m_creature->GetPositionZ(),3.229f,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,900000); + Drakonian03->GetMotionMaster()->MovePoint(0, pArthas->GetPositionX(), pArthas->GetPositionY(), pArthas->GetPositionZ()); + } + m_uiStepTimer = 3000; + Step++; + break; + case 2: + m_creature->ForcedDespawn(); + Step++; + break; + } + } else m_uiStepTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_cs_gnoul(Creature* pCreature) +{ + return new npc_cs_gnoulAI(pCreature); +} + +CreatureAI* GetAI_npc_cs_necromancer(Creature* pCreature) +{ + return new npc_cs_necromancerAI(pCreature); +} + +CreatureAI* GetAI_npc_cs_field(Creature* pCreature) +{ + return new npc_cs_fieldAI(pCreature); +} + +CreatureAI* GetAI_npc_cs_acolyte(Creature* pCreature) +{ + return new npc_cs_acolyteAI(pCreature); +} + +CreatureAI* GetAI_npc_cs_butcher(Creature* pCreature) +{ + return new npc_cs_butcherAI(pCreature); +} + +CreatureAI* GetAI_npc_time_riftCS(Creature* pCreature) +{ + return new npc_time_riftCSAI(pCreature); +} + +void AddSC_trash_culling_of_stratholme() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_cs_gnoul"; + pNewScript->GetAI = &GetAI_npc_cs_gnoul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_cs_necromancer"; + pNewScript->GetAI = &GetAI_npc_cs_necromancer; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_cs_field"; + pNewScript->GetAI = &GetAI_npc_cs_field; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_cs_acolyte"; + pNewScript->GetAI = &GetAI_npc_cs_acolyte; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_cs_butcher"; + pNewScript->GetAI = &GetAI_npc_cs_butcher; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_time_riftCS"; + pNewScript->GetAI = &GetAI_npc_time_riftCS; + 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 3a5f3603ca..95bba827e6 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Aeonus -SD%Complete: 80 -SDComment: Some spells not implemented +SD%Complete: 90 +SDComment: Small adjustments; Timers SDCategory: Caverns of Time, The Dark Portal EndScriptData */ @@ -26,7 +26,6 @@ EndScriptData */ enum { - SAY_ENTER = -1269012, SAY_AGGRO = -1269013, SAY_BANISH = -1269014, SAY_SLAY1 = -1269015, @@ -38,7 +37,7 @@ enum SPELL_TIME_STOP = 31422, SPELL_ENRAGE = 37605, SPELL_SAND_BREATH = 31473, - H_SPELL_SAND_BREATH = 39049 + SPELL_SAND_BREATH_H = 39049 }; struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI @@ -53,77 +52,93 @@ struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 SandBreath_Timer; - uint32 TimeStop_Timer; - uint32 Frenzy_Timer; + uint32 m_uiSandBreathTimer; + uint32 m_uiTimeStopTimer; + uint32 m_uiFrenzyTimer; + uint32 m_uiCleaveTimer; void Reset() { - SandBreath_Timer = urand(15000, 30000); - TimeStop_Timer = urand(10000, 15000); - Frenzy_Timer = urand(30000, 45000); + m_uiSandBreathTimer = urand(15000, 30000); + m_uiTimeStopTimer = urand(10000, 15000); + m_uiFrenzyTimer = urand(30000, 45000); + m_uiCleaveTimer = urand(5000, 9000); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { - //Despawn Time Keeper - if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) + // Despawn Time Keeper + if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_TIME_KEEPER) { - if (m_creature->IsWithinDistInMap(who,20.0f)) + if (m_creature->IsWithinDistInMap(pWho, 20.0f)) { - DoScriptText(SAY_BANISH, m_creature); - m_creature->DealDamage(who, who->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (DoCastSpellIfCan(pWho, SPELL_BANISH_HELPER) == CAST_OK) + DoScriptText(SAY_BANISH, m_creature); } } - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::MoveInLineOfSight(pWho); } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RIFT,DONE); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - 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; - //Sand Breath - if (SandBreath_Timer < diff) + // Sand Breath + if (m_uiSandBreathTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SAND_BREATH : H_SPELL_SAND_BREATH); - SandBreath_Timer = urand(15000, 25000); - }else SandBreath_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SAND_BREATH : SPELL_SAND_BREATH_H) == CAST_OK) + m_uiSandBreathTimer = urand(15000, 25000); + } + else + m_uiSandBreathTimer -= uiDiff; + + // Time Stop + if (m_uiTimeStopTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TIME_STOP) == CAST_OK) + m_uiTimeStopTimer = urand(20000, 35000); + } + else + m_uiTimeStopTimer -= uiDiff; - //Time Stop - if (TimeStop_Timer < diff) + // Cleave + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TIME_STOP); - TimeStop_Timer = urand(20000, 35000); - }else TimeStop_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(7000, 12000); + } + else + m_uiCleaveTimer -= uiDiff; - //Frenzy - if (Frenzy_Timer < diff) + // Frenzy + if (m_uiFrenzyTimer < uiDiff) { - DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - Frenzy_Timer = urand(20000, 35000); - }else Frenzy_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); + m_uiFrenzyTimer = urand(20000, 35000); + } + } + else + m_uiFrenzyTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -136,9 +151,10 @@ CreatureAI* GetAI_boss_aeonus(Creature* pCreature) void AddSC_boss_aeonus() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_aeonus"; - newscript->GetAI = &GetAI_boss_aeonus; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_aeonus"; + pNewScript->GetAI = &GetAI_boss_aeonus; + pNewScript->RegisterSelf(); } 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 656742a57a..000a332732 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,27 +16,29 @@ /* ScriptData SDName: Boss_Chrono_Lord_Deja -SD%Complete: 65 -SDComment: All abilities not implemented +SD%Complete: 90 +SDComment: Small adjustments; Timers SDCategory: Caverns of Time, The Dark Portal EndScriptData */ #include "precompiled.h" #include "dark_portal.h" -#define SAY_ENTER -1269006 -#define SAY_AGGRO -1269007 -#define SAY_BANISH -1269008 -#define SAY_SLAY1 -1269009 -#define SAY_SLAY2 -1269010 -#define SAY_DEATH -1269011 - -#define SPELL_ARCANE_BLAST 31457 -#define H_SPELL_ARCANE_BLAST 38538 -#define SPELL_ARCANE_DISCHARGE 31472 -#define H_SPELL_ARCANE_DISCHARGE 38539 -#define SPELL_TIME_LAPSE 31467 -#define SPELL_ATTRACTION 38540 //Not Implemented (Heroic mode) +enum +{ + SAY_AGGRO = -1269007, + SAY_BANISH = -1269008, + SAY_SLAY1 = -1269009, + SAY_SLAY2 = -1269010, + SAY_DEATH = -1269011, + + SPELL_ARCANE_BLAST = 31457, + SPELL_ARCANE_BLAST_H = 38538, + SPELL_ARCANE_DISCHARGE = 31472, + SPELL_ARCANE_DISCHARGE_H = 38539, + SPELL_TIME_LAPSE = 31467, + SPELL_ATTRACTION = 38540 +}; struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI { @@ -50,89 +52,92 @@ struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 ArcaneBlast_Timer; - uint32 TimeLapse_Timer; - uint32 Attraction_Timer; - uint32 ArcaneDischarge_Timer; + uint32 m_uiArcaneBlastTimer; + uint32 m_uiTimeLapseTimer; + uint32 m_uiAttractionTimer; + uint32 m_uiArcaneDischargeTimer; void Reset() { - ArcaneBlast_Timer = urand(18000, 23000); - TimeLapse_Timer = urand(10000, 15000); - ArcaneDischarge_Timer = urand(20000, 30000); - Attraction_Timer = urand(25000, 35000); + m_uiArcaneBlastTimer = urand(18000, 23000); + m_uiTimeLapseTimer = urand(10000, 15000); + m_uiArcaneDischargeTimer = urand(20000, 30000); + m_uiAttractionTimer = urand(25000, 35000); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { - //Despawn Time Keeper - if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) + // Despawn Time Keeper + if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_TIME_KEEPER) { - if (m_creature->IsWithinDistInMap(who,20.0f)) + if (m_creature->IsWithinDistInMap(pWho, 20.0f)) { - DoScriptText(SAY_BANISH, m_creature); - m_creature->DealDamage(who, who->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (DoCastSpellIfCan(pWho, SPELL_BANISH_HELPER) == CAST_OK) + DoScriptText(SAY_BANISH, m_creature); } } - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::MoveInLineOfSight(pWho); } - 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* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RIFT,SPECIAL); } - 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; - //Arcane Blast - if (ArcaneBlast_Timer < diff) + // Arcane Blast + if (m_uiArcaneBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_BLAST : H_SPELL_ARCANE_BLAST); - ArcaneBlast_Timer = urand(15000, 25000); - }else ArcaneBlast_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_BLAST : SPELL_ARCANE_BLAST_H) == CAST_OK) + m_uiArcaneBlastTimer = urand(15000, 25000); + } + else + m_uiArcaneBlastTimer -= uiDiff; - //Arcane Discharge - if (ArcaneDischarge_Timer < diff) + // Arcane Discharge + if (m_uiArcaneDischargeTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_ARCANE_DISCHARGE : H_SPELL_ARCANE_DISCHARGE); - - ArcaneDischarge_Timer = urand(20000, 30000); - }else ArcaneDischarge_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_DISCHARGE : SPELL_ARCANE_DISCHARGE_H) == CAST_OK) + m_uiArcaneDischargeTimer = urand(20000, 30000); + } + else + m_uiArcaneDischargeTimer -= uiDiff; - //Time Lapse - if (TimeLapse_Timer < diff) + // Time Lapse + if (m_uiTimeLapseTimer < uiDiff) { - DoScriptText(SAY_BANISH, m_creature); - DoCastSpellIfCan(m_creature, SPELL_TIME_LAPSE); - TimeLapse_Timer = urand(15000, 25000); - }else TimeLapse_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_TIME_LAPSE) == CAST_OK) + m_uiTimeLapseTimer = urand(15000, 25000); + } + else + m_uiTimeLapseTimer -= uiDiff; + // Attraction if (!m_bIsRegularMode) { - if (Attraction_Timer < diff) + if (m_uiAttractionTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_ATTRACTION); - Attraction_Timer = urand(25000, 35000); - }else Attraction_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ATTRACTION) == CAST_OK) + m_uiAttractionTimer = urand(25000, 35000); + } + else + m_uiAttractionTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -146,9 +151,10 @@ CreatureAI* GetAI_boss_chrono_lord_deja(Creature* pCreature) void AddSC_boss_chrono_lord_deja() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_chrono_lord_deja"; - newscript->GetAI = &GetAI_boss_chrono_lord_deja; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_chrono_lord_deja"; + pNewScript->GetAI = &GetAI_boss_chrono_lord_deja; + pNewScript->RegisterSelf(); } 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 d3c40f45fd..3ac4ca0d50 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,26 +16,28 @@ /* ScriptData SDName: Boss_Temporus -SD%Complete: 75 -SDComment: More abilities need to be implemented +SD%Complete: 90 +SDComment: Small adjustments; Timers SDCategory: Caverns of Time, The Dark Portal EndScriptData */ #include "precompiled.h" #include "dark_portal.h" -#define SAY_ENTER -1269000 -#define SAY_AGGRO -1269001 -#define SAY_BANISH -1269002 -#define SAY_SLAY1 -1269003 -#define SAY_SLAY2 -1269004 -#define SAY_DEATH -1269005 - -#define SPELL_HASTE 31458 -#define SPELL_MORTAL_WOUND 31464 -#define SPELL_WING_BUFFET 31475 -#define H_SPELL_WING_BUFFET 38593 -#define SPELL_REFLECT 38592 //Not Implemented (Heroic mod) +enum +{ + SAY_AGGRO = -1269001, + SAY_BANISH = -1269002, + SAY_SLAY1 = -1269003, + SAY_SLAY2 = -1269004, + SAY_DEATH = -1269005, + + SPELL_HASTE = 31458, + SPELL_MORTAL_WOUND = 31464, + SPELL_WING_BUFFET = 31475, + SPELL_WING_BUFFET_H = 38593, + SPELL_REFLECT = 38592 +}; struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI { @@ -49,86 +51,92 @@ struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 Haste_Timer; - uint32 SpellReflection_Timer; - uint32 MortalWound_Timer; - uint32 WingBuffet_Timer; + uint32 m_uiHasteTimer; + uint32 m_uiSpellReflectionTimer; + uint32 m_uiMortalWoundTimer; + uint32 m_uiWingBuffetTimer; void Reset() { - Haste_Timer = urand(15000, 23000); - SpellReflection_Timer = 30000; - MortalWound_Timer = 8000; - WingBuffet_Timer = urand(25000, 35000); + m_uiHasteTimer = urand(15000, 23000); + m_uiSpellReflectionTimer = 30000; + m_uiMortalWoundTimer = 8000; + m_uiWingBuffetTimer = urand(25000, 35000); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - 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 { DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RIFT,SPECIAL); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { - //Despawn Time Keeper - if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) + // Despawn Time Keeper + if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_TIME_KEEPER) { - if (m_creature->IsWithinDistInMap(who,20.0f)) + if (m_creature->IsWithinDistInMap(pWho, 20.0f)) { - DoScriptText(SAY_BANISH, m_creature); - m_creature->DealDamage(who, who->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (DoCastSpellIfCan(pWho, SPELL_BANISH_HELPER) == CAST_OK) + DoScriptText(SAY_BANISH, m_creature); } } - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::MoveInLineOfSight(pWho); } - 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; - //Attack Haste - if (Haste_Timer < diff) + // Attack Haste + if (m_uiHasteTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_HASTE); - Haste_Timer = urand(20000, 25000); - }else Haste_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_HASTE) == CAST_OK) + m_uiHasteTimer = urand(20000, 25000); + } + else + m_uiHasteTimer -= uiDiff; - //MortalWound_Timer - if (MortalWound_Timer < diff) + // MortalWound_Timer + 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(10000, 20000); + } + else + m_uiMortalWoundTimer -= uiDiff; - //Wing ruffet - if (WingBuffet_Timer < diff) + // Wing ruffet + if (m_uiWingBuffetTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WING_BUFFET : H_SPELL_WING_BUFFET); - WingBuffet_Timer = urand(20000, 30000); - }else WingBuffet_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WING_BUFFET : SPELL_WING_BUFFET_H) == CAST_OK) + m_uiWingBuffetTimer = urand(20000, 30000); + } + else + m_uiWingBuffetTimer -= uiDiff; + // Spell reflection if (!m_bIsRegularMode) { - if (SpellReflection_Timer < diff) + if (m_uiSpellReflectionTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_REFLECT); - SpellReflection_Timer = urand(25000, 35000); - }else SpellReflection_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_REFLECT) == CAST_OK) + m_uiSpellReflectionTimer = urand(25000, 35000); + } + else + m_uiSpellReflectionTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -142,9 +150,10 @@ CreatureAI* GetAI_boss_temporus(Creature* pCreature) void AddSC_boss_temporus() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_temporus"; - newscript->GetAI = &GetAI_boss_temporus; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_temporus"; + pNewScript->GetAI = &GetAI_boss_temporus; + pNewScript->RegisterSelf(); } 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 c4b16cf4c9..711d431112 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,47 +16,33 @@ /* 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 */ /* ContentData npc_medivh_bm npc_time_rift -npc_saat 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 MANGOS_DLL_DECL 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(); @@ -64,291 +50,265 @@ struct MANGOS_DLL_DECL npc_medivh_bmAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 SpellCorrupt_Timer; - uint32 Check_Timer; + void Reset() { } - bool Life75; - bool Life50; - bool Life25; + void AttackStart(Unit* /*pWho*/) override { } - void Reset() + void JustSummoned(Creature* pSummoned) override { - 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); - - m_creature->CastSpell(m_creature, SPELL_PORTAL_RUNE, true); - } - - void MoveInLineOfSight(Unit *who) - { - if (!m_pInstance) - return; - - if (who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 10.0f)) - { - 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; - } - else if (who->GetTypeId() == TYPEID_UNIT && m_creature->IsWithinDistInMap(who, 15.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) - 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); - } + 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); } } - 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); + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; - Check_Timer = 5000; +CreatureAI* GetAI_npc_medivh_black_morass(Creature* pCreature) +{ + return new npc_medivh_black_morassAI(pCreature); +} - 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; - } +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 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; - } + // always return true when we are handling this spell and effect + return true; + } - if (m_pInstance->GetData(TYPE_RIFT) == DONE) - { - DoScriptText(SAY_WIN, m_creature); - Check_Timer = 0; + return false; +} - if (m_creature->HasAura(SPELL_CHANNEL, EFFECT_INDEX_0)) - m_creature->RemoveAurasDueToSpell(SPELL_CHANNEL); +/*###### +## npc_time_rift +######*/ - //TODO: start the post-event here - m_pInstance->SetData(TYPE_MEDIVH,DONE); - } - } - else - Check_Timer -= diff; - } - - //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 { 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; + + uint8 m_uiRiftWaveCount; + uint8 m_uiRiftNumber; + uint8 m_uiRiftWaveId; void Reset() { - TimeRiftWave_Timer = 15000; - mRiftWaveCount = 0; - - if (!m_pInstance) - return; + 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) - return; - - if (m_pInstance->GetData(TYPE_MEDIVH) != IN_PROGRESS) - { - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); + if (!uiCreatureEntry) 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); - - if (Unit *Summon = m_creature->SummonCreature(creature_entry, x, y, z, m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) - { - if (Creature *temp = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_MEDIVH))) - Summon->AddThreat(temp); - } + 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 DoSelectSummon() + void DoSummon() { - uint32 entry = 0; + if (!m_pInstance) + return; - if ((mRiftWaveCount > 2 && mWaveId < 1) || mRiftWaveCount > 3) - mRiftWaveCount = 0; + uint32 uiSummonEntry = 0; - entry = PortalWaves[mWaveId].PortalMob[mRiftWaveCount]; - debug_log("SD2: npc_time_rift: summoning wave creature (Wave %u, Entry %u).", mRiftWaveCount, entry); + if (m_bIsFirstSummon) + { + // 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; + } - ++mRiftWaveCount; + // Set the next rift delay + if (uiSummonEntry != NPC_AEONUS) + m_pInstance->SetData(TYPE_TIME_RIFT, SPECIAL); - if (entry == NPC_WHELP) - { - for(uint8 i = 0; i < 3; ++i) - DoSummonAtRift(entry); + DoSummonCreatureAtRift(uiSummonEntry, m_creature); + m_bIsFirstSummon = false; } else - DoSummonAtRift(entry); + { + // 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; + + // 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; + + uiSummonEntry = aPortalWaves[m_uiRiftWaveId].uiPortalMob[m_uiRiftWaveCount]; + ++m_uiRiftWaveCount; + + // 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); + } } - void UpdateAI(const uint32 diff) + void JustSummoned(Creature* pSummoned) override { - if (!m_pInstance) - return; + switch (pSummoned->GetEntry()) + { + 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; + } + } - if (TimeRiftWave_Timer < diff) + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - DoSelectSummon(); - TimeRiftWave_Timer = 15000; + 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; } - 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) @@ -356,61 +316,34 @@ CreatureAI* GetAI_npc_time_rift(Creature* pCreature) return new npc_time_riftAI(pCreature); } -#define SAY_SAAT_WELCOME -1269019 - -#define GOSSIP_ITEM_OBTAIN "[PH] Obtain Chrono-Beacon" -#define SPELL_CHRONO_BEACON 34975 -#define ITEM_CHRONO_BEACON 24289 - -bool GossipHello_npc_saat(Player* pPlayer, Creature* pCreature) +bool EffectDummyCreature_npc_time_rift_channel(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE && !pPlayer->HasItemCount(ITEM_CHRONO_BEACON,1)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_OBTAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(10000, pCreature->GetGUID()); - return true; - } - else if (pPlayer->GetQuestRewardStatus(QUEST_OPENING_PORTAL) && !pPlayer->HasItemCount(ITEM_CHRONO_BEACON,1)) + // always check spellid and effectindex + if (uiSpellId == SPELL_RIFT_PERIODIC && uiEffIndex == EFFECT_INDEX_0) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_OBTAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(10001, pCreature->GetGUID()); + if (npc_time_riftAI* pTimeRiftAI = dynamic_cast(pCreatureTarget->AI())) + pTimeRiftAI->DoSummon(); + + // always return true when we are handling this spell and effect return true; } - pPlayer->SEND_GOSSIP_MENU(10002, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_saat(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer,SPELL_CHRONO_BEACON,false); - } - return true; + return false; } void AddSC_dark_portal() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_medivh_bm"; - newscript->GetAI = &GetAI_npc_medivh_bm; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_time_rift"; - newscript->GetAI = &GetAI_npc_time_rift; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_saat"; - newscript->pGossipHello = &GossipHello_npc_saat; - newscript->pGossipSelect = &GossipSelect_npc_saat; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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 34c9f66dd7..d9a0079efa 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,39 +7,136 @@ 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_MEDIVH = 10, - 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, +}; + +static const LOCATION 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} +}; + +// 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 MANGOS_DLL_DECL instance_dark_portal : public ScriptedInstance +{ + public: + instance_dark_portal(Map* pMap); + + void Initialize() override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) 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 DoHandleAreaTrigger(uint32 uiTriggerId); + + uint32 GetCurrentRiftId() { return m_uiWorldStateRiftCount; } + + void Update(uint32 uiDiff) override; + + private: + 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; - SPELL_RIFT_CHANNEL = 31387, + bool m_bHasIntroYelled; + uint32 m_uiMedivhYellCount; - RIFT_BOSS = 1 + uint32 m_uiNextPortalTimer; + uint8 m_uiCurrentRiftId; }; #endif 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 4484784f48..ad715a27f3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,319 +16,395 @@ /* 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} -}; + m_bHasIntroYelled(false), + m_uiMedivhYellCount(1), -struct Wave + m_uiNextPortalTimer(0), + m_uiCurrentRiftId(0) { - uint32 PortalBoss; // protector of current portal - uint32 NextPortalTime; // time to next portal, or 0 if portal boss need to be killed -}; + Initialize(); +} -static Wave RiftWaves[]= -{ - {RIFT_BOSS, 0}, - {NPC_DEJA, 0}, - {RIFT_BOSS, 120000}, - {NPC_TEMPO, 140000}, - {RIFT_BOSS, 120000}, - {NPC_AEONUS, 0} -}; - -struct MANGOS_DLL_DECL instance_dark_portal : public ScriptedInstance +void instance_dark_portal::Initialize() { - instance_dark_portal(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint32 m_uiRiftPortalCount; - uint32 m_uiShieldPercent; - uint8 m_uiRiftWaveCount; - uint8 m_uiRiftWaveId; - - uint32 m_uiNextPortal_Timer; - - uint64 m_uiMedivhGUID; - uint8 m_uiCurrentRiftId; + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() - { - m_uiMedivhGUID = 0; - Clear(); - } +void instance_dark_portal::DoResetEvent() +{ + UpdateWorldState(false); - void Clear() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + m_uiWorldStateShieldCount = 100; + m_uiWorldStateRiftCount = 0; - m_uiRiftPortalCount = 0; - m_uiShieldPercent = 100; - m_uiRiftWaveCount = 0; - m_uiRiftWaveId = 0; + m_uiCurrentRiftId = 0; + m_uiNextPortalTimer = 0; + m_uiMedivhYellCount = 1; +} - m_uiCurrentRiftId = 0; +void instance_dark_portal::UpdateWorldState(bool bEnable) +{ + m_uiWorldState = bEnable ? 1 : 0; - m_uiNextPortal_Timer = 0; - } + DoUpdateWorldState(WORLD_STATE_ID, m_uiWorldState); + DoUpdateWorldState(WORLD_STATE_SHIELD, m_uiWorldStateShieldCount); + DoUpdateWorldState(WORLD_STATE_RIFT, m_uiWorldStateRiftCount); +} - void InitWorldState(bool Enable = true) - { - DoUpdateWorldState(WORLD_STATE_BM,Enable ? 1 : 0); - DoUpdateWorldState(WORLD_STATE_BM_SHIELD, 100); - DoUpdateWorldState(WORLD_STATE_BM_RIFT, 0); - } +void instance_dark_portal::OnPlayerEnter(Player* /*pPlayer*/) +{ + UpdateWorldState(m_auiEncounter[TYPE_MEDIVH] == IN_PROGRESS ? true : false); +} - bool IsEncounterInProgress() const +void instance_dark_portal::DoHandleAreaTrigger(uint32 uiTriggerId) +{ + if (uiTriggerId == AREATRIGGER_ENTER) { - if (m_auiEncounter[0] == IN_PROGRESS) - return true; - - return false; + // Yell at instance entrance + if (!m_bHasIntroYelled) + { + if (Creature* pSaat = GetSingleCreatureFromStorage(NPC_SAAT)) + DoScriptText(SAY_SAAT_WELCOME, pSaat); + m_bHasIntroYelled = true; + } } - - void OnPlayerEnter(Player* pPlayer) + else if (uiTriggerId == AREATRIGGER_MEDIVH) { - if (m_auiEncounter[0] == IN_PROGRESS) - return; - - pPlayer->SendUpdateWorldState(WORLD_STATE_BM, 0); + // 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); } +} - void OnCreatureCreate(Creature* pCreature) +void instance_dark_portal::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - if (pCreature->GetEntry() == NPC_MEDIVH) - m_uiMedivhGUID = pCreature->GetGUID(); - } - - // what other conditions to check? - bool CanProgressEvent() - { - if (instance->GetPlayers().isEmpty()) - return false; - - return true; + case NPC_MEDIVH: + case NPC_SAAT: + case NPC_DARK_PORTAL_DUMMY: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - uint8 GetRiftWaveId() +void instance_dark_portal::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(m_uiRiftPortalCount) + case TYPE_MEDIVH: { - case 6: - m_uiRiftWaveId = 2; - return 1; - case 12: - m_uiRiftWaveId = 4; - return 3; - case 18: - return 5; - default: - return m_uiRiftWaveId; - } - } + if (uiData == IN_PROGRESS) + { + 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; + } - void SetData(uint32 uiType, uint32 uiData) - { - switch(uiType) - { - case TYPE_MEDIVH: - if (uiData == SPECIAL && m_auiEncounter[0] == IN_PROGRESS) + // ToDo: + // Start the Portal Crystal casting - by the Dark Portal Dumm Npc + // Also Start summoning the Dark Portal Beams + + UpdateWorldState(); + m_uiNextPortalTimer = 3000; + } + if (uiData == DONE) + { + // Yell for event finished + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) { - --m_uiShieldPercent; + DoScriptText(SAY_MEDIVH_WIN, pMedivh); + pMedivh->SetFacingTo(6.15f); + pMedivh->InterruptNonMeleeSpells(false); + pMedivh->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } - DoUpdateWorldState(WORLD_STATE_BM_SHIELD, m_uiShieldPercent); + // this may be completed further out in the post-event + Map::PlayerList const& players = instance->GetPlayers(); - if (!m_uiShieldPercent) + if (!players.isEmpty()) + { + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) { - if (Creature* pMedivh = instance->GetCreature(m_uiMedivhGUID)) + if (Player* pPlayer = itr->getSource()) { - if (pMedivh->isAlive()) - { - 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) + { + --m_uiWorldStateShieldCount; + DoUpdateWorldState(WORLD_STATE_SHIELD, m_uiWorldStateShieldCount); + + // Yell at 75%, 50% and 25% shield + if (m_uiWorldStateShieldCount < 100 - 25 * m_uiMedivhYellCount) { - if (uiData == IN_PROGRESS) + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) { - debug_log("SD2: Instance Dark Portal: Starting event."); - InitWorldState(); - m_auiEncounter[1] = IN_PROGRESS; - m_uiNextPortal_Timer = 15000; + DoScriptText(uiMedivhWeakYell[m_uiMedivhYellCount - 1], pMedivh); + ++m_uiMedivhYellCount; } + } - if (uiData == DONE) + // Kill the npc when the shield is broken + if (!m_uiWorldStateShieldCount) + { + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) { - // 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()) - { - 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; } - break; - case TYPE_RIFT: - if (uiData == SPECIAL) - { - if (m_uiRiftPortalCount < 7) - m_uiNextPortal_Timer = 5000; - } - else - m_auiEncounter[1] = uiData; - break; - } - } - - uint32 GetData(uint32 uiType) - { - switch(uiType) + } + m_auiEncounter[uiType] = uiData; + return; + case TYPE_TIME_RIFT: { - 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; + // 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; } - return 0; + case TYPE_CHRONO_LORD: + case TYPE_TEMPORUS: + if (m_auiEncounter[uiType] != DONE) // Keep the DONE-information stored + m_auiEncounter[uiType] = uiData; + break; + case TYPE_AEONUS: + if (uiData == DONE) + UpdateWorldState(false); + m_auiEncounter[uiType] = uiData; + break; + default: + return; } - uint64 GetData64(uint32 uiData) + if (uiData == DONE) { - if (uiData == DATA_MEDIVH) - return m_uiMedivhGUID; + 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]; - return 0; + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - Creature* SummonedPortalBoss(Creature* pSource) +uint32 instance_dark_portal::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_dark_portal::Load(const char* chrIn) +{ + if (!chrIn) { - uint32 uiEntry = RiftWaves[GetRiftWaveId()].PortalBoss; + OUT_LOAD_INST_DATA_FAIL; + return; + } - if (uiEntry == RIFT_BOSS) - uiEntry = RandRiftBoss(); + OUT_LOAD_INST_DATA(chrIn); - 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); + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5]; - debug_log("SD2: Instance Dark Portal: Summoning rift boss uiEntry %u.", uiEntry); + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } - if (Creature* pSummoned = pSource->SummonCreature(uiEntry, x, y, z, pSource->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000)) - return pSummoned; + OUT_LOAD_INST_DATA_COMPLETE; +} - debug_log("SD2: Instance Dark Portal: what just happened there? No boss, no loot, no fun..."); - return NULL; +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 DoSpawnPortal() +void instance_dark_portal::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - if (Creature* pMedivh = instance->GetCreature(m_uiMedivhGUID)) - { - uint8 uiTmp = urand(0, 2); + 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; + } +} - if (uiTmp >= m_uiCurrentRiftId) - ++uiTmp; +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; + } +} - debug_log("SD2: Instance Dark Portal: Creating Time Rift at locationId %i (old locationId was %u).", uiTmp, m_uiCurrentRiftId); +void instance_dark_portal::DoSpawnNextPortal() +{ + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) + { + // Randomize portal locations + uint8 uiTmp = urand(0, 2); - m_uiCurrentRiftId = uiTmp; + if (uiTmp >= 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); + debug_log("SD2: instance_dark_portal: SetRiftId %u, old was id %u.", uiTmp, m_uiCurrentRiftId); - if (Creature* pBoss = SummonedPortalBoss(pTemp)) - { - if (pBoss->GetEntry() == NPC_AEONUS) - pBoss->AddThreat(pMedivh); - else - { - pBoss->AddThreat(pTemp); - pTemp->CastSpell(pBoss, SPELL_RIFT_CHANNEL, false); - } - } - } - } - } + m_uiCurrentRiftId = uiTmp; - void Update(uint32 uiDiff) - { - if (m_auiEncounter[1] != IN_PROGRESS) - return; + // Summon next portal + pMedivh->SummonCreature(NPC_TIME_RIFT, afPortalLocation[uiTmp].x, afPortalLocation[uiTmp].y, afPortalLocation[uiTmp].z, afPortalLocation[uiTmp].o, TEMPSUMMON_CORPSE_DESPAWN, 0); + } +} - //add delay timer? - if (!CanProgressEvent()) - { - Clear(); - return; - } +void instance_dark_portal::Update(uint32 uiDiff) +{ + if (GetData(TYPE_MEDIVH) != IN_PROGRESS) + return; - if (m_uiNextPortal_Timer) + if (m_uiNextPortalTimer) + { + if (m_uiNextPortalTimer <= uiDiff) { - if (m_uiNextPortal_Timer <= uiDiff) - { - ++m_uiRiftPortalCount; - - DoUpdateWorldState(WORLD_STATE_BM_RIFT, m_uiRiftPortalCount); + DoUpdateWorldState(WORLD_STATE_RIFT, ++m_uiWorldStateRiftCount); - DoSpawnPortal(); - m_uiNextPortal_Timer = RiftWaves[GetRiftWaveId()].NextPortalTime; - } - else - m_uiNextPortal_Timer -= uiDiff; + DoSpawnNextPortal(); + m_uiNextPortalTimer = 0; } + else + m_uiNextPortalTimer -= uiDiff; } -}; +} 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* newscript; - newscript = new Script; - newscript->Name = "instance_dark_portal"; - newscript->GetInstanceData = &GetInstanceData_instance_dark_portal; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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/dragon_soul/boss_deathwing.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_deathwing.cpp new file mode 100644 index 0000000000..fa18fc733a --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_deathwing.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_deathwing +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_deathwing() +{ +} diff --git a/scripts/northrend/ruby_sanctum/boss_zarithian.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_hagara.cpp similarity index 81% rename from scripts/northrend/ruby_sanctum/boss_zarithian.cpp rename to scripts/kalimdor/caverns_of_time/dragon_soul/boss_hagara.cpp index 8d62b32e92..9dea65f7f5 100644 --- a/scripts/northrend/ruby_sanctum/boss_zarithian.cpp +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_hagara.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,10 +15,14 @@ */ /* ScriptData -SDName: boss_zarithian -SD%Complete: -SDComment:placeholder -SDCategory: Ruby Sanctum +SDName: boss_hagara +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul EndScriptData */ #include "precompiled.h" + +void AddSC_boss_hagara() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/boss_morchok.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_morchok.cpp new file mode 100644 index 0000000000..3eee345955 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_morchok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_morchok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_morchok() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/boss_ultraxion.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_ultraxion.cpp new file mode 100644 index 0000000000..7c7879332f --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_ultraxion.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ultraxion +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ultraxion() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/boss_warlord_zonozz.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_warlord_zonozz.cpp new file mode 100644 index 0000000000..8e60d577a5 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_warlord_zonozz.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_warlord_zonozz +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_warlord_zonozz() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/boss_warmaster_blackhorn.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_warmaster_blackhorn.cpp new file mode 100644 index 0000000000..2a258f7d66 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_warmaster_blackhorn.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_blackhorn +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_warmaster_blackhorn() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/boss_yorsahj.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_yorsahj.cpp new file mode 100644 index 0000000000..6c7cc55028 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/boss_yorsahj.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_yorsahj +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_yorsahj() +{ +} diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falryn.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/dragon_soul.cpp similarity index 81% rename from scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falryn.cpp rename to scripts/kalimdor/caverns_of_time/dragon_soul/dragon_soul.cpp index b7c8771cb3..2f834c2170 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falryn.cpp +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/dragon_soul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,10 +15,14 @@ */ /* ScriptData -SDName: boss_falryn -SD%Complete: 0% -SDComment: -SDCategory: Halls of Reflection +SDName: dragon_soul +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul EndScriptData */ #include "precompiled.h" + +void AddSC_dragon_soul() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/dragon_soul.h b/scripts/kalimdor/caverns_of_time/dragon_soul/dragon_soul.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/dragon_soul.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/caverns_of_time/dragon_soul/instance_dragon_soul.cpp b/scripts/kalimdor/caverns_of_time/dragon_soul/instance_dragon_soul.cpp new file mode 100644 index 0000000000..bce483b6c3 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/dragon_soul/instance_dragon_soul.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_dragon_soul +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Dragon Soul +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_dragon_soul() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_baine.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_baine.cpp new file mode 100644 index 0000000000..80ed500697 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_baine.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_echo_of_baine +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_echo_of_baine() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_jaina.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_jaina.cpp new file mode 100644 index 0000000000..fb94a1fa89 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_jaina.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_echo_of_jaina +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_echo_of_jaina() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_sylvanas.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_sylvanas.cpp new file mode 100644 index 0000000000..ac7be086e0 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_sylvanas.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_echo_of_sylvanas +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_echo_of_sylvanas() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_tyrande.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_tyrande.cpp new file mode 100644 index 0000000000..e77d8e672d --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/boss_echo_of_tyrande.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_echo_of_tyrande +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_echo_of_tyrande() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/boss_murozond.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/boss_murozond.cpp new file mode 100644 index 0000000000..b4267aad2c --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/boss_murozond.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_murozond +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_murozond() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/end_of_time.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/end_of_time.cpp new file mode 100644 index 0000000000..6e2f440586 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/end_of_time.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: end_of_time +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_end_of_time() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/end_of_time.h b/scripts/kalimdor/caverns_of_time/end_of_time/end_of_time.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/end_of_time.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/caverns_of_time/end_of_time/instance_end_of_time.cpp b/scripts/kalimdor/caverns_of_time/end_of_time/instance_end_of_time.cpp new file mode 100644 index 0000000000..8f12d72bfb --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/end_of_time/instance_end_of_time.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_end_of_time +SD%Complete: 0 +SDComment: Placeholder +SDCategory: End of Time +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_end_of_time() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_archbishop_benedictus.cpp b/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_archbishop_benedictus.cpp new file mode 100644 index 0000000000..ff6137eb4c --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_archbishop_benedictus.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_archbishop_benedictus +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Hour of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_archbishop_benedictus() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_arcurion.cpp b/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_arcurion.cpp new file mode 100644 index 0000000000..fd08d64d8c --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_arcurion.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_arcurion +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Hour of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_arcurion() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_asira_dawnslayer.cpp b/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_asira_dawnslayer.cpp new file mode 100644 index 0000000000..a051485a0a --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hour_of_twilight/boss_asira_dawnslayer.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_asira_dawnslayer +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Hour of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_asira_dawnslayer() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/hour_of_twilight/hour_of_twilight.h b/scripts/kalimdor/caverns_of_time/hour_of_twilight/hour_of_twilight.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hour_of_twilight/hour_of_twilight.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/caverns_of_time/hour_of_twilight/instance_hour_of_twilight.cpp b/scripts/kalimdor/caverns_of_time/hour_of_twilight/instance_hour_of_twilight.cpp new file mode 100644 index 0000000000..61a23df59f --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hour_of_twilight/instance_hour_of_twilight.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_hour_of_twilight +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Hour of Twilight +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_hour_of_twilight() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp b/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp deleted file mode 100644 index 00667807f6..0000000000 --- a/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp +++ /dev/null @@ -1,586 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Archimonde -SD%Complete: 85 -SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented. -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(); - ArchimondeGUID = 0; - Reset(); - } - - ScriptedInstance* m_pInstance; - uint64 ArchimondeGUID; - uint32 CheckTimer; - - void Reset() - { - CheckTimer = 1000; - - if (m_pInstance) - ArchimondeGUID = m_pInstance->GetData64(DATA_ARCHIMONDE); - - 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 (CheckTimer < diff) - { - if (Creature* Archimonde = m_creature->GetMap()->GetCreature(ArchimondeGUID)) - { - 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 -{ - 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(); } - - uint64 TargetGUID; - uint32 ChangeTargetTimer; - - void Reset() - { - TargetGUID = 0; - ChangeTargetTimer = 5000; - } - - void MoveInLineOfSight(Unit* who) - { - //will update once 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 (!TargetGUID && who->GetTypeId() == TYPEID_PLAYER) - TargetGUID = who->GetGUID(); - } - - void DamageTaken(Unit *done_by, uint32 &damage) { damage = 0; } - - void UpdateAI(const uint32 diff) - { - if (ChangeTargetTimer < diff) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(TargetGUID)) - { - m_creature->GetMotionMaster()->MoveFollow(pPlayer, 0.0f, 0.0f); - TargetGUID = 0; - } - 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); - } - - ChangeTargetTimer = 5000; - }else ChangeTargetTimer -= diff; - } -}; - -/* Finally, Archimonde's script. His script isn't extremely complex, most are simply spells on timers. - The only complicated aspect of the battle is Finger of Death and Doomfire, with Doomfire being the - hardest bit to code. Finger of Death is simply a distance check - if no one is in melee range, then - 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. */ - -struct MANGOS_DLL_DECL boss_archimondeAI : public ScriptedAI -{ - boss_archimondeAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint64 DoomfireSpiritGUID; - uint64 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() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_ARCHIMONDE, NOT_STARTED); - - DoomfireSpiritGUID = 0; - WorldTreeGUID = 0; - - 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; - } - - void Aggro(Unit* pWho) - { - m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); - DoScriptText(SAY_AGGRO, m_creature); - - m_creature->SetInCombatWithZone(); - - if (m_pInstance) - m_pInstance->SetData(TYPE_ARCHIMONDE, IN_PROGRESS); - } - - void KilledUnit(Unit* pVictim) - { - 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; - } - - if (pVictim->GetTypeId() != TYPEID_PLAYER) - return; - - switch(pVictim->getClass()) - { - case CLASS_PRIEST: - case CLASS_PALADIN: - case CLASS_WARLOCK: - pVictim->CastSpell(m_creature, SPELL_SOUL_CHARGE_RED, true); - break; - case CLASS_MAGE: - case CLASS_ROGUE: - case CLASS_WARRIOR: - pVictim->CastSpell(m_creature, SPELL_SOUL_CHARGE_YELLOW, true); - break; - case CLASS_DRUID: - case CLASS_SHAMAN: - case CLASS_HUNTER: - pVictim->CastSpell(m_creature, SPELL_SOUL_CHARGE_GREEN, true); - break; - } - } - - void JustDied(Unit *victim) - { - DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_ARCHIMONDE, DONE); - } - - bool CanUseFingerOfDeath() - { - // 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) - { - 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())); - } - - return false; - } - - void JustSummoned(Creature* pSummoned) - { - if (pSummoned->GetEntry() == CREATURE_ANCIENT_WISP) - pSummoned->AI()->AttackStart(m_creature); - else - { - pSummoned->setFaction(m_creature->getFaction()); - pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - if (pSummoned->GetEntry() == CREATURE_DOOMFIRE_SPIRIT) - { - DoomfireSpiritGUID = pSummoned->GetGUID(); - } - - if (pSummoned->GetEntry() == CREATURE_DOOMFIRE) - { - pSummoned->CastSpell(pSummoned,SPELL_DOOMFIRE_SPAWN,false); - pSummoned->CastSpell(pSummoned,SPELL_DOOMFIRE,true,0,0,m_creature->GetGUID()); - - if (Creature* pDoomfireSpirit = m_creature->GetMap()->GetCreature(DoomfireSpiritGUID)) - { - pSummoned->GetMotionMaster()->MoveFollow(pDoomfireSpirit,0.0f,0.0f); - DoomfireSpiritGUID = 0; - } - } - } - - //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) - { - if (!m_creature->isInCombat()) - { - if (m_pInstance) - { - // 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))) - { - 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 (DrainNordrassilTimer < diff) - { - if (!IsChanneling) - { - Creature *temp = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1200000); - - if (temp) - WorldTreeGUID = temp->GetGUID(); - - if (Creature *Nordrassil = m_creature->GetMap()->GetCreature(WorldTreeGUID)) - { - Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Nordrassil->SetDisplayId(11686); - DoCastSpellIfCan(Nordrassil, SPELL_DRAIN_WORLD_TREE); - IsChanneling = true; - } - } - - if (Creature *Nordrassil = m_creature->GetMap()->GetCreature(WorldTreeGUID)) - { - Nordrassil->CastSpell(m_creature, SPELL_DRAIN_WORLD_TREE_2, true); - DrainNordrassilTimer = 1000; - } - }else DrainNordrassilTimer -= diff; - } - - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_creature->GetHealthPercent() < 10.0f && !BelowTenPercent && !Enraged) - BelowTenPercent = true; - - if (!Enraged) - { - if (EnrageTimer < diff) - { - if (m_creature->GetHealthPercent() > 10.0f) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - Enraged = true; - DoScriptText(SAY_ENRAGE, m_creature); - } - }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; - } - - if (BelowTenPercent) - { - if (!HasProtected) - { - 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 (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); - } - - if (Enraged) - { - if (HandOfDeathTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAND_OF_DEATH); - HandOfDeathTimer = 2000; - }else HandOfDeathTimer -= diff; - return; // Don't do anything after this point. - } - - if (GripOfTheLegionTimer < diff) - { - 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 (AirBurstTimer < diff) - { - 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 (FearTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEAR); - FearTimer = 42000; - }else FearTimer -= diff; - - if (DoomfireTimer < diff) - { - if (!urand(0, 1)) - DoScriptText(SAY_DOOMFIRE1, m_creature); - else - DoScriptText(SAY_DOOMFIRE2, m_creature); - - Unit *temp = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (!temp) - temp = m_creature->getVictim(); - - //replace with spell cast 31903 once implicitTarget 73 implemented - SummonDoomfire(temp); - - //supposedly three doomfire can be up at the same time - DoomfireTimer = 20000; - }else DoomfireTimer -= diff; - - if (MeleeRangeCheckTimer < diff) - { - if (CanUseFingerOfDeath()) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_FINGER_OF_DEATH); - - MeleeRangeCheckTimer = 1000; - } - - MeleeRangeCheckTimer = 5000; - }else MeleeRangeCheckTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_archimonde(Creature* pCreature) -{ - return new boss_archimondeAI(pCreature); -} - -CreatureAI* GetAI_mob_doomfire(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); -} - -void AddSC_boss_archimonde() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_archimonde"; - newscript->GetAI = &GetAI_boss_archimonde; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_doomfire"; - newscript->GetAI = &GetAI_mob_doomfire; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_doomfire_targetting"; - newscript->GetAI = &GetAI_mob_doomfire_targetting; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_ancient_wisp"; - newscript->GetAI = &GetAI_mob_ancient_wisp; - newscript->RegisterSelf(); -} diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h b/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h deleted file mode 100644 index 851936027b..0000000000 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef DEF_HYJAL_H -#define DEF_HYJAL_H - -#define ERROR_INST_DATA "SD2: Instance data not set properly for Mount Hyjal. Encounters will be buggy" - -enum eNPC -{ - NPC_JAINA = 17772, - NPC_THRALL = 17852, - NPC_TYRANDE = 17948, - - // Bosses summoned after every 8 waves - NPC_WINTERCHILL = 17767, - NPC_ANETHERON = 17808, - NPC_KAZROGAL = 17888, - NPC_AZGALOR = 17842, - NPC_ARCHIMONDE = 17968, - - // Trash Mobs summoned in waves - NPC_NECRO = 17899, - NPC_ABOMI = 17898, - NPC_GHOUL = 17895, - NPC_BANSH = 17905, - NPC_CRYPT = 17897, - NPC_GARGO = 17906, - NPC_FROST = 17907, - NPC_GIANT = 17908, - NPC_STALK = 17916, - - NPC_WATER_ELEMENTAL = 18001, - NPC_DIRE_WOLF = 17854, - - GO_ANCIENT_GEM = 185557 -}; - -enum -{ - MAX_ENCOUNTER = 5, - - WORLD_STATE_WAVES = 2842, - WORLD_STATE_ENEMY = 2453, - WORLD_STATE_ENEMYCOUNT = 2454, - - // ACID scripted, don't touch id's (or provide update for ACID) - TYPE_WINTERCHILL = 11, - TYPE_ANETHERON = 2, - TYPE_KAZROGAL = 9, - TYPE_AZGALOR = 6, - - TYPE_ARCHIMONDE = 4, - - DATA_ANETHERON = 1, - DATA_RAGEWINTERCHILL = 10, - DATA_AZGALOR = 5, - DATA_KAZROGAL = 8, - - DATA_ARCHIMONDE = 3, - DATA_JAINAPROUDMOORE = 7, - DATA_THRALL = 12, - DATA_TYRANDEWHISPERWIND = 13, - - DATA_TRASH = 14, - DATA_RESET_TRASH_COUNT = 15, - TYPE_RETREAT = 16 -}; - -#endif diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp b/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp deleted file mode 100644 index bfde3223e5..0000000000 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: HyjalAI -SD%Complete: 90 -SDComment: -SDCategory: Caverns of Time, Mount Hyjal -EndScriptData */ - -#include "precompiled.h" -#include "hyjalAI.h" - -struct sHyjalLocation -{ - eBaseArea m_pBaseArea; - float m_fX, m_fY, m_fZ; -}; - -// Locations for summoning waves -sHyjalLocation m_aHyjalSpawnLoc[]= -{ - {BASE_ALLY, 4979.010f, -1709.134f, 1339.674f}, - {BASE_ALLY, 4969.123f, -1705.904f, 1341.363f}, - {BASE_ALLY, 4970.260f, -1698.546f, 1341.200f}, - {BASE_ALLY, 4975.262f, -1698.239f, 1341.427f}, - {BASE_HORDE, 5557.582f, -2587.159f, 1481.644f}, - {BASE_HORDE, 5545.901f, -2582.246f, 1479.256f}, - {BASE_HORDE, 5565.642f, -2565.666f, 1481.635f}, - {BASE_HORDE, 5547.218f, -2574.589f, 1479.194f} -}; - -// used to inform the wave where to move -sHyjalLocation m_aHyjalWaveMoveTo[]= -{ - {BASE_ALLY, 5018.654f, -1752.074f, 1322.203f}, - {BASE_HORDE, 5504.569f, -2688.489f, 1479.991f} -}; - -struct sHyjalYells -{ - uint32 uiCreatureEntry; - YellType m_pYellType; // Used to determine the type of yell (attack, rally, etc) - int32 m_iTextId; // The text id to be yelled -}; - -sHyjalYells m_aHyjalYell[]= -{ - {NPC_JAINA, ATTACKED, -1534000}, - {NPC_JAINA, ATTACKED, -1534001}, - {NPC_JAINA, INCOMING, -1534002}, - {NPC_JAINA, BEGIN, -1534003}, - {NPC_JAINA, RALLY, -1534004}, - {NPC_JAINA, RALLY, -1534005}, - {NPC_JAINA, FAILURE, -1534006}, - {NPC_JAINA, SUCCESS, -1534007}, - {NPC_JAINA, DEATH, -1534008}, - - {NPC_THRALL, ATTACKED, -1534009}, - {NPC_THRALL, ATTACKED, -1534010}, - {NPC_THRALL, INCOMING, -1534011}, - {NPC_THRALL, BEGIN, -1534012}, - {NPC_THRALL, RALLY, -1534013}, - {NPC_THRALL, RALLY, -1534014}, - {NPC_THRALL, FAILURE, -1534015}, - {NPC_THRALL, SUCCESS, -1534016}, - {NPC_THRALL, DEATH, -1534017} -}; - -void hyjalAI::Reset() -{ - // GUIDs - m_uiBossGUID[0] = 0; - m_uiBossGUID[1] = 0; - - // Timers - m_uiNextWaveTimer = 10000; - m_uiWaveMoveTimer = 15000; - m_uiCheckTimer = 0; - m_uiRetreatTimer = 25000; - - // Misc - m_uiWaveCount = 0; - m_uiEnemyCount = 0; - - // Set base area based on creature entry - switch(m_creature->GetEntry()) - { - case NPC_JAINA: - m_uiBase = BASE_ALLY; - DoCastSpellIfCan(m_creature, SPELL_BRILLIANCE_AURA, CAST_TRIGGERED); - break; - case NPC_THRALL: - m_uiBase = BASE_HORDE; - break; - } - - // Bools - m_bIsEventInProgress = false; - m_bIsSummoningWaves = false; - - m_bIsRetreating = false; - m_bDebugMode = false; - - // Flags - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - // 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) : m_pInstance->GetData(TYPE_WINTERCHILL); - m_bIsSecondBossDead = m_uiBase ? m_pInstance->GetData(TYPE_AZGALOR) : m_pInstance->GetData(TYPE_ANETHERON); - - // Reset Instance Data for trash count - m_pInstance->SetData(DATA_RESET_TRASH_COUNT, 0); -} - -void hyjalAI::EnterEvadeMode() -{ - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); - m_creature->LoadCreatureAddon(); - - if (m_creature->isAlive()) - m_creature->GetMotionMaster()->MoveTargetedHome(); - - m_creature->SetLootRecipient(NULL); -} - -void hyjalAI::JustReachedHome() -{ - if (m_uiBase == BASE_ALLY) - DoCastSpellIfCan(m_creature, SPELL_BRILLIANCE_AURA, CAST_TRIGGERED); - - m_bIsFirstBossDead = m_uiBase ? m_pInstance->GetData(TYPE_KAZROGAL) : m_pInstance->GetData(TYPE_WINTERCHILL); - m_bIsSecondBossDead = m_uiBase ? m_pInstance->GetData(TYPE_AZGALOR) : m_pInstance->GetData(TYPE_ANETHERON); -} - -void hyjalAI::Aggro(Unit *who) -{ - for(uint8 i = 0; i < MAX_SPELL; ++i) - if (m_aSpells[i].m_uiCooldown) - m_uiSpellTimer[i] = m_aSpells[i].m_uiCooldown; - - DoTalk(ATTACKED); -} - -void hyjalAI::SpawnCreatureForWave(uint32 uiMobEntry) -{ - sHyjalLocation* pSpawn = NULL; - - uint32 uiMaxCount = sizeof(m_aHyjalSpawnLoc)/sizeof(sHyjalLocation); - uint32 uiRandId = urand(1, uiMaxCount/2); //unsafe, if array becomes uneven. - - uint32 uiJ = 0; - - for (uint32 i = 0; i < uiMaxCount; ++i) - { - if (m_aHyjalSpawnLoc[i].m_pBaseArea != m_uiBase) - continue; - - ++uiJ; - - if (uiJ == uiRandId) - { - pSpawn = &m_aHyjalSpawnLoc[i]; - break; - } - } - - if (pSpawn) - m_creature->SummonCreature(uiMobEntry, pSpawn->m_fX, pSpawn->m_fY, pSpawn->m_fZ, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); -} - -void hyjalAI::JustSummoned(Creature* pSummoned) -{ - // not interesting for us - if (pSummoned->GetEntry() == NPC_WATER_ELEMENTAL || pSummoned->GetEntry() == NPC_DIRE_WOLF) - return; - - // Increment Enemy Count to be used in World States and instance script - ++m_uiEnemyCount; - - sHyjalLocation* pMove = NULL; - - uint32 uiMaxCount = sizeof(m_aHyjalWaveMoveTo)/sizeof(sHyjalLocation); - - for (uint32 i = 0; i < uiMaxCount; ++i) - { - if (m_aHyjalWaveMoveTo[i].m_pBaseArea != m_uiBase) - continue; - - pMove = &m_aHyjalWaveMoveTo[i]; - break; - } - - if (pMove) - { - float fX, fY, fZ; - pSummoned->GetRandomPoint(pMove->m_fX, pMove->m_fY, pMove->m_fZ, 10.0f, fX, fY, fZ); - - pSummoned->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); - } - - // Check if creature is a boss. - if (pSummoned->IsWorldBoss()) - { - if (!m_bIsFirstBossDead) - m_uiBossGUID[0] = pSummoned->GetGUID(); - else - m_uiBossGUID[1] = pSummoned->GetGUID(); - - m_uiCheckTimer = 5000; - } - else - lWaveMobGUIDList.push_back(pSummoned->GetGUID()); -} - -void hyjalAI::SummonNextWave() -{ - // 1 in 4 chance we give a rally yell. Not sure if the chance is offilike. - if (!urand(0, 3)) - DoTalk(RALLY); - - if (!m_pInstance) - { - error_log(ERROR_INST_DATA); - return; - } - - sHyjalWave* pWaveData = m_uiBase ? &m_aHyjalWavesHorde[m_uiWaveCount] : &m_aHyjalWavesAlliance[m_uiWaveCount]; - - if (!pWaveData) - { - error_log("SD2: hyjalAI not able to obtain wavedata for SummonNextWave."); - return; - } - - m_uiEnemyCount = m_pInstance->GetData(DATA_TRASH); - - for(uint8 i = 0; i < MAX_WAVE_MOB; ++i) - { - if (pWaveData->m_auiMobEntry[i]) - SpawnCreatureForWave(pWaveData->m_auiMobEntry[i]); - } - - if (!pWaveData->m_bIsBoss) - { - 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 - - // Set world state to our current wave number - m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, stateValue); - // Enable world state - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 1); - - m_pInstance->SetData(DATA_TRASH, m_uiEnemyCount); // Send data for instance script to update count - - if (!m_bDebugMode) - m_uiNextWaveTimer = pWaveData->m_uiWaveTimer; - else - { - m_uiNextWaveTimer = 15000; - debug_log("SD2: HyjalAI: debug mode is enabled. Next Wave in 15 seconds"); - } - } - else - { - // Set world state for waves to 0 to disable it. - m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, 0); - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 1); - - // Set World State for enemies invading to 1. - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, 1); - - m_bIsSummoningWaves = false; - } - - m_uiWaveMoveTimer = 15000; - m_uiCheckTimer = 5000; - ++m_uiWaveCount; -} - -void hyjalAI::StartEvent() -{ - if (!m_pInstance) - 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); - - m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, 0); - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 0); - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, 0); -} - -void hyjalAI::DoTalk(YellType pYellType) -{ - sHyjalYells* pYell = NULL; - - uint32 uiMaxCount = sizeof(m_aHyjalYell)/sizeof(sHyjalYells); - bool bGetNext = false; - - for (uint32 i = 0; i < uiMaxCount; ++i) - { - if (m_aHyjalYell[i].uiCreatureEntry == m_creature->GetEntry() && m_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) - { - if (!bGetNext && urand(0, 1)) - { - bGetNext = true; - continue; - } - } - - pYell = &m_aHyjalYell[i]; - break; - } - } - - if (pYell) - DoScriptText(pYell->m_iTextId, m_creature); -} - -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) - //{ - //despawn; - //} -} - -void hyjalAI::Retreat() -{ - //this will trigger ancient gem respawn - if (m_pInstance) - m_pInstance->SetData(TYPE_RETREAT, SPECIAL); - - DoCastSpellIfCan(m_creature, SPELL_MASS_TELEPORT); - - m_bIsRetreating = true; -} - -void hyjalAI::JustDied(Unit* pKiller) -{ - DoTalk(DEATH); - - //TODO: in case they die during boss encounter, then what? despawn boss? -} - -void hyjalAI::UpdateAI(const uint32 uiDiff) -{ - if (!m_bIsEventInProgress) - return; - - if (m_bIsSummoningWaves && m_pInstance) - { - if (m_uiWaveMoveTimer < uiDiff) - { - // Skip the master timer, and start next wave in 5. Clear the list, it should not be any here now. - if (!m_pInstance->GetData(DATA_TRASH)) - { - lWaveMobGUIDList.clear(); - m_uiNextWaveTimer = 5000; - } - - if (!lWaveMobGUIDList.empty()) - { - for(std::list::iterator itr = lWaveMobGUIDList.begin(); itr != lWaveMobGUIDList.end(); ++itr) - { - if (Creature* pTemp = m_pInstance->instance->GetCreature(*itr)) - { - if (!pTemp->isAlive() || pTemp->getVictim()) - continue; - - pTemp->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - pTemp->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - } - } - } - m_uiWaveMoveTimer = 10000; - } - else - m_uiWaveMoveTimer -= uiDiff; - - if (m_uiNextWaveTimer < uiDiff) - SummonNextWave(); - else - m_uiNextWaveTimer -= uiDiff; - } - - if (m_uiCheckTimer < uiDiff) - { - for(uint8 i = 0; i < 2; ++i) - { - if (m_uiBossGUID[i]) - { - Creature* pBoss = m_creature->GetMap()->GetCreature(m_uiBossGUID[i]); - - if (pBoss && !pBoss->isAlive()) - { - if (m_uiBossGUID[i] == m_uiBossGUID[0]) - { - DoTalk(INCOMING); - m_bIsFirstBossDead = true; - } - else if (m_uiBossGUID[i] == m_uiBossGUID[1]) - { - DoTalk(SUCCESS); - m_bIsSecondBossDead = true; - } - - m_bIsEventInProgress = false; - m_uiCheckTimer = 0; - - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - m_uiBossGUID[i] = 0; - - // Reset world state for enemies to disable it - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 0); - } - } - } - - m_uiCheckTimer = 5000; - } - else - m_uiCheckTimer -= uiDiff; - - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - for(uint8 i = 0; i < MAX_SPELL; ++i) - { - if (m_aSpells[i].m_uiSpellId) - { - if (m_uiSpellTimer[i] < uiDiff) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - Unit* pTarget = NULL; - - 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; - case TARGETTYPE_VICTIM: pTarget = m_creature->getVictim(); break; - } - - if (pTarget) - { - DoCastSpellIfCan(pTarget, m_aSpells[i].m_uiSpellId); - m_uiSpellTimer[i] = m_aSpells[i].m_uiCooldown; - } - } - else - m_uiSpellTimer[i] -= uiDiff; - } - } - - DoMeleeAttackIfReady(); -} diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h b/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h deleted file mode 100644 index d188213d96..0000000000 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h +++ /dev/null @@ -1,199 +0,0 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_HYJALAI_H -#define SC_HYJALAI_H - -#include "hyjal.h" - -enum eBaseArea -{ - BASE_ALLY = 0, - BASE_HORDE = 1 -}; - -enum eMisc -{ - MAX_SPELL = 3, - MAX_WAVES = 9, - MAX_WAVE_MOB = 18, - - ITEM_TEAR_OF_GODDESS = 24494 -}; - -enum eSpell -{ - SPELL_MASS_TELEPORT = 16807, - - // Spells for Jaina - SPELL_BRILLIANCE_AURA = 31260, - SPELL_BLIZZARD = 31266, - SPELL_PYROBLAST = 31263, - SPELL_SUMMON_ELEMENTALS = 31264, - - // Thrall spells - SPELL_CHAIN_LIGHTNING = 31330, - SPELL_FERAL_SPIRIT = 31331 -}; - -struct sHyjalWave -{ - uint32 m_auiMobEntry[MAX_WAVE_MOB]; // Stores Creature Entries to be summoned in Waves - uint32 m_uiWaveTimer; // The timer before the next wave is summoned - bool m_bIsBoss; // Simply used to inform the wave summoner that the next wave contains a boss to halt all waves after that -}; - -// Waves that will be summoned in the Alliance Base -static sHyjalWave m_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, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 180000, false}, - // All 8 Waves are summoned, summon Rage Winterchill, next few waves are for Anetheron - {NPC_WINTERCHILL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true}, - // Anetheron 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, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_BANSH, NPC_BANSH, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 180000, false}, - // All 8 Waves are summoned, summon Anatheron - {NPC_ANETHERON, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true} -}; - -// Waves that are summoned in the Horde base -static sHyjalWave m_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, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 120000, false}, - {NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_FROST, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_FROST, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_BANSH, NPC_BANSH, 180000, false}, - // All 8 Waves are summoned, summon Kaz'Rogal, next few waves are for Azgalor - {NPC_KAZROGAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true}, - // Azgalor Wave 1-8 - {NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_FROST, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, 0, 0, 0, 0, 120000, false}, - {NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, 0, 0, 0, 0, 120000, false}, - {NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 120000, false}, - {NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, 0, 0, 0, 0, 120000, false}, - {NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_STALK, NPC_STALK, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, 0, 0, 0, 0, 0, 0, 120000, false}, - {NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_STALK, NPC_STALK, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_NECRO, NPC_NECRO, 0, 0, 180000, false}, - // All 8 Waves are summoned, summon Azgalor - {NPC_AZGALOR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true} -}; - -enum TargetType // Used in the spell cast system for the AI -{ - TARGETTYPE_SELF = 0, - TARGETTYPE_RANDOM = 1, - TARGETTYPE_VICTIM = 2, -}; - -enum YellType -{ - ATTACKED = 0, // Used when attacked and set in combat - BEGIN = 1, // Used when the event is begun - INCOMING = 2, // Used to warn the raid that another wave phase is coming - RALLY = 3, // Used to rally the raid and warn that the next wave has been summoned - FAILURE = 4, // Used when raid has failed (unsure where to place) - SUCCESS = 5, // Used when the raid has sucessfully defeated a wave phase - DEATH = 6, // Used on death -}; - -struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI -{ - 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(); - - // Send creature back to spawn location and evade. - void EnterEvadeMode(); - - // Called when creature reached home location after evade. - void JustReachedHome(); - - // Used to reset cooldowns for our spells and to inform the raid that we're under attack - void Aggro(Unit* pWho); - - // Called to summon waves, check for boss deaths and to cast our spells. - void UpdateAI(const uint32 uiDiff); - - // Called on death, informs the raid that they have failed. - void JustDied(Unit* pKiller); - - // "Teleport" all friendly creatures away from the base. - void Retreat(); - - // Summons a creature for that wave in that base - void SpawnCreatureForWave(uint32 uiMobEntry); - - void JustSummoned(Creature*); - - // Summons the next wave, calls SummonCreature - void SummonNextWave(); - - // Begins the event by gossip click - void StartEvent(); - - // 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*); - - public: - - ScriptedInstance* m_pInstance; - - uint64 m_uiBossGUID[2]; - - uint32 m_uiNextWaveTimer; - uint32 m_uiWaveCount; - uint32 m_uiWaveMoveTimer; - uint32 m_uiCheckTimer; - uint32 m_uiEnemyCount; - uint32 m_uiRetreatTimer; - uint32 m_uiBase; - - bool m_bIsEventInProgress; - bool m_bIsFirstBossDead; - bool m_bIsSecondBossDead; - bool m_bIsSummoningWaves; - bool m_bIsRetreating; - bool m_bDebugMode; - - struct sSpells - { - uint32 m_uiSpellId; - uint32 m_uiCooldown; - TargetType m_pType; - } m_aSpells[MAX_SPELL]; - - private: - uint32 m_uiSpellTimer[MAX_SPELL]; - std::list lWaveMobGUIDList; -}; - -#endif diff --git a/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp b/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp deleted file mode 100644 index fadb763124..0000000000 --- a/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Instance_Mount_Hyjal -SD%Complete: 100 -SDComment: Instance Data Scripts and functions to acquire mobs and set encounter status for use in various Hyjal Scripts -SDCategory: Caverns of Time, Mount Hyjal -EndScriptData */ - -#include "precompiled.h" -#include "hyjal.h" - -/* Battle of Mount Hyjal encounters: -0 - Rage Winterchill event -1 - Anetheron event -2 - Kaz'rogal event -3 - Azgalor event -4 - Archimonde event -*/ - -struct MANGOS_DLL_DECL instance_mount_hyjal : public ScriptedInstance -{ - instance_mount_hyjal(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strSaveData; - - std::list lAncientGemGUIDList; - - uint64 m_uiRageWinterchill; - uint64 m_uiAnetheron; - uint64 m_uiKazrogal; - uint64 m_uiAzgalor; - uint64 m_uiArchimonde; - uint64 m_uiJainaProudmoore; - uint64 m_uiThrall; - uint64 m_uiTyrandeWhisperwind; - - uint32 m_uiTrashCount; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - lAncientGemGUIDList.clear(); - - m_uiRageWinterchill = 0; - m_uiAnetheron = 0; - m_uiKazrogal = 0; - m_uiAzgalor = 0; - m_uiArchimonde = 0; - m_uiJainaProudmoore = 0; - m_uiThrall = 0; - m_uiTyrandeWhisperwind = 0; - - m_uiTrashCount = 0; - } - - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; - - return false; - } - - void OnCreatureCreate(Creature* pCreature) - { - switch(pCreature->GetEntry()) - { - case NPC_WINTERCHILL: m_uiRageWinterchill = pCreature->GetGUID(); break; - case NPC_ANETHERON: m_uiAnetheron = pCreature->GetGUID(); break; - case NPC_KAZROGAL: m_uiKazrogal = pCreature->GetGUID(); break; - case NPC_AZGALOR: m_uiAzgalor = pCreature->GetGUID(); break; - case NPC_ARCHIMONDE: m_uiArchimonde = pCreature->GetGUID(); break; - case NPC_JAINA: m_uiJainaProudmoore = pCreature->GetGUID(); break; - case NPC_THRALL: m_uiThrall = pCreature->GetGUID(); break; - case NPC_TYRANDE: m_uiTyrandeWhisperwind = pCreature->GetGUID(); break; - } - } - - void OnObjectCreate(GameObject* pGo) - { - if (pGo->GetEntry() == GO_ANCIENT_GEM) - lAncientGemGUIDList.push_back(pGo->GetGUID()); - } - - uint64 GetData64(uint32 uiData) - { - switch(uiData) - { - case DATA_RAGEWINTERCHILL: return m_uiRageWinterchill; - case DATA_ANETHERON: return m_uiAnetheron; - case DATA_KAZROGAL: return m_uiKazrogal; - case DATA_AZGALOR: return m_uiAzgalor; - case DATA_ARCHIMONDE: return m_uiArchimonde; - case DATA_JAINAPROUDMOORE: return m_uiJainaProudmoore; - case DATA_THRALL: return m_uiThrall; - case DATA_TYRANDEWHISPERWIND: return m_uiTyrandeWhisperwind; - } - - return 0; - } - - void SetData(uint32 uiType, uint32 uiData) - { - switch(uiType) - { - case TYPE_WINTERCHILL: - if (m_auiEncounter[0] == DONE) - return; - m_auiEncounter[0] = uiData; - break; - case TYPE_ANETHERON: - if (m_auiEncounter[1] == DONE) - return; - m_auiEncounter[1] = uiData; - break; - case TYPE_KAZROGAL: - if (m_auiEncounter[2] == DONE) - return; - m_auiEncounter[2] = uiData; - break; - case TYPE_AZGALOR: - if (m_auiEncounter[3] == DONE) - return; - m_auiEncounter[3] = uiData; - break; - case TYPE_ARCHIMONDE: - m_auiEncounter[4] = uiData; - break; - - case DATA_RESET_TRASH_COUNT: - m_uiTrashCount = 0; - break; - - case DATA_TRASH: - if (uiData) - m_uiTrashCount = uiData; - else - --m_uiTrashCount; - - DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, m_uiTrashCount); - break; - - case TYPE_RETREAT: - if (uiData == SPECIAL) - { - if (!lAncientGemGUIDList.empty()) - { - for(std::list::iterator itr = lAncientGemGUIDList.begin(); itr != lAncientGemGUIDList.end(); ++itr) - { - //don't know how long it expected - DoRespawnGameObject(*itr,DAY); - } - } - } - break; - } - - debug_log("SD2: Instance Hyjal: Instance data updated for event %u (Data=%u)", uiType, uiData); - - 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]; - - strSaveData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } - - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_WINTERCHILL: return m_auiEncounter[0]; - case TYPE_ANETHERON: return m_auiEncounter[1]; - case TYPE_KAZROGAL: return m_auiEncounter[2]; - case TYPE_AZGALOR: return m_auiEncounter[3]; - case TYPE_ARCHIMONDE: return m_auiEncounter[4]; - case DATA_TRASH: return m_uiTrashCount; - } - return 0; - } - - const char* Save() - { - return strSaveData.c_str(); - } - - void Load(const char* in) - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - - std::istringstream loadStream(in); - 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. - m_auiEncounter[i] = NOT_STARTED; - - OUT_LOAD_INST_DATA_COMPLETE; - } -}; - -InstanceData* GetInstanceData_instance_mount_hyjal(Map* pMap) -{ - return new instance_mount_hyjal(pMap); -} - -void AddSC_instance_mount_hyjal() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "instance_hyjal"; - newscript->GetInstanceData = &GetInstanceData_instance_mount_hyjal; - newscript->RegisterSelf(); -} diff --git a/scripts/kalimdor/caverns_of_time/hyjal_summit/boss_archimonde.cpp b/scripts/kalimdor/caverns_of_time/hyjal_summit/boss_archimonde.cpp new file mode 100644 index 0000000000..0cf34fd1a5 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hyjal_summit/boss_archimonde.cpp @@ -0,0 +1,418 @@ +/* Copyright (C) 2006 - 2013 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_Archimonde +SD%Complete: 85 +SDComment: Timers; Some details may need adjustments. +SDCategory: Caverns of Time, Mount Hyjal +EndScriptData */ + +#include "precompiled.h" +#include "hyjal.h" + +enum +{ + 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. + The only complicated aspect of the battle is Finger of Death and Doomfire, with Doomfire being the + hardest bit to code. Finger of Death is simply a distance check - if no one is in melee range, then + 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. +*/ + +struct MANGOS_DLL_DECL boss_archimondeAI : public ScriptedAI +{ + boss_archimondeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bHasIntro = false; + Reset(); + } + + ScriptedInstance* m_pInstance; + + 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() + { + 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*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // 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)) + { + m_uiEnrageTimer = 1000; + m_bIsEnraged = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + 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; + case 2: DoScriptText(SAY_SLAY3, m_creature); break; + } + + switch (pVictim->getClass()) + { + case CLASS_PRIEST: + case CLASS_PALADIN: + case CLASS_WARLOCK: + pVictim->CastSpell(m_creature, SPELL_SOUL_CHARGE_RED, true); + break; + case CLASS_MAGE: + case CLASS_ROGUE: + case CLASS_WARRIOR: + pVictim->CastSpell(m_creature, SPELL_SOUL_CHARGE_YELLOW, true); + break; + case CLASS_DRUID: + case CLASS_SHAMAN: + case CLASS_HUNTER: + pVictim->CastSpell(m_creature, SPELL_SOUL_CHARGE_GREEN, true); + break; + } + } + + void JustReachedHome() override + { + // Start epilogue at 10% hp + if (m_bIsEpilogue) + { + if (DoCastSpellIfCan(m_creature, SPELL_PROTECTION_OF_ELUNE) == CAST_OK) + { + m_uiFingerOfDeathTimer = 5000; + m_bStartEpilogue = true; + } + } + else if (m_pInstance) + m_pInstance->SetData(TYPE_ARCHIMONDE, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ANCIENT_WISP) + { + pSummoned->AI()->AttackStart(m_creature); + ++m_uiWispCount; + + // 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); + } + else if (pSummoned->GetEntry() == NPC_DOOMFIRE) + { + pSummoned->CastSpell(pSummoned, SPELL_DOOMFIRE_SPAWN, true); + pSummoned->CastSpell(pSummoned, SPELL_DOOMFIRE, true, NULL, NULL, m_creature->GetObjectGuid()); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Intro timer + if (m_uiDrainNordrassilTimer) + { + if (m_uiDrainNordrassilTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DRAIN_TREE) == CAST_OK) + { + if (!m_bHasIntro) + { + DoScriptText(SAY_INTRO, m_creature); + m_bHasIntro = true; + } + m_uiDrainNordrassilTimer = 0; + } + } + else + m_uiDrainNordrassilTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Start epilogue - fight was won! + if (m_creature->GetHealthPercent() < 10.0f) + { + if (!m_bIsEpilogue) + { + DoScriptText(SAY_EPILOGUE, m_creature); + + // move at home position and start outro + m_creature->GetMotionMaster()->MoveTargetedHome(); + SetCombatMovement(false); + m_bIsEpilogue = 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 (m_uiSummonWispTimer < uiDiff) + { + 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 + m_uiSummonWispTimer -= uiDiff; + } + + // Stop using the other spells + return; + } + + if (m_uiEnrageTimer) + { + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HAND_OF_DEATH) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiEnrageTimer = 0; + } + } + else + m_uiEnrageTimer -= uiDiff; + } + + if (m_uiGripOfTheLegionTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_GRIP_OF_THE_LEGION) == CAST_OK) + m_uiGripOfTheLegionTimer = urand(5000, 25000); + } + } + else + m_uiGripOfTheLegionTimer -= uiDiff; + + if (m_uiAirBurstTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_AIR_BURST) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_AIR_BURST1 : SAY_AIR_BURST2, m_creature); + m_uiAirBurstTimer = urand(25000, 40000); + } + } + else + m_uiAirBurstTimer -= uiDiff; + + if (m_uiFearTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = 42000; + } + else + m_uiFearTimer -= uiDiff; + + if (m_uiDoomfireTimer < uiDiff) + { + 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 we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + // Else spam Finger of Death + else + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_FINGER_DEATH); + } + } + } +}; + +/* 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 MANGOS_DLL_DECL npc_doomfire_spiritAI : public ScriptedAI +{ + npc_doomfire_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + ObjectGuid m_doomfireGuid; + + uint32 m_uiDoomfireLoadTimer; + uint32 m_uiChangeTargetTimer; + float m_fAngle; + + void Reset() + { + m_uiDoomfireLoadTimer = 1000; + m_uiChangeTargetTimer = 1500; + m_fAngle = urand(0, M_PI_F * 2); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDoomfireLoadTimer) + { + if (m_uiDoomfireLoadTimer <= uiDiff) + { + // Get the closest doomfire + if (Creature* pTemp = GetClosestCreatureWithEntry(m_creature, NPC_DOOMFIRE, 5.0f)) + m_doomfireGuid = pTemp->GetObjectGuid(); + + m_uiDoomfireLoadTimer = 0; + } + else + m_uiDoomfireLoadTimer -= uiDiff; + } + + // 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); + } + + m_uiChangeTargetTimer = 4000; + } + else + m_uiChangeTargetTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_archimonde(Creature* pCreature) +{ + return new boss_archimondeAI(pCreature); +} + +CreatureAI* GetAI_npc_doomfire_spirit(Creature* pCreature) +{ + return new npc_doomfire_spiritAI(pCreature); +} + +void AddSC_boss_archimonde() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_archimonde"; + pNewScript->GetAI = &GetAI_boss_archimonde; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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_summit/hyjal.cpp similarity index 63% rename from scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp rename to scripts/kalimdor/caverns_of_time/hyjal_summit/hyjal.cpp index a7255ad63b..d45e82c535 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp +++ b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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->GetGUID()); + 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->GetGUID()); + 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; } } @@ -192,15 +199,15 @@ bool GossipHello_npc_tyrande_whisperwind(Player* pPlayer, Creature* pCreature) if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) { // 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); + if (pInstance->GetData(TYPE_AZGALOR) == DONE && !pPlayer->HasItemCount(ITEM_TEAR_OF_GODDESS, 1)) + 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->GetGUID()); + 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) { @@ -214,25 +221,25 @@ bool GossipSelect_npc_tyrande_whisperwind(Player* pPlayer, Creature* pCreature, void AddSC_hyjal() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_jaina_proudmoore"; - newscript->GetAI = &GetAI_npc_jaina_proudmoore; - newscript->pGossipHello = &GossipHello_npc_jaina_proudmoore; - newscript->pGossipSelect = &GossipSelect_npc_jaina_proudmoore; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_thrall"; - newscript->GetAI = &GetAI_npc_thrall; - newscript->pGossipHello = &GossipHello_npc_thrall; - newscript->pGossipSelect = &GossipSelect_npc_thrall; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tyrande_whisperwind"; - newscript->pGossipHello = &GossipHello_npc_tyrande_whisperwind; - newscript->pGossipSelect = &GossipSelect_npc_tyrande_whisperwind; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_jaina_proudmoore"; + pNewScript->GetAI = &GetAI_npc_jaina_proudmoore; + pNewScript->pGossipHello = &GossipHello_npc_jaina_proudmoore; + pNewScript->pGossipSelect = &GossipSelect_npc_jaina_proudmoore; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_thrall"; + pNewScript->GetAI = &GetAI_npc_thrall; + pNewScript->pGossipHello = &GossipHello_npc_thrall; + pNewScript->pGossipSelect = &GossipSelect_npc_thrall; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tyrande_whisperwind"; + pNewScript->pGossipHello = &GossipHello_npc_tyrande_whisperwind; + pNewScript->pGossipSelect = &GossipSelect_npc_tyrande_whisperwind; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjal.h b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjal.h new file mode 100644 index 0000000000..93992649e1 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjal.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_HYJAL_H +#define DEF_HYJAL_H + +enum +{ + MAX_ENCOUNTER = 5, + + TYPE_WINTERCHILL = 0, + TYPE_ANETHERON = 1, + TYPE_KAZROGAL = 2, + TYPE_AZGALOR = 3, + TYPE_ARCHIMONDE = 4, + + TYPE_TRASH_COUNT = 5, + TYPE_RETREAT = 6, + + WORLD_STATE_WAVES = 2842, + WORLD_STATE_ENEMY = 2453, + WORLD_STATE_ENEMYCOUNT = 2454, + + NPC_JAINA = 17772, + NPC_THRALL = 17852, + NPC_TYRANDE = 17948, + + // Bosses summoned after every 8 waves + NPC_WINTERCHILL = 17767, + NPC_ANETHERON = 17808, + NPC_KAZROGAL = 17888, + NPC_AZGALOR = 17842, + NPC_ARCHIMONDE = 17968, + + // Trash Mobs summoned in waves + NPC_NECRO = 17899, + NPC_ABOMI = 17898, + NPC_GHOUL = 17895, + NPC_BANSH = 17905, + NPC_CRYPT = 17897, + NPC_GARGO = 17906, + NPC_FROST = 17907, + NPC_GIANT = 17908, + NPC_STALK = 17916, + + NPC_WATER_ELEMENTAL = 18001, + NPC_DIRE_WOLF = 17854, + + GO_ANCIENT_GEM = 185557, +}; + +static const float aArchimondeSpawnLoc[4] = {5581.49f, -3445.63f, 1575.1f, 3.905f}; + +class MANGOS_DLL_DECL instance_mount_hyjal : public ScriptedInstance +{ + public: + instance_mount_hyjal(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 OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) 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_strSaveData.c_str(); } + void Load(const char* chrIn) override; + + private: + void DoSpawnArchimonde(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strSaveData; + + GuidList lAncientGemGuidList; + + uint32 m_uiTrashCount; +}; + +#endif diff --git a/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjalAI.cpp b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjalAI.cpp new file mode 100644 index 0000000000..148171fd83 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjalAI.cpp @@ -0,0 +1,548 @@ +/* Copyright (C) 2006 - 2013 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: HyjalAI +SD%Complete: 90 +SDComment: +SDCategory: Caverns of Time, Mount Hyjal +EndScriptData */ + +#include "precompiled.h" +#include "hyjalAI.h" + +struct HyjalLocation +{ + eBaseArea m_pBaseArea; + float m_fX, m_fY, m_fZ; +}; + +// Locations for summoning waves +// Must be even number +static const HyjalLocation aHyjalSpawnLoc[] = +{ + {BASE_ALLY, 4979.010f, -1709.134f, 1339.674f}, + {BASE_ALLY, 4969.123f, -1705.904f, 1341.363f}, + {BASE_ALLY, 4970.260f, -1698.546f, 1341.200f}, + {BASE_ALLY, 4975.262f, -1698.239f, 1341.427f}, + {BASE_HORDE, 5557.582f, -2587.159f, 1481.644f}, + {BASE_HORDE, 5545.901f, -2582.246f, 1479.256f}, + {BASE_HORDE, 5565.642f, -2565.666f, 1481.635f}, + {BASE_HORDE, 5547.218f, -2574.589f, 1479.194f} +}; + +// used to inform the wave where to move +static const HyjalLocation aHyjalWaveMoveTo[] = +{ + {BASE_ALLY, 5018.654f, -1752.074f, 1322.203f}, + {BASE_HORDE, 5504.569f, -2688.489f, 1479.991f} +}; + +struct HyjalYells +{ + uint32 uiCreatureEntry; + YellType m_pYellType; // Used to determine the type of yell (attack, rally, etc) + int32 m_iTextId; // The text id to be yelled +}; + +static const HyjalYells aHyjalYell[] = +{ + {NPC_JAINA, ATTACKED, -1534000}, + {NPC_JAINA, ATTACKED, -1534001}, + {NPC_JAINA, INCOMING, -1534002}, + {NPC_JAINA, BEGIN, -1534003}, + {NPC_JAINA, RALLY, -1534004}, + {NPC_JAINA, RALLY, -1534005}, + {NPC_JAINA, FAILURE, -1534006}, + {NPC_JAINA, SUCCESS, -1534007}, + {NPC_JAINA, DEATH, -1534008}, + + {NPC_THRALL, ATTACKED, -1534009}, + {NPC_THRALL, ATTACKED, -1534010}, + {NPC_THRALL, INCOMING, -1534011}, + {NPC_THRALL, BEGIN, -1534012}, + {NPC_THRALL, RALLY, -1534013}, + {NPC_THRALL, RALLY, -1534014}, + {NPC_THRALL, FAILURE, -1534015}, + {NPC_THRALL, SUCCESS, -1534016}, + {NPC_THRALL, DEATH, -1534017} +}; + +struct HyjalWave +{ + uint32 m_auiMobEntry[MAX_WAVE_MOB]; // Stores Creature Entries to be summoned in Waves + uint32 m_uiWaveTimer; // The timer before the next wave is summoned + bool m_bIsBoss; // Simply used to inform the wave summoner that the next wave contains a boss to halt all waves after that +}; + +// Waves that will be summoned in the Alliance Base +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}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 140000, false}, + // All 8 Waves are summoned, summon Rage Winterchill, next few waves are for Anetheron + {{NPC_WINTERCHILL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true}, + // Anetheron 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}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_BANSH, NPC_BANSH, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_BANSH, NPC_BANSH, 0, 0, 0, 0, 0, 0}, 125000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_BANSH, NPC_BANSH, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 140000, false}, + // All 8 Waves are summoned, summon Anatheron + {{NPC_ANETHERON, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true} +}; + +// Waves that are summoned in the Horde base +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}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, 0, 0, 0, 0}, 165000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 160000, false}, + {{NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 165000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 135000, false}, + {{NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_FROST, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 135000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_FROST, 0, 0, 0, 0, 0, 0, 0}, 195000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_BANSH, NPC_BANSH, 0, 0}, 225000, false}, + // All 8 Waves are summoned, summon Kaz'Rogal, next few waves are for Azgalor + {{NPC_KAZROGAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true}, + // Azgalor Wave 1-8 + {{NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 135000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_FROST, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, NPC_GARGO, 0, 0, 0, 0}, 165000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, 0, 0, 0, 0, 0, 0}, 160000, false}, + {{NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, 0, 0, 0, 0}, 165000, false}, + {{NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_STALK, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 135000, false}, + {{NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_NECRO, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, NPC_BANSH, 0, 0, 0, 0, 0, 0}, 135000, false}, + {{NPC_GHOUL, NPC_GHOUL, NPC_CRYPT, NPC_CRYPT, NPC_STALK, NPC_STALK, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, NPC_GIANT, 0, 0, 0, 0}, 195000, false}, + {{NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_CRYPT, NPC_STALK, NPC_STALK, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_BANSH, NPC_BANSH, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0}, 225000, false}, + // All 8 Waves are summoned, summon Azgalor + {{NPC_AZGALOR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true} +}; + +void hyjalAI::Reset() +{ + // Timers + m_uiNextWaveTimer = 10000; + m_uiWaveMoveTimer = 15000; + m_uiRetreatTimer = 25000; + + // Misc + m_uiWaveCount = 0; + m_uiEnemyCount = 0; + + // Set base area based on creature entry + switch (m_creature->GetEntry()) + { + case NPC_JAINA: + m_uiBase = BASE_ALLY; + DoCastSpellIfCan(m_creature, SPELL_BRILLIANCE_AURA, CAST_TRIGGERED); + break; + case NPC_THRALL: + m_uiBase = BASE_HORDE; + break; + } + + // Bools + m_bIsEventInProgress = false; + m_bIsSummoningWaves = false; + + m_bIsRetreating = false; + m_bDebugMode = false; + + // 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); + + // 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->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); +} + +void hyjalAI::JustReachedHome() +{ + if (m_uiBase == BASE_ALLY) + DoCastSpellIfCan(m_creature, SPELL_BRILLIANCE_AURA, CAST_TRIGGERED); + + 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; +} + +void hyjalAI::Aggro(Unit* /*who*/) +{ + for (uint8 i = 0; i < MAX_SPELL; ++i) + if (m_aSpells[i].m_uiCooldown) + m_uiSpellTimer[i] = m_aSpells[i].m_uiCooldown; + + DoTalk(ATTACKED); +} + +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 uiJ = 0; + + for (uint32 i = 0; i < uiMaxCount; ++i) + { + if (aHyjalSpawnLoc[i].m_pBaseArea != (eBaseArea)m_uiBase) + continue; + + ++uiJ; + + if (uiJ == uiRandId) + { + pSpawn = &aHyjalSpawnLoc[i]; + break; + } + } + + if (pSpawn) + m_creature->SummonCreature(uiMobEntry, pSpawn->m_fX, pSpawn->m_fY, pSpawn->m_fZ, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); +} + +void hyjalAI::JustSummoned(Creature* pSummoned) +{ + // not interesting for us + if (pSummoned->GetEntry() == NPC_WATER_ELEMENTAL || pSummoned->GetEntry() == NPC_DIRE_WOLF) + return; + + // Increment Enemy Count to be used in World States and instance script + ++m_uiEnemyCount; + + HyjalLocation const* pMove = NULL; + + for (uint32 i = 0; i < countof(aHyjalWaveMoveTo); ++i) + { + if (aHyjalWaveMoveTo[i].m_pBaseArea != (eBaseArea)m_uiBase) + continue; + + pMove = &aHyjalWaveMoveTo[i]; + break; + } + + if (pMove) + { + float fX, fY, fZ; + pSummoned->GetRandomPoint(pMove->m_fX, pMove->m_fY, pMove->m_fZ, 10.0f, fX, fY, fZ); + + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + + // Check if creature is a boss. + if (pSummoned->IsWorldBoss()) + 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. + if (!urand(0, 3)) + DoTalk(RALLY); + + if (!m_pInstance) + return; + + HyjalWave const* pWaveData = m_uiBase ? &aHyjalWavesHorde[m_uiWaveCount] : &aHyjalWavesAlliance[m_uiWaveCount]; + + if (!pWaveData) + { + 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) + { + if (pWaveData->m_auiMobEntry[i]) + SpawnCreatureForWave(pWaveData->m_auiMobEntry[i]); + } + + if (!pWaveData->m_bIsBoss) + { + 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 + + // Set world state to our current wave number + m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, stateValue); + // Enable world state + m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 1); + + m_pInstance->SetData(TYPE_TRASH_COUNT, m_uiEnemyCount); // Send data for instance script to update count + + if (!m_bDebugMode) + m_uiNextWaveTimer = pWaveData->m_uiWaveTimer; + else + { + m_uiNextWaveTimer = 15000; + debug_log("SD2: HyjalAI: debug mode is enabled. Next Wave in 15 seconds"); + } + } + else + { + // Set world state for waves to 0 to disable it. + m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, 0); + m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 1); + + // Set World State for enemies invading to 1. + m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, 1); + + m_bIsSummoningWaves = false; + } + + m_uiWaveMoveTimer = 15000; + ++m_uiWaveCount; +} + +void hyjalAI::StartEvent() +{ + if (!m_pInstance) + return; + + if (IsEventInProgress()) + return; + + DoTalk(BEGIN); + + m_bIsEventInProgress = true; + m_bIsSummoningWaves = true; + + m_uiNextWaveTimer = 10000; + + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, 0); + m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 0); + m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, 0); + + m_creature->SetActiveObjectState(true); +} + +void hyjalAI::DoTalk(YellType pYellType) +{ + HyjalYells const* pYell = NULL; + + bool bGetNext = false; + + for (uint32 i = 0; i < countof(aHyjalYell); ++i) + { + 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) + { + if (!bGetNext && urand(0, 1)) + { + bGetNext = true; + continue; + } + } + + pYell = &aHyjalYell[i]; + break; + } + } + + if (pYell) + DoScriptText(pYell->m_iTextId, m_creature); +} + +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) + //{ + // despawn; + //} +} + +void hyjalAI::Retreat() +{ + // this will trigger ancient gem respawn + if (m_pInstance) + m_pInstance->SetData(TYPE_RETREAT, SPECIAL); + + DoCastSpellIfCan(m_creature, SPELL_MASS_TELEPORT); + + m_bIsRetreating = true; +} + +void hyjalAI::JustDied(Unit* /*pKiller*/) +{ + DoTalk(DEATH); + m_creature->SetActiveObjectState(false); + + // TODO: in case they die during boss encounter, then what? despawn boss? +} + +void hyjalAI::UpdateAI(const uint32 uiDiff) +{ + if (!m_bIsEventInProgress) + return; + + if (m_bIsSummoningWaves && m_pInstance) + { + if (m_uiWaveMoveTimer < uiDiff) + { + // Skip the master timer, and start next wave in 5. Clear the list, it should not be any here now. + if (!m_pInstance->GetData(TYPE_TRASH_COUNT)) + { + lWaveMobGuidList.clear(); + m_uiNextWaveTimer = std::min(m_uiNextWaveTimer, (uint32)5000); + } + + for (GuidList::const_iterator itr = lWaveMobGuidList.begin(); itr != lWaveMobGuidList.end(); ++itr) + { + if (Creature* pTemp = m_pInstance->instance->GetCreature(*itr)) + { + if (!pTemp->isAlive() || pTemp->getVictim()) + continue; + + pTemp->SetWalk(false); + pTemp->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + } + } + m_uiWaveMoveTimer = 10000; + } + else + m_uiWaveMoveTimer -= uiDiff; + + if (m_uiNextWaveTimer < uiDiff) + SummonNextWave(); + else + m_uiNextWaveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + for (uint8 i = 0; i < MAX_SPELL; ++i) + { + if (m_aSpells[i].m_uiSpellId) + { + if (m_uiSpellTimer[i] < uiDiff) + { + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + Unit* pTarget = NULL; + + 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; + case TARGETTYPE_VICTIM: pTarget = m_creature->getVictim(); break; + } + + if (pTarget) + { + DoCastSpellIfCan(pTarget, m_aSpells[i].m_uiSpellId); + m_uiSpellTimer[i] = m_aSpells[i].m_uiCooldown; + } + } + else + m_uiSpellTimer[i] -= uiDiff; + } + } + + DoMeleeAttackIfReady(); +} + +void hyjalAI::JustRespawned() +{ + Reset(); +} diff --git a/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjalAI.h b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjalAI.h new file mode 100644 index 0000000000..e43e14b372 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hyjal_summit/hyjalAI.h @@ -0,0 +1,142 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_HYJALAI_H +#define SC_HYJALAI_H + +#include "hyjal.h" + +enum eBaseArea +{ + BASE_ALLY = 0, + BASE_HORDE = 1 +}; + +enum eMisc +{ + MAX_SPELL = 3, + MAX_WAVES = 9, + MAX_WAVE_MOB = 18, + + ITEM_TEAR_OF_GODDESS = 24494 +}; + +enum eSpell +{ + SPELL_MASS_TELEPORT = 16807, + + // Spells for Jaina + SPELL_BRILLIANCE_AURA = 31260, + SPELL_BLIZZARD = 31266, + SPELL_PYROBLAST = 31263, + SPELL_SUMMON_ELEMENTALS = 31264, + + // Thrall spells + SPELL_CHAIN_LIGHTNING = 31330, + SPELL_FERAL_SPIRIT = 31331 +}; + +enum TargetType // Used in the spell cast system for the AI +{ + TARGETTYPE_SELF = 0, + TARGETTYPE_RANDOM = 1, + TARGETTYPE_VICTIM = 2, +}; + +enum YellType +{ + ATTACKED = 0, // Used when attacked and set in combat + BEGIN = 1, // Used when the event is begun + INCOMING = 2, // Used to warn the raid that another wave phase is coming + RALLY = 3, // Used to rally the raid and warn that the next wave has been summoned + FAILURE = 4, // Used when raid has failed (unsure where to place) + SUCCESS = 5, // Used when the raid has sucessfully defeated a wave phase + DEATH = 6, // Used on death +}; + +struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI +{ + 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(); + + // Send creature back to spawn location and evade. + void EnterEvadeMode() override; + + // 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); + + // 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) override; + + void JustRespawned() override; + + // "Teleport" all friendly creatures away from the base. + void Retreat(); + + // Summons a creature for that wave in that base + void SpawnCreatureForWave(uint32 uiMobEntry); + + void JustSummoned(Creature*); + + void SummonedCreatureJustDied(Creature* pSummoned) override; + + // Summons the next wave, calls SummonCreature + void SummonNextWave(); + + // Begins the event by gossip click + void StartEvent(); + + // 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*); + + bool IsEventInProgress() const; + + public: + ScriptedInstance* m_pInstance; + + ObjectGuid m_aBossGuid[2]; + + uint32 m_uiNextWaveTimer; + uint32 m_uiWaveCount; + uint32 m_uiWaveMoveTimer; + uint32 m_uiEnemyCount; + uint32 m_uiRetreatTimer; + uint32 m_uiBase; + + bool m_bIsEventInProgress; + bool m_bIsFirstBossDead; + bool m_bIsSecondBossDead; + bool m_bIsSummoningWaves; + bool m_bIsRetreating; + bool m_bDebugMode; + + struct sSpells + { + uint32 m_uiSpellId; + uint32 m_uiCooldown; + TargetType m_pType; + } m_aSpells[MAX_SPELL]; + + private: + uint32 m_uiSpellTimer[MAX_SPELL]; + GuidList lWaveMobGuidList; +}; + +#endif diff --git a/scripts/kalimdor/caverns_of_time/hyjal_summit/instance_hyjal.cpp b/scripts/kalimdor/caverns_of_time/hyjal_summit/instance_hyjal.cpp new file mode 100644 index 0000000000..6298459c58 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/hyjal_summit/instance_hyjal.cpp @@ -0,0 +1,245 @@ +/* Copyright (C) 2006 - 2013 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: Instance_Mount_Hyjal +SD%Complete: 100 +SDComment: Instance Data Scripts and functions to acquire mobs and set encounter status for use in various Hyjal Scripts +SDCategory: Caverns of Time, Mount Hyjal +EndScriptData */ + +#include "precompiled.h" +#include "hyjal.h" + +/* Battle of Mount Hyjal encounters: +0 - Rage Winterchill event +1 - Anetheron event +2 - Kaz'rogal event +3 - Azgalor event +4 - Archimonde event +*/ + +instance_mount_hyjal::instance_mount_hyjal(Map* pMap) : ScriptedInstance(pMap), + m_uiTrashCount(0) +{ + Initialize(); +} + +void instance_mount_hyjal::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +bool instance_mount_hyjal::IsEncounterInProgress() const +{ + 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(); +} + +void instance_mount_hyjal::OnObjectCreate(GameObject* pGo) +{ + if (pGo->GetEntry() == GO_ANCIENT_GEM) + lAncientGemGuidList.push_back(pGo->GetObjectGuid()); +} + +void instance_mount_hyjal::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_WINTERCHILL: SetData(TYPE_WINTERCHILL, IN_PROGRESS); break; + case NPC_ANETHERON: SetData(TYPE_ANETHERON, IN_PROGRESS); break; + case NPC_KAZROGAL: SetData(TYPE_KAZROGAL, IN_PROGRESS); break; + case NPC_AZGALOR: SetData(TYPE_AZGALOR, IN_PROGRESS); break; + case NPC_ARCHIMONDE: SetData(TYPE_ARCHIMONDE, IN_PROGRESS); break; + } +} + +void instance_mount_hyjal::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_WINTERCHILL: SetData(TYPE_WINTERCHILL, FAIL); break; + case NPC_ANETHERON: SetData(TYPE_ANETHERON, FAIL); break; + case NPC_KAZROGAL: SetData(TYPE_KAZROGAL, FAIL); break; + case NPC_AZGALOR: SetData(TYPE_AZGALOR, FAIL); break; + } +} + +void instance_mount_hyjal::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_WINTERCHILL: SetData(TYPE_WINTERCHILL, DONE); break; + case NPC_ANETHERON: SetData(TYPE_ANETHERON, DONE); break; + case NPC_KAZROGAL: SetData(TYPE_KAZROGAL, DONE); break; + case NPC_AZGALOR: SetData(TYPE_AZGALOR, DONE); break; + case NPC_ARCHIMONDE: SetData(TYPE_ARCHIMONDE, DONE); break; + + // Trash Mobs summoned in waves + case NPC_NECRO: + case NPC_ABOMI: + case NPC_GHOUL: + case NPC_BANSH: + case NPC_CRYPT: + case NPC_GARGO: + case NPC_FROST: + case NPC_GIANT: + case NPC_STALK: + // Decrease counter, and update world-state + if (m_uiTrashCount) + { + --m_uiTrashCount; + DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, m_uiTrashCount); + } + break; + } +} + +void instance_mount_hyjal::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_WINTERCHILL: + case TYPE_ANETHERON: + case TYPE_KAZROGAL: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_AZGALOR: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoSpawnArchimonde(); + break; + case TYPE_ARCHIMONDE: + m_auiEncounter[uiType] = uiData; + break; + + case TYPE_TRASH_COUNT: + m_uiTrashCount = uiData; + DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, m_uiTrashCount); + break; + + case TYPE_RETREAT: + if (uiData == SPECIAL) + { + if (!lAncientGemGuidList.empty()) + { + for (GuidList::const_iterator itr = lAncientGemGuidList.begin(); itr != lAncientGemGuidList.end(); ++itr) + { + // don't know how long it expected + DoRespawnGameObject(*itr, DAY); + } + } + } + break; + } + + debug_log("SD2: Instance Hyjal: Instance data updated for event %u (Data=%u)", uiType, uiData); + + 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_strSaveData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +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) + { + case TYPE_WINTERCHILL: + case TYPE_ANETHERON: + case TYPE_KAZROGAL: + case TYPE_AZGALOR: + case TYPE_ARCHIMONDE: + return m_auiEncounter[uiType]; + case TYPE_TRASH_COUNT: + return m_uiTrashCount; + default: + return 0; + } +} + +void instance_mount_hyjal::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) // Do not load an encounter as IN_PROGRESS - reset it instead. + m_auiEncounter[i] = NOT_STARTED; + + OUT_LOAD_INST_DATA_COMPLETE; +} + +InstanceData* GetInstanceData_instance_mount_hyjal(Map* pMap) +{ + return new instance_mount_hyjal(pMap); +} + +void AddSC_instance_mount_hyjal() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_hyjal"; + pNewScript->GetInstanceData = &GetInstanceData_instance_mount_hyjal; + pNewScript->RegisterSelf(); +} 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 b3a6aad977..0000000000 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_captain_skarloc"; - newscript->GetAI = &GetAI_boss_captain_skarloc; - newscript->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 6b7c4c3b1f..0000000000 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_epoch_hunter"; - newscript->GetAI = &GetAI_boss_epoch_hunter; - newscript->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 2f86b4ab88..0000000000 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 GOHello_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 *newscript; - - newscript = new Script; - newscript->Name = "go_barrel_old_hillsbrad"; - newscript->pGOHello = &GOHello_go_barrel_old_hillsbrad; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lieutenant_drake"; - newscript->GetAI = &GetAI_boss_lieutenant_drake; - newscript->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 0b5fc83c4a..68afcdf93e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 */ @@ -27,10 +27,7 @@ EndScriptData */ instance_old_hillsbrad::instance_old_hillsbrad(Map* pMap) : ScriptedInstance(pMap), m_uiBarrelCount(0), m_uiThrallEventCount(0), - m_uiThrallGUID(0), - m_uiTarethaGUID(0), - m_uiScarlocGUID(0), - m_uiEpochGUID(0) + m_uiThrallResetTimer(0) { Initialize(); } @@ -40,196 +37,275 @@ void instance_old_hillsbrad::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } -Player* instance_old_hillsbrad::GetPlayerInMap() +void instance_old_hillsbrad::OnPlayerEnter(Player* pPlayer) { - Map::PlayerList const& players = instance->GetPlayers(); + // ToDo: HandleThrallRelocation(); + // Note: this isn't yet supported because of the grid load / unload - if (!players.isEmpty()) - { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* plr = itr->getSource()) - return plr; - } - } + // Spawn Drake if necessary + if (GetData(TYPE_DRAKE) == DONE || GetData(TYPE_BARREL_DIVERSION) != DONE) + return; - debug_log("SD2: Instance Old Hillsbrad: GetPlayerInMap, but PlayerList is empty!"); - return NULL; + 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: - m_uiThrallGUID = pCreature->GetGUID(); - break; case NPC_TARETHA: - m_uiTarethaGUID = pCreature->GetGUID(); - break; + 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_uiEpochGUID = pCreature->GetGUID(); + 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 = instance->GetCreature(m_uiThrallGUID)) - 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() { - if (Creature* pThrall = instance->GetCreature(m_uiThrallGUID)) + // 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; } -} -uint32 instance_old_hillsbrad::GetData(uint32 uiData) -{ - switch(uiData) + if (uiData == DONE) { - 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_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; } } -uint64 instance_old_hillsbrad::GetData64(uint32 uiData) +uint32 instance_old_hillsbrad::GetData(uint32 uiType) const { + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + return 0; } +void instance_old_hillsbrad::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] >> 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() { Map::PlayerList const& players = instance->GetPlayers(); 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); @@ -237,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; @@ -250,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 72fb2b2767..e449d33b79 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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; - uint64 m_uiErozionGUID; - 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->GetGUID()); - 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->GetGUID()); - else - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID); - } - } - return true; -} - /*###### ## npc_erozion ######*/ @@ -93,38 +40,40 @@ 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) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); 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) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] Teleport please, i'm tired.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);*/ - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_DEFAULT, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_DEFAULT, pCreature->GetObjectGuid()); 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); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_GOT_ITEM, pCreature->GetGUID()); + 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,69 +211,217 @@ 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 MANGOS_DLL_DECL 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(); } instance_old_hillsbrad* m_pInstance; - uint64 m_uiScarlocMountGUID; - bool m_bIsLowHp; bool m_bHadMount; + bool m_bHasChurchYelled; + bool m_bHasInnYelled; + bool m_bHasEpochYelled; + + uint8 m_uiEpochWaveId; + + uint32 m_uiStrikeTimer; + uint32 m_uiShieldBlockTimer; + uint32 m_uiEpochAttackTimer; + + ObjectGuid m_skarlocMountGuid; + + GuidList m_lSkarlocAddsGuids; + GuidList m_lTarrenMillSoldiersGuids; void Reset() { - m_uiScarlocMountGUID = 0; - - 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; @@ -294,316 +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; + // *** 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 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); + 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 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 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; + // *** Escort event - Part III - church *** + case 92: + DoScriptText(SAY_TH_CHURCH_ENTER, m_creature); + m_creature->SetFacingTo(1.0f); 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); + case 93: + m_creature->SummonCreature(NPC_CHURCH_PROTECTOR, 2627.88f, 657.63f, 55.98f, 4.28f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); + m_creature->SummonCreature(NPC_CHURCH_LOOKOUT, 2627.27f, 655.17f, 56.03f, 4.50f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); + m_creature->SummonCreature(NPC_CHURCH_LOOKOUT, 2629.21f, 654.81f, 56.04f, 4.38f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); + m_creature->SummonCreature(NPC_CHURCH_GUARDSMAN, 2629.98f, 656.96f, 55.96f, 4.34f, TEMPSUMMON_TIMED_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 (Player* pPlayer = GetPlayerForEscort()) - { - if (npc_tarethaAI* pTarethaAI = dynamic_cast(pTaretha->AI())) - pTarethaAI->Start(true, pPlayer->GetGUID()); - } - } - - // 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->GetGUID()); - } - } - - // 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: - break; - case NPC_SKARLOC_MOUNT: - m_uiScarlocMountGUID = pSummoned->GetGUID(); - 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) - { - 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) - uiRespawnDelay = 4 * HOUR; } - void JustRespawned() + void UpdateEscortAI(const uint32 uiDiff) override { - if (!m_pInstance) - return; - - Reset(); + DialogueUpdate(uiDiff); - 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) { @@ -624,81 +1014,95 @@ bool GossipHello_npc_thrall_old_hillsbrad(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) { - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - pPlayer->SendPreparedQuest(pCreature->GetGUID()); + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + pPlayer->SendPreparedQuest(pCreature->GetObjectGuid()); } 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->GetGUID()); + 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->GetGUID()); + 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->GetGUID()); + 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->GetGUID()); + 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->GetGUID()); + 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->GetGUID()); - - 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; } @@ -712,111 +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_uiErozionGUID = 0; - 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 MANGOS_DLL_DECL npc_tarethaAI : public npc_escortAI, private DialogueHelper { - if (pSummoned->GetEntry() == NPC_EROZION) - m_uiErozionGUID = pSummoned->GetGUID(); - 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() { - 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); + 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 3: - if (Creature* pThrall = m_pInstance->GetThrall()) - DoScriptText(SAY_TR_THEN_WHO, pThrall); + case SPELL_MEMORY_WIPE: + if (Creature* pErozion = m_pInstance->GetSingleCreatureFromStorage(NPC_EROZION)) + pErozion->CastSpell(pErozion, SPELL_MEMORY_WIPE, false); break; - case 4: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_uiErozionGUID)) - DoScriptText(SAY_PRE_WIPE, pErozion); + 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 5: - //if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_uiErozionGUID)) - //pErozion->AI()->DoCastSpellIfCan(); - break; - case 6: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_uiErozionGUID)) - DoScriptText(SAY_WIPE_MEMORY, pErozion); - break; - case 7: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_uiErozionGUID)) - DoScriptText(SAY_ABOUT_TARETHA, pErozion); - break; - case 8: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_uiErozionGUID)) - DoScriptText(SAY_AFTER_WIPE, pErozion); - break; - case 9: - if (Creature* pThrall = m_pInstance->GetThrall()) - DoScriptText(SAY_TH_EVENT_COMPLETE, pThrall); - 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) { @@ -827,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->GetGUID()); + 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->GetGUID()); + 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(); } } } @@ -866,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; @@ -888,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 61b82968b5..fcf942d9e4 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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,41 +48,54 @@ enum WORLD_STATE_OH = 2436, }; +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 MANGOS_DLL_DECL instance_old_hillsbrad : public ScriptedInstance { public: instance_old_hillsbrad(Map* pMap); ~instance_old_hillsbrad() {} - void Initialize(); + void Initialize() override; - Player* GetPlayerInMap(); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void HandleThrallRelocation(); + uint32 GetThrallEventCount() { return m_uiThrallEventCount; } - void UpdateLodgeQuestCredit(); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - Creature* GetThrall() { return instance->GetCreature(m_uiThrallGUID); } - Creature* GetTaretha() { return instance->GetCreature(m_uiTarethaGUID); } - Creature* GetScarloc() { return instance->GetCreature(m_uiScarlocGUID); } - Creature* GetEpoch() { return instance->GetCreature(m_uiEpochGUID); } + 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; - uint64 m_uiThrallGUID; - uint64 m_uiTarethaGUID; - uint64 m_uiScarlocGUID; - uint64 m_uiEpochGUID; + uint32 m_uiThrallResetTimer; + + GuidList m_lRoaringFlamesList; + GuidList m_lLeftPrisonersList; + GuidList m_lRightPrisonersList; }; #endif diff --git a/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_mannoroth_and_varothen.cpp b/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_mannoroth_and_varothen.cpp new file mode 100644 index 0000000000..7d46435c54 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_mannoroth_and_varothen.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_mannoroth_and_varothen +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Well of Eternity +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_mannoroth_and_varothen() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_perotharn.cpp b/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_perotharn.cpp new file mode 100644 index 0000000000..6d31fe95ae --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_perotharn.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_perotharn +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Well of Eternity +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_perotharn() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_queen_azshara.cpp b/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_queen_azshara.cpp new file mode 100644 index 0000000000..cc3975e2ec --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/well_of_eternity/boss_queen_azshara.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_queen_azshara +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Well of Eternity +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_queen_azshara() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/well_of_eternity/instance_well_of_eternity.cpp b/scripts/kalimdor/caverns_of_time/well_of_eternity/instance_well_of_eternity.cpp new file mode 100644 index 0000000000..f1ef70fc0d --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/well_of_eternity/instance_well_of_eternity.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_well_of_eternity +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Well of Eternity +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_well_of_eternity() +{ +} diff --git a/scripts/kalimdor/caverns_of_time/well_of_eternity/well_of_eternity.h b/scripts/kalimdor/caverns_of_time/well_of_eternity/well_of_eternity.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/caverns_of_time/well_of_eternity/well_of_eternity.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/darkshore.cpp b/scripts/kalimdor/darkshore.cpp index 2fca1e0afb..d1d2bdc291 100644 --- a/scripts/kalimdor/darkshore.cpp +++ b/scripts/kalimdor/darkshore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Darkshore SD%Complete: 100 -SDComment: Quest support: 731, 2078, 5321 +SDComment: Quest support: 731, 945, 994, 995, 2078, 2118, 5321 SDCategory: Darkshore EndScriptData */ @@ -25,6 +25,9 @@ EndScriptData */ npc_kerlonian npc_prospector_remtravel npc_threshwackonator +npc_volcor +npc_therylune +npc_rabid_bear EndContentData */ #include "precompiled.h" @@ -58,10 +61,10 @@ 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. +// 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 { npc_kerlonianAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } @@ -73,13 +76,13 @@ struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI 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()) { @@ -94,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(); @@ -104,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; @@ -133,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()) { @@ -208,14 +211,14 @@ struct MANGOS_DLL_DECL 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); @@ -224,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); @@ -254,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); @@ -273,16 +276,16 @@ struct MANGOS_DLL_DECL npc_prospector_remtravelAI : public npc_escortAI void Reset() { } - 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); } }; @@ -295,10 +298,10 @@ 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->GetGUID(), pQuest, true); + pEscortAI->Start(false, pPlayer, pQuest, true); } return true; @@ -325,7 +328,7 @@ struct MANGOS_DLL_DECL npc_threshwackonatorAI : public FollowerAI void Reset() {} - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); @@ -341,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); @@ -358,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->GetGUID()); + 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(); @@ -380,6 +383,351 @@ bool GossipSelect_npc_threshwackonator(Player* pPlayer, Creature* pCreature, uin return true; } +/*###### +# 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_ESCAPE = -1000195, + + NPC_BLACKWOOD_SHAMAN = 2171, + NPC_BLACKWOOD_URSA = 2170, + + SPELL_MOONSTALKER_FORM = 10849, + + WAYPOINT_ID_QUEST_STEALTH = 16, + FACTION_FRIENDLY = 35, + + QUEST_ESCAPE_THROUGH_FORCE = 994, + QUEST_ESCAPE_THROUGH_STEALTH = 995, +}; + +// Spawn locations +static const EVENTLOCATION aVolcorSpawnLocs[] = +{ + {4630.2f, 22.6f, 70.1f, 2.4f}, + {4603.8f, 53.5f, 70.4f, 5.4f}, + {4627.5f, 100.4f, 62.7f, 5.8f}, + {4692.8f, 75.8f, 56.7f, 3.1f}, + {4747.8f, 152.8f, 54.6f, 2.4f}, + {4711.7f, 109.1f, 53.5f, 2.4f}, +}; + +struct MANGOS_DLL_DECL npc_volcorAI : public npc_escortAI +{ + npc_volcorAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiQuestId; + + void Reset() + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_uiQuestId = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + // shouldn't always use text on agro + switch (urand(0, 4)) + { + case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; + } + } + + 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); + } + + // 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 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 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 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; + } + } +}; + +CreatureAI* GetAI_npc_volcor(Creature* pCreature) +{ + return new npc_volcorAI(pCreature); +} + +bool QuestAccept_npc_volcor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ESCAPE_THROUGH_FORCE || pQuest->GetQuestId() == QUEST_ESCAPE_THROUGH_STEALTH) + { + if (npc_volcorAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->StartEscort(pPlayer, pQuest); + } + + return true; +} + +/*#### +# npc_therylune +####*/ + +enum +{ + SAY_THERYLUNE_START = -1000905, + SAY_THERYLUNE_FINISH = -1000906, + + NPC_THERYSIL = 3585, + + QUEST_ID_THERYLUNE_ESCAPE = 945, +}; + +struct MANGOS_DLL_DECL npc_theryluneAI : public npc_escortAI +{ + npc_theryluneAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + + void Reset() {} + + 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 MANGOS_DLL_DECL 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->RemoveAllAuras(); + 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; @@ -387,13 +735,13 @@ void AddSC_darkshore() pNewScript = new Script; pNewScript->Name = "npc_kerlonian"; pNewScript->GetAI = &GetAI_npc_kerlonian; - pNewScript->pQuestAccept = &QuestAccept_npc_kerlonian; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kerlonian; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_prospector_remtravel"; pNewScript->GetAI = &GetAI_npc_prospector_remtravel; - pNewScript->pQuestAccept = &QuestAccept_npc_prospector_remtravel; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_prospector_remtravel; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -402,4 +750,21 @@ void AddSC_darkshore() pNewScript->pGossipHello = &GossipHello_npc_threshwackonator; pNewScript->pGossipSelect = &GossipSelect_npc_threshwackonator; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_volcor"; + 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 e3ea63b4df..a9cac6a886 100644 --- a/scripts/kalimdor/desolace.cpp +++ b/scripts/kalimdor/desolace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,15 +17,22 @@ /* ScriptData SDName: Desolace SD%Complete: 100 -SDComment: Quest support: 5561 +SDComment: Quest support: 1440, 5561, 6132 SDCategory: Desolace EndScriptData */ /* ContentData npc_aged_dying_ancient_kodo +npc_dalinda_malem +npc_melizza_brimbuzzle EndContentData */ #include "precompiled.h" +#include "escort_ai.h" + +/*###### +## npc_aged_dying_ancient_kodo +######*/ enum { @@ -42,10 +49,9 @@ 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 @@ -59,7 +65,7 @@ struct MANGOS_DLL_DECL npc_aged_dying_ancient_kodoAI : public ScriptedAI m_uiDespawnTimer = 0; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (pWho->GetEntry() == NPC_SMEED) { @@ -68,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) { @@ -90,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()) @@ -102,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; @@ -116,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(); @@ -140,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; @@ -150,25 +157,259 @@ 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 - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); + // the expected quest objective + pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); pPlayer->RemoveAurasDueToSpell(SPELL_KODO_KOMBO_PLAYER_BUFF); pCreature->GetMotionMaster()->MoveIdle(); } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_dalinda_malem +######*/ + +enum +{ + QUEST_RETURN_TO_VAHLARRIEL = 1440, +}; + +struct MANGOS_DLL_DECL npc_dalinda_malemAI : public npc_escortAI +{ + npc_dalinda_malemAI(Creature* m_creature) : npc_escortAI(m_creature) { Reset(); } + + void Reset() {} + + void JustStartedEscort() override + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + } + + void WaypointReached(uint32 uiPointId) override + { + if (uiPointId == 18) + { + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_RETURN_TO_VAHLARRIEL, m_creature); + } + } +}; + +CreatureAI* GetAI_npc_dalinda_malem(Creature* pCreature) +{ + return new npc_dalinda_malemAI(pCreature); +} + +bool QuestAccept_npc_dalinda_malem(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_RETURN_TO_VAHLARRIEL) + { + 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->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_PASSIVE); + pEscortAI->Start(false, pPlayer, pQuest); + } + } + return true; +} + +/*###### +## npc_melizza_brimbuzzle +######*/ + +enum +{ + QUEST_GET_ME_OUT_OF_HERE = 6132, + + GO_MELIZZAS_CAGE = 177706, + + SAY_MELIZZA_START = -1000784, + SAY_MELIZZA_FINISH = -1000785, + SAY_MELIZZA_1 = -1000786, + SAY_MELIZZA_2 = -1000787, + SAY_MELIZZA_3 = -1000788, + + NPC_MARAUDINE_MARAUDER = 4659, + NPC_MARAUDINE_BONEPAW = 4660, + NPC_MARAUDINE_WRANGLER = 4655, + + NPC_MELIZZA = 12277, + + POINT_ID_QUEST_COMPLETE = 1, + POINT_ID_EVENT_COMPLETE = 2, + + MAX_MARAUDERS = 2, + MAX_WRANGLERS = 3, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {POINT_ID_QUEST_COMPLETE, 0, 1000}, + {QUEST_GET_ME_OUT_OF_HERE, NPC_MELIZZA, 0}, + {POINT_ID_EVENT_COMPLETE, 0, 2000}, + {SAY_MELIZZA_1, NPC_MELIZZA, 4000}, + {SAY_MELIZZA_2, NPC_MELIZZA, 5000}, + {SAY_MELIZZA_3, NPC_MELIZZA, 4000}, + {NPC_MELIZZA, 0, 0}, + {0, 0, 0}, +}; + +static const LOCATION aMarauderSpawn[]= +{ + { -1291.492f, 2644.650f, 111.556f}, + { -1306.730f, 2675.163f, 111.561f}, +}; + +static const LOCATION aWranglerSpawn[]= +{ + {-1393.194f, 2429.465f, 88.689f}, +}; + +struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private DialogueHelper +{ + npc_melizza_brimbuzzleAI(Creature* m_creature) : npc_escortAI(m_creature), + DialogueHelper(aIntroDialogue) + { + Reset(); + } + + void Reset() {} + + void JustStartedEscort() override + { + if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_MELIZZAS_CAGE, INTERACTION_DISTANCE)) + pCage->UseDoorOrButton(); + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_MELIZZA) + return m_creature; + + return NULL; + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 1: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_MELIZZA_START, m_creature, pPlayer); + + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + break; + case 4: + for (uint8 i = 0; i < MAX_MARAUDERS; ++i) + { + for (uint8 j = 0; j < MAX_MARAUDERS; ++j) + { + // Summon 2 Marauders on each point + float fX, fY, fZ; + m_creature->GetRandomPoint(aMarauderSpawn[i].x, aMarauderSpawn[i].y, aMarauderSpawn[i].z, 7.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_MARAUDINE_MARAUDER, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + break; + case 9: + for (uint8 i = 0; i < MAX_WRANGLERS; ++i) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(aWranglerSpawn[0].x, aWranglerSpawn[0].y, aWranglerSpawn[0].z, 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].x, aWranglerSpawn[0].y, aWranglerSpawn[0].z, 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_MARAUDINE_WRANGLER, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + break; + case 12: + StartNextDialogueText(POINT_ID_QUEST_COMPLETE); + break; + case 19: + StartNextDialogueText(POINT_ID_EVENT_COMPLETE); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case POINT_ID_QUEST_COMPLETE: + SetEscortPaused(true); + break; + case QUEST_GET_ME_OUT_OF_HERE: + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_MELIZZA_FINISH, m_creature, pPlayer); + pPlayer->GroupEventHappens(QUEST_GET_ME_OUT_OF_HERE, m_creature); + } + + m_creature->ClearTemporaryFaction(); + SetRun(true); + SetEscortPaused(false); + break; + case POINT_ID_EVENT_COMPLETE: + SetEscortPaused(true); + m_creature->SetFacingTo(4.71f); + break; + case NPC_MELIZZA: + SetEscortPaused(false); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_melizza_brimbuzzle(Creature* pCreature) +{ + return new npc_melizza_brimbuzzleAI(pCreature); +} + +bool QuestAccept_npc_melizza_brimbuzzle(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_GET_ME_OUT_OF_HERE) + { + if (npc_melizza_brimbuzzleAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest); + } + return true; } void AddSC_desolace() { - Script *newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_aged_dying_ancient_kodo"; + pNewScript->GetAI = &GetAI_npc_aged_dying_ancient_kodo; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_aged_dying_ancient_kodo; + pNewScript->pGossipHello = &GossipHello_npc_aged_dying_ancient_kodo; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dalinda_malem"; + pNewScript->GetAI = &GetAI_npc_dalinda_malem; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_dalinda_malem; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_aged_dying_ancient_kodo"; - newscript->GetAI = &GetAI_npc_aged_dying_ancient_kodo; - newscript->pEffectDummyCreature = &EffectDummyCreature_npc_aged_dying_ancient_kodo; - newscript->pGossipHello = &GossipHello_npc_aged_dying_ancient_kodo; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_melizza_brimbuzzle"; + pNewScript->GetAI = &GetAI_npc_melizza_brimbuzzle; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_melizza_brimbuzzle; + pNewScript->RegisterSelf(); } diff --git a/scripts/world/boss_lethon.cpp b/scripts/kalimdor/dire_maul/dire_maul.cpp similarity index 83% rename from scripts/world/boss_lethon.cpp rename to scripts/kalimdor/dire_maul/dire_maul.cpp index a524dc8775..28d5ed68d8 100644 --- a/scripts/world/boss_lethon.cpp +++ b/scripts/kalimdor/dire_maul/dire_maul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,10 +15,14 @@ */ /* ScriptData -SDName: Lethon +SDName: dire_maul SD%Complete: 0 -SDComment: Place Holder -SDCategory: Bosses +SDComment: Placeholder +SDCategory: Dire Maul EndScriptData */ #include "precompiled.h" + +void AddSC_dire_maul() +{ +} diff --git a/scripts/kalimdor/dire_maul/dire_maul.h b/scripts/kalimdor/dire_maul/dire_maul.h new file mode 100644 index 0000000000..05e97fa747 --- /dev/null +++ b/scripts/kalimdor/dire_maul/dire_maul.h @@ -0,0 +1,135 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_DM_H +#define DEF_DM_H + +enum +{ + MAX_ENCOUNTER = 16, + MAX_GENERATORS = 5, + + // East + TYPE_ALZZIN = 0, // Do not change - Handled with Acid + TYPE_ZEVRIM = 1, + TYPE_IRONBARK = 2, + + // West + TYPE_WARPWOOD = 3, + TYPE_IMMOLTHAR = 4, + TYPE_PRINCE = 5, + TYPE_PYLON_1 = 6, + TYPE_PYLON_2 = TYPE_PYLON_1 + 1, + TYPE_PYLON_3 = TYPE_PYLON_1 + 2, + TYPE_PYLON_4 = TYPE_PYLON_1 + 3, + TYPE_PYLON_5 = TYPE_PYLON_1 + 4, + + // North + TYPE_KING_GORDOK = 11, + TYPE_MOLDAR = 12, + TYPE_FENGUS = 13, + TYPE_SLIPKIK = 14, + TYPE_KROMCRUSH = 15, + + // East + GO_CRUMBLE_WALL = 177220, + GO_CORRUPT_VINE = 179502, + GO_FELVINE_SHARD = 179559, + GO_CONSERVATORY_DOOR = 176907, // Opened by Ironbark the redeemed + + NPC_ZEVRIM_THORNHOOF = 11490, + NPC_OLD_IRONBARK = 11491, + NPC_IRONBARK_REDEEMED = 14241, + + // West + NPC_TENDRIS_WARPWOOD = 11489, + NPC_PRINCE_TORTHELDRIN = 11486, + NPC_IMMOLTHAR = 11496, + NPC_ARCANE_ABERRATION = 11480, + NPC_MANA_REMNANT = 11483, + NPC_HIGHBORNE_SUMMONER = 11466, + + GO_PRINCES_CHEST = 179545, + GO_PRINCES_CHEST_AURA = 179563, + GO_CRYSTAL_GENERATOR_1 = 177259, + GO_CRYSTAL_GENERATOR_2 = 177257, + GO_CRYSTAL_GENERATOR_3 = 177258, + GO_CRYSTAL_GENERATOR_4 = 179504, + GO_CRYSTAL_GENERATOR_5 = 179505, + GO_FORCEFIELD = 179503, + GO_WARPWOOD_DOOR = 177221, + GO_WEST_LIBRARY_DOOR = 179550, + + // North + NPC_GUARD_MOLDAR = 14326, + NPC_STOMPER_KREEG = 14322, + NPC_GUARD_FENGUS = 14321, + NPC_GUARD_SLIPKIK = 14323, + NPC_CAPTAIN_KROMCRUSH = 14325, + NPC_CHORUSH = 14324, + NPC_KING_GORDOK = 11501, + NPC_MIZZLE_THE_CRAFTY = 14353, + + 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, + + FACTION_HOSTILE = 14, + SPELL_KING_OF_GORDOK = 22799, +}; + +class MANGOS_DLL_DECL instance_dire_maul : public ScriptedInstance +{ + public: + instance_dire_maul(Map* pMap); + ~instance_dire_maul() {} + + void Initialize() 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 OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + + 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, ConditionSource conditionSourceType) const override; + + protected: + bool CheckAllGeneratorsDestroyed(); + void ProcessForceFieldOpening(); + void SortPylonGuards(); + void PylonGuardJustDied(Creature* pCreature); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + // East + bool m_bWallDestroyed; + GuidList m_lFelvineShardGUIDs; + + // West + ObjectGuid m_aCrystalGeneratorGuid[MAX_GENERATORS]; + + GuidList m_luiHighborneSummonerGUIDs; + std::queue m_lGeneratorGuardGUIDs; + GuidSet 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 new file mode 100644 index 0000000000..27091c358f --- /dev/null +++ b/scripts/kalimdor/dire_maul/instance_dire_maul.cpp @@ -0,0 +1,503 @@ +/* Copyright (C) 2006 - 2013 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: instance_dire_maul +SD%Complete: 30 +SDComment: Basic Support - Most events and quest-related stuff missing +SDCategory: Dire Maul +EndScriptData */ + +#include "precompiled.h" +#include "dire_maul.h" + +instance_dire_maul::instance_dire_maul(Map* pMap) : ScriptedInstance(pMap), + m_bWallDestroyed(false), + m_bDoNorthBeforeWest(false) +{ + Initialize(); +} + +void instance_dire_maul::Initialize() +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + m_auiEncounter[i] = 0; + + m_luiHighborneSummonerGUIDs.clear(); +} + +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()) + { + // East + case NPC_OLD_IRONBARK: + break; + + // West + case NPC_PRINCE_TORTHELDRIN: + if (m_auiEncounter[TYPE_IMMOLTHAR] == DONE) + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_OOC_NOT_ATTACK); + break; + case NPC_ARCANE_ABERRATION: + case NPC_MANA_REMNANT: + m_lGeneratorGuardGUIDs.push(pCreature->GetObjectGuid()); + return; + case NPC_IMMOLTHAR: + break; + case NPC_HIGHBORNE_SUMMONER: + m_luiHighborneSummonerGUIDs.push_back(pCreature->GetObjectGuid()); + return; + + // North + case NPC_CHORUSH: + case NPC_KING_GORDOK: + case NPC_MIZZLE_THE_CRAFTY: + break; + + default: + return; + } + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); +} + +void instance_dire_maul::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + // East + case GO_CONSERVATORY_DOOR: + if (m_auiEncounter[TYPE_IRONBARK] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_CRUMBLE_WALL: + if (m_bWallDestroyed || m_auiEncounter[TYPE_ALZZIN] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_CORRUPT_VINE: + if (m_auiEncounter[TYPE_ALZZIN] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FELVINE_SHARD: + m_lFelvineShardGUIDs.push_back(pGo->GetObjectGuid()); + break; + + // West + case GO_CRYSTAL_GENERATOR_1: + m_aCrystalGeneratorGuid[0] = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_PYLON_1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + return; + case GO_CRYSTAL_GENERATOR_2: + m_aCrystalGeneratorGuid[1] = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_PYLON_2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + return; + case GO_CRYSTAL_GENERATOR_3: + m_aCrystalGeneratorGuid[2] = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_PYLON_3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + return; + case GO_CRYSTAL_GENERATOR_4: + m_aCrystalGeneratorGuid[3] = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_PYLON_4] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + return; + case GO_CRYSTAL_GENERATOR_5: + m_aCrystalGeneratorGuid[4] = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_PYLON_5] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + return; + case GO_FORCEFIELD: + if (CheckAllGeneratorsDestroyed()) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_PRINCES_CHEST_AURA: + break; + case GO_WARPWOOD_DOOR: + 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; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + // East + case TYPE_ZEVRIM: + if (uiData == DONE) + { + // Update Old Ironbark so he can open the conservatory door + if (Creature* pIronbark = GetSingleCreatureFromStorage(NPC_OLD_IRONBARK)) + { + DoScriptText(SAY_IRONBARK_REDEEM, pIronbark); + pIronbark->UpdateEntry(NPC_IRONBARK_REDEEMED); + } + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_IRONBARK: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_ALZZIN: // This Encounter is expected to be handled within Acid (reason handling at 50% hp) + if (uiData == DONE) + { + if (!m_bWallDestroyed) + { + DoUseDoorOrButton(GO_CRUMBLE_WALL); + m_bWallDestroyed = true; + } + + DoUseDoorOrButton(GO_CORRUPT_VINE); + + if (!m_lFelvineShardGUIDs.empty()) + { + for (GuidList::const_iterator itr = m_lFelvineShardGUIDs.begin(); itr != m_lFelvineShardGUIDs.end(); ++itr) + DoRespawnGameObject(*itr); + } + } + else if (uiData == SPECIAL && !m_bWallDestroyed) + { + DoUseDoorOrButton(GO_CRUMBLE_WALL); + m_bWallDestroyed = true; + } + m_auiEncounter[uiType] = uiData; + break; + + // West + case TYPE_WARPWOOD: + if (uiData == DONE) + DoUseDoorOrButton(GO_WARPWOOD_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_IMMOLTHAR: + if (uiData == DONE) + { + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_PRINCE_TORTHELDRIN)) + { + DoScriptText(SAY_FREE_IMMOLTHAR, pPrince); + 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); + } + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_PRINCE: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_PYLON_1: + case TYPE_PYLON_2: + case TYPE_PYLON_3: + case TYPE_PYLON_4: + case TYPE_PYLON_5: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoUseDoorOrButton(m_aCrystalGeneratorGuid[uiType - TYPE_PYLON_1]); + if (CheckAllGeneratorsDestroyed()) + ProcessForceFieldOpening(); + } + break; + + // 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) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->CastSpell(pPlayer, SPELL_KING_OF_GORDOK, true); + } + } + break; + case TYPE_MOLDAR: + case TYPE_FENGUS: + case TYPE_SLIPKIK: + case TYPE_KROMCRUSH: + 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_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(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_dire_maul::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_dire_maul::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + // West + // - Handling of guards of generators + case NPC_ARCANE_ABERRATION: + case NPC_MANA_REMNANT: + SortPylonGuards(); + break; + // - Set InstData for ImmolThar + case NPC_IMMOLTHAR: + SetData(TYPE_IMMOLTHAR, IN_PROGRESS); + break; + } +} + +void instance_dire_maul::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + // East + // - Handling Zevrim and Old Ironbark for the door event + case NPC_ZEVRIM_THORNHOOF: + SetData(TYPE_ZEVRIM, DONE); + break; + case NPC_IRONBARK_REDEEMED: + SetData(TYPE_IRONBARK, DONE); + break; + + // West + // - Handling of guards of generators + case NPC_ARCANE_ABERRATION: + case NPC_MANA_REMNANT: + PylonGuardJustDied(pCreature); + break; + // - InstData settings + case NPC_TENDRIS_WARPWOOD: + SetData(TYPE_WARPWOOD, DONE); + break; + case NPC_IMMOLTHAR: + SetData(TYPE_IMMOLTHAR, DONE); + break; + + // 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; + } +} + +void instance_dire_maul::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] >> 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; + + 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_dire_maul::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource 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) + return false; + + return true; +} + +void instance_dire_maul::ProcessForceFieldOpening() +{ + // 'Open' the force field + DoUseDoorOrButton(GO_FORCEFIELD); + + // Let the summoners attack Immol'Thar + Creature* pImmolThar = GetSingleCreatureFromStorage(NPC_IMMOLTHAR); + if (!pImmolThar || pImmolThar->isDead()) + return; + + bool bHasYelled = false; + for (GuidList::const_iterator itr = m_luiHighborneSummonerGUIDs.begin(); itr != m_luiHighborneSummonerGUIDs.end(); ++itr) + { + Creature* pSummoner = instance->GetCreature(*itr); + + if (!bHasYelled && pSummoner) + { + DoScriptText(SAY_KILL_IMMOLTHAR, pSummoner); + bHasYelled = true; + } + + if (!pSummoner || pSummoner->isDead()) + continue; + + pSummoner->AI()->AttackStart(pImmolThar); + } + m_luiHighborneSummonerGUIDs.clear(); +} + +void instance_dire_maul::SortPylonGuards() +{ + // Sort all remaining (alive) NPCs to unfinished generators + while(!m_lGeneratorGuardGUIDs.empty()) + { + ObjectGuid guid = m_lGeneratorGuardGUIDs.front(); + m_lGeneratorGuardGUIDs.pop(); + + Creature* pGuard = instance->GetCreature(guid); + if (!pGuard || pGuard->isDead()) // Remove invalid guids and dead guards + continue; + + for (uint8 i = 0; i < MAX_GENERATORS; ++i) + { + GameObject* pGenerator = instance->GetGameObject(m_aCrystalGeneratorGuid[i]); + // Skip non-existing or finished generators + if (pGenerator && GetData(TYPE_PYLON_1 + i) != DONE && + pGuard->IsWithinDistInMap(pGenerator, 20.0f)) + m_sSortedGeneratorGuards[i].insert(guid); + } + } +} + +void instance_dire_maul::PylonGuardJustDied(Creature* pCreature) +{ + for (uint8 i = 0; i < MAX_GENERATORS; ++i) + { + // Skip already activated generators + if (GetData(TYPE_PYLON_1 + i) == DONE) + continue; + + // Only process generator where the npc is sorted in + if (m_sSortedGeneratorGuards[i].find(pCreature->GetObjectGuid()) != m_sSortedGeneratorGuards[i].end()) + { + m_sSortedGeneratorGuards[i].erase(pCreature->GetObjectGuid()); + if (m_sSortedGeneratorGuards[i].empty()) + SetData(TYPE_PYLON_1 + i, DONE); + + break; + } + } +} + +InstanceData* GetInstanceData_instance_dire_maul(Map* pMap) +{ + return new instance_dire_maul(pMap); +} + +void AddSC_instance_dire_maul() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_dire_maul"; + pNewScript->GetInstanceData = &GetInstanceData_instance_dire_maul; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/durotar.cpp b/scripts/kalimdor/durotar.cpp new file mode 100644 index 0000000000..9b752c87cb --- /dev/null +++ b/scripts/kalimdor/durotar.cpp @@ -0,0 +1,155 @@ +/* Copyright (C) 2006 - 2013 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: Durotar +SD%Complete: 100 +SDComment: Quest support: 5441 +SDCategory: Durotar +EndScriptData */ + +/* ContentData +npc_lazy_peon +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_lazy_peon +######*/ + +enum +{ + SAY_PEON_AWAKE_1 = -1000795, + SAY_PEON_AWAKE_2 = -1000796, + + SPELL_PEON_SLEEP = 17743, + SPELL_AWAKEN_PEON = 19938, + + NPC_SLEEPING_PEON = 10556, + GO_LUMBERPILE = 175784, +}; + +struct MANGOS_DLL_DECL npc_lazy_peonAI : public ScriptedAI +{ + 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; // Time, until the npc stops harvesting lumber + uint32 m_uiStopSleepingTimer; // Time, until the npcs (re)starts working on its own + + void Reset() + { + m_uiResetSleepTimer = 0; + m_uiStopSleepingTimer = urand(90000, 120000); // Sleeping aura has only 2min duration + } + + // 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; + + m_creature->HandleEmote(EMOTE_STATE_WORK_CHOPWOOD); + // TODO - random bevahior for self-invoked awakening guesswork + m_uiResetSleepTimer = uiPointId == 1 ? 80000 : urand(30000, 60000); + } + + 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; + } + else + m_uiResetSleepTimer -= uiDiff; + } + + if (m_uiStopSleepingTimer) + { + if (m_uiStopSleepingTimer <= uiDiff) + StartLumbering(m_creature); + else + m_uiStopSleepingTimer -= uiDiff; + } + } +}; + +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, ObjectGuid /*originalCasterGuid*/) +{ + // 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 (npc_lazy_peonAI* pPeonAI = dynamic_cast(pCreatureTarget->AI())) + pPeonAI->StartLumbering(pCaster); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +void AddSC_durotar() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_lazy_peon"; + pNewScript->GetAI = &GetAI_npc_lazy_peon; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_lazy_peon_awake; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/dustwallow_marsh.cpp b/scripts/kalimdor/dustwallow_marsh.cpp index bbf3f20b22..8bc38dfb91 100644 --- a/scripts/kalimdor/dustwallow_marsh.cpp +++ b/scripts/kalimdor/dustwallow_marsh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,24 +17,26 @@ /* ScriptData SDName: Dustwallow_Marsh SD%Complete: 95 -SDComment: Quest support: 558, 1173, 1273, 1324, 11209, 11126, 11142, 11180. Vendor Nat Pagle +SDComment: Quest support: 1173, 1222, 1270, 1273, 1324, 11180, 11198, 11209. SDCategory: Dustwallow Marsh EndScriptData */ /* ContentData mobs_risen_husk_spirit npc_restless_apparition -npc_deserter_agitator -npc_lady_jaina_proudmoore npc_morokk -npc_nat_pagle npc_ogron npc_private_hendel npc_cassa_crimsonwing +Lady Jaina Proudmoore +npc_stinky_ignatz +at_nats_landing +boss_tethyr EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "TemporarySummon.h" /*###### ## mobs_risen_husk_spirit @@ -44,13 +46,12 @@ 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 { mobs_risen_husk_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -60,7 +61,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; @@ -68,13 +69,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->GetGUID()); + m_pCreditPlayer->KilledMonsterCredit(pSummoned->GetEntry(), pSummoned->GetObjectGuid()); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; @@ -89,7 +90,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; @@ -97,7 +98,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; } @@ -107,7 +108,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; } @@ -145,19 +146,19 @@ struct MANGOS_DLL_DECL npc_restless_apparitionAI : public ScriptedAI 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; @@ -168,7 +169,7 @@ struct MANGOS_DLL_DECL npc_restless_apparitionAI : public ScriptedAI case 6: DoScriptText(SAY_RAND_7, m_creature); break; case 7: DoScriptText(SAY_RAND_8, m_creature); break; } - + m_uiTalk_Timer = 0; } else @@ -197,7 +198,7 @@ struct MANGOS_DLL_DECL npc_deserter_agitatorAI : public ScriptedAI void Reset() { - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); + m_creature->setFaction(m_creature->GetCreatureInfo()->FactionAlliance); } }; @@ -211,49 +212,14 @@ bool GossipHello_npc_deserter_agitator(Player* pPlayer, Creature* pCreature) if (pPlayer->GetQuestStatus(QUEST_TRAITORS_AMONG_US) == QUEST_STATUS_INCOMPLETE) { pCreature->setFaction(FACTION_THER_DESERTER); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); + pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); } else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -/*###### -## npc_lady_jaina_proudmoore -######*/ - -enum -{ - QUEST_JAINAS_AUTOGRAPH = 558, - SPELL_JAINAS_AUTOGRAPH = 23122 -}; - -#define GOSSIP_ITEM_JAINA "I know this is rather silly but i have a young ward who is a bit shy and would like your autograph." - -bool GossipHello_npc_lady_jaina_proudmoore(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(QUEST_JAINAS_AUTOGRAPH) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JAINA, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lady_jaina_proudmoore(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_SENDER_INFO) - { - pPlayer->SEND_GOSSIP_MENU(7012, pCreature->GetGUID()); - pPlayer->CastSpell(pPlayer, SPELL_JAINAS_AUTOGRAPH, false); - } - return true; -} - /*###### ## npc_morokk ######*/ @@ -279,11 +245,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); @@ -300,7 +266,7 @@ struct MANGOS_DLL_DECL npc_morokkAI : public npc_escortAI } } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -311,7 +277,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)) { @@ -330,7 +296,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()) { @@ -364,45 +330,13 @@ bool QuestAccept_npc_morokk(Player* pPlayer, Creature* pCreature, const Quest* p if (pQuest->GetQuestId() == QUEST_CHALLENGE_MOROKK) { if (npc_morokkAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(true, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(true, pPlayer, pQuest); return true; } return false; } -/*###### -## npc_nat_pagle -######*/ - -enum -{ - QUEST_NATS_MEASURING_TAPE = 8227 -}; - -bool GossipHello_npc_nat_pagle(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pCreature->isVendor() && pPlayer->GetQuestRewardStatus(QUEST_NATS_MEASURING_TAPE)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(7640, pCreature->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(7638, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_nat_pagle(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - - return true; -} /*###### ## npc_ogron @@ -449,8 +383,8 @@ 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 { @@ -468,7 +402,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI uint32 m_uiPhaseCounter; uint32 m_uiGlobalTimer; - void Reset() + void Reset() override { m_uiGlobalTimer = 5000; @@ -483,7 +417,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); @@ -495,7 +429,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); @@ -505,9 +439,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); @@ -522,7 +456,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { lCreatureList.push_back(pSummoned); @@ -534,9 +468,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); } } } @@ -545,7 +479,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; @@ -559,7 +493,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()) { @@ -569,11 +503,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)) @@ -599,10 +533,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; @@ -611,7 +545,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)) @@ -652,7 +586,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()) @@ -694,8 +628,8 @@ bool QuestAccept_npc_ogron(Player* pPlayer, Creature* pCreature, const Quest* pQ { if (npc_ogronAI* pEscortAI = dynamic_cast(pCreature->AI())) { - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest, true); - pCreature->setFaction(FACTION_ESCORT_N_FRIEND_PASSIVE); + pEscortAI->Start(false, pPlayer, pQuest, true); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_FRIEND_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_OGR_START, pCreature, pPlayer); } } @@ -721,25 +655,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 +// TODO: develop this further, end event not created struct MANGOS_DLL_DECL 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; @@ -750,7 +680,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) { @@ -765,10 +695,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; } @@ -778,34 +708,125 @@ CreatureAI* GetAI_npc_private_hendel(Creature* pCreature) return new npc_private_hendelAI(pCreature); } -/*###### -## npc_cassa_crimsonwing -######*/ +/*##### +## npc_stinky_ignatz +## TODO Note: Faction change is guessed +#####*/ enum { - QUEST_SURVEY_ALCAZ = 11142, - SPELL_ALCAZ_SURVEY = 42295 + 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, }; -#define GOSSIP_RIDE "" - -bool GossipHello_npc_cassa_crimsonwing(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_stinky_ignatzAI : public npc_escortAI { - if (pPlayer->GetQuestStatus(QUEST_SURVEY_ALCAZ) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_RIDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + npc_stinky_ignatzAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + ObjectGuid m_bogbeanPlantGuid; -bool GossipSelect_npc_cassa_crimsonwing(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + void Reset() override {} + + void Aggro(Unit* pWho) override { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_ALCAZ_SURVEY, false); + 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; } @@ -819,14 +840,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; @@ -834,6 +855,370 @@ 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 MANGOS_DLL_DECL 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->SetLevitate(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); +} + +/*###### +## Lady Jaina Proudmoore +######*/ + +enum +{ + SPELL_BLIZZARD = 20680, + SPELL_FIRE_BLAST = 20679, + SPELL_FIREBALL = 20692, + SPELL_SUMMON_WATER_ELEMENT = 20681, + SPELL_TELEPORT = 20682, + + QUEST_JAINAS_AUTOGRAPH = 558, + SPELL_JAINAS_AUTOGRAPH = 23122 +}; + +struct MANGOS_DLL_DECL boss_lady_jaina_proudmooreAI : public ScriptedAI +{ + boss_lady_jaina_proudmooreAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiBlizzardTimer; + uint32 m_uiFireBlastTimer; + uint32 m_uiFireballTimer; + uint32 m_uiTeleportTimer; + uint32 m_uiWaterElementTimer; + + void Reset() + { + m_uiBlizzardTimer = 15000; + m_uiFireBlastTimer = 5000; + m_uiFireballTimer = 7000; + m_uiTeleportTimer = 17000; + m_uiWaterElementTimer = 20000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBlizzardTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_BLIZZARD); + m_uiBlizzardTimer = urand(15000, 18000); + } + else + m_uiBlizzardTimer -= uiDiff; + + if (m_uiFireBlastTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_FIRE_BLAST); + m_uiFireBlastTimer = urand(5000, 8000); + } + else + m_uiFireBlastTimer -= uiDiff; + + if (m_uiFireballTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_FIREBALL); + m_uiFireballTimer = urand(7000, 10000); + } + else + m_uiFireballTimer -= uiDiff; + + if (m_uiTeleportTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_TELEPORT); + m_uiTeleportTimer = urand(17000, 25000); + } + else + m_uiTeleportTimer -= uiDiff; + + if (m_uiWaterElementTimer < uiDiff) + { + DoCast(m_creature, SPELL_SUMMON_WATER_ELEMENT); + m_uiWaterElementTimer = urand(20000, 30000); + } + else + m_uiWaterElementTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +#define GOSSIP_ITEM_JAINA "I know this is rather silly but i have a young ward who is a bit shy and would like your autograph." + +bool GossipHello_boss_lady_jaina_proudmoore(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + if (pPlayer->GetQuestStatus(QUEST_JAINAS_AUTOGRAPH) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JAINA, GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_boss_lady_jaina_proudmoore(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_SENDER_INFO) + { + pPlayer->SEND_GOSSIP_MENU(7012, pCreature->GetObjectGuid()); + pPlayer->CastSpell(pPlayer, SPELL_JAINAS_AUTOGRAPH, false); + } + return true; +} + +CreatureAI* GetAI_boss_lady_jaina_proudmoore(Creature* pCreature) +{ + return new boss_lady_jaina_proudmooreAI(pCreature); +} + void AddSC_dustwallow_marsh() { Script* pNewScript; @@ -854,44 +1239,44 @@ void AddSC_dustwallow_marsh() pNewScript->pGossipHello = &GossipHello_npc_deserter_agitator; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_lady_jaina_proudmoore"; - pNewScript->pGossipHello = &GossipHello_npc_lady_jaina_proudmoore; - pNewScript->pGossipSelect = &GossipSelect_npc_lady_jaina_proudmoore; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_morokk"; pNewScript->GetAI = &GetAI_npc_morokk; - pNewScript->pQuestAccept = &QuestAccept_npc_morokk; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_nat_pagle"; - pNewScript->pGossipHello = &GossipHello_npc_nat_pagle; - pNewScript->pGossipSelect = &GossipSelect_npc_nat_pagle; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_morokk; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_ogron"; pNewScript->GetAI = &GetAI_npc_ogron; - pNewScript->pQuestAccept = &QuestAccept_npc_ogron; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_ogron; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_private_hendel"; pNewScript->GetAI = &GetAI_npc_private_hendel; - pNewScript->pQuestAccept = &QuestAccept_npc_private_hendel; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_private_hendel; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_cassa_crimsonwing"; - pNewScript->pGossipHello = &GossipHello_npc_cassa_crimsonwing; - pNewScript->pGossipSelect = &GossipSelect_npc_cassa_crimsonwing; + 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(); + + pNewScript = new Script; + pNewScript->Name = "boss_lady_jaina_proudmoore"; + pNewScript->GetAI = &GetAI_boss_lady_jaina_proudmoore; + pNewScript->pGossipHello = &GossipHello_boss_lady_jaina_proudmoore; + pNewScript->pGossipSelect = &GossipSelect_boss_lady_jaina_proudmoore; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/felwood.cpp b/scripts/kalimdor/felwood.cpp index 4e8164e3bc..c5e8f2c172 100644 --- a/scripts/kalimdor/felwood.cpp +++ b/scripts/kalimdor/felwood.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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" /*#### @@ -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; @@ -73,9 +75,9 @@ struct MANGOS_DLL_DECL npc_kittenAI : public FollowerAI void Reset() { } - 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->GetGUID()); + 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->GetGUID()); - - 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->GetGUID()); - }else if (pPlayer->GetTeam() == HORDE) - pPlayer->SEND_GOSSIP_MENU(2845, pCreature->GetGUID()); - else - pPlayer->SEND_GOSSIP_MENU(2844, pCreature->GetGUID()); - 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->GetGUID()); - }else if (pPlayer->GetTeam() == ALLIANCE) - pPlayer->SEND_GOSSIP_MENU(2843, pCreature->GetGUID()); - else - pPlayer->SEND_GOSSIP_MENU(2842, pCreature->GetGUID()); - 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) ######*/ @@ -240,7 +183,7 @@ enum struct MANGOS_DLL_DECL 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; @@ -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 ChooseReward_npc_niby_the_almighty(Player* pPlayer, Creature* pCreature, const Quest* pQuest, uint32 slot) +bool QuestRewarded_npc_niby_the_almighty(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) { if (pQuest->GetQuestId() == QUEST_KROSHIUS) { @@ -355,7 +298,7 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI Reset(); } - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; uint32 m_uiKnockBackTimer; uint32 m_uiPhaseTimer; @@ -364,16 +307,10 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI void Reset() { m_uiKnockBackTimer = urand(5000, 8000); - m_uiPlayerGUID = 0; + 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) @@ -383,17 +320,17 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI m_uiPhase = 1; m_uiPhaseTimer = 2500; - m_uiPlayerGUID = pSource->GetGUID(); + m_playerGuid = pSource->GetObjectGuid(); // 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,19 +349,16 @@ 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); - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + 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)) AttackStart(pPlayer); } break; } - m_uiPhase++; + ++m_uiPhase; } else m_uiPhaseTimer -= uiDiff; @@ -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,378 @@ 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_STRENGHT_ARKONARIN = 18163, + SPELL_MORTAL_STRIKE = 16856, + SPELL_CLEAVE = 15496, + + QUEST_ID_RESCUE_JAEDENAR = 5203, + NPC_JAEDENAR_LEGIONNAIRE = 9862, + NPC_SPIRT_TREY = 11141, + GO_ARKONARIN_CHEST = 176225, + GO_ARKONARIN_CAGE = 176306, +}; + +struct MANGOS_DLL_DECL 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_STRENGHT_ARKONARIN); + break; + case 40: + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + m_bCanAttack = true; + DoScriptText(SAY_FOUND_EQUIPMENT, m_creature); + // ToDo: change equipment! + 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 MANGOS_DLL_DECL 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; @@ -477,7 +783,7 @@ void AddSC_felwood() pNewScript = new Script; pNewScript->Name = "npc_kitten"; pNewScript->GetAI = &GetAI_npc_kitten; - pNewScript->pEffectDummyCreature = &EffectDummyCreature_npc_kitten; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_kitten; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -486,16 +792,10 @@ 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; - pNewScript->pChooseReward = &ChooseReward_npc_niby_the_almighty; + pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_niby_the_almighty; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -503,4 +803,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 79463a8b0a..a7379c5eaf 100644 --- a/scripts/kalimdor/feralas.cpp +++ b/scripts/kalimdor/feralas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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->GetGUID()); - - 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->GetGUID()); - 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->GetGUID()); - } - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - return true; -} +#include "follower_ai.h" /*###### ## npc_oox22fe @@ -78,34 +56,34 @@ struct MANGOS_DLL_DECL 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); @@ -119,17 +97,17 @@ struct MANGOS_DLL_DECL npc_oox22feAI : public npc_escortAI 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,56 +123,196 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } /*###### -## npc_screecher_spirit +## npc_shay_leafrunner ######*/ -bool GossipHello_npc_screecher_spirit(Player* pPlayer, Creature* pCreature) +enum +{ + 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 MANGOS_DLL_DECL 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) { - pPlayer->SEND_GOSSIP_MENU(2039, pCreature->GetGUID()); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + 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 *newscript; - - newscript = new Script; - newscript->Name = "npc_gregan_brewspewer"; - newscript->pGossipHello = &GossipHello_npc_gregan_brewspewer; - newscript->pGossipSelect = &GossipSelect_npc_gregan_brewspewer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_oox22fe"; - newscript->GetAI = &GetAI_npc_oox22fe; - newscript->pQuestAccept = &QuestAccept_npc_oox22fe; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_screecher_spirit"; - newscript->pGossipHello = &GossipHello_npc_screecher_spirit; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_oox22fe"; + pNewScript->GetAI = &GetAI_npc_oox22fe; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_oox22fe; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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/firelands/boss_alysrazor.cpp b/scripts/kalimdor/firelands/boss_alysrazor.cpp new file mode 100644 index 0000000000..29a243057f --- /dev/null +++ b/scripts/kalimdor/firelands/boss_alysrazor.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_alysrazor +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_alysrazor() +{ +} diff --git a/scripts/kalimdor/firelands/boss_baleroc.cpp b/scripts/kalimdor/firelands/boss_baleroc.cpp new file mode 100644 index 0000000000..568c0ea4b0 --- /dev/null +++ b/scripts/kalimdor/firelands/boss_baleroc.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_baleroc +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_baleroc() +{ +} diff --git a/scripts/kalimdor/firelands/boss_bethtilac.cpp b/scripts/kalimdor/firelands/boss_bethtilac.cpp new file mode 100644 index 0000000000..cc55f448b2 --- /dev/null +++ b/scripts/kalimdor/firelands/boss_bethtilac.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_bethtilac +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_bethtilac() +{ +} diff --git a/scripts/kalimdor/firelands/boss_lord_rhyolith.cpp b/scripts/kalimdor/firelands/boss_lord_rhyolith.cpp new file mode 100644 index 0000000000..d78dfa4747 --- /dev/null +++ b/scripts/kalimdor/firelands/boss_lord_rhyolith.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lord_rhyolith +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lord_rhyolith() +{ +} diff --git a/scripts/kalimdor/firelands/boss_majordomo_staghelm.cpp b/scripts/kalimdor/firelands/boss_majordomo_staghelm.cpp new file mode 100644 index 0000000000..1a68ad9c6b --- /dev/null +++ b/scripts/kalimdor/firelands/boss_majordomo_staghelm.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_majordomo_staghelm +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_majordomo_staghelm() +{ +} diff --git a/scripts/kalimdor/firelands/boss_ragnaros_firelands.cpp b/scripts/kalimdor/firelands/boss_ragnaros_firelands.cpp new file mode 100644 index 0000000000..23bc7e67f8 --- /dev/null +++ b/scripts/kalimdor/firelands/boss_ragnaros_firelands.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ragnaros_firelands +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ragnaros_firelands() +{ +} diff --git a/scripts/kalimdor/firelands/boss_shannox.cpp b/scripts/kalimdor/firelands/boss_shannox.cpp new file mode 100644 index 0000000000..454f8ca1fc --- /dev/null +++ b/scripts/kalimdor/firelands/boss_shannox.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_shannox +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_shannox() +{ +} diff --git a/scripts/kalimdor/firelands/firelands.h b/scripts/kalimdor/firelands/firelands.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/firelands/firelands.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/firelands/instance_firelands.cpp b/scripts/kalimdor/firelands/instance_firelands.cpp new file mode 100644 index 0000000000..49d28c48fa --- /dev/null +++ b/scripts/kalimdor/firelands/instance_firelands.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_firelands +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Firelands +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_firelands() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_ammunae.cpp b/scripts/kalimdor/halls_of_origination/boss_ammunae.cpp new file mode 100644 index 0000000000..421a81afd4 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_ammunae.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ammunae +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ammunae() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_anraphet.cpp b/scripts/kalimdor/halls_of_origination/boss_anraphet.cpp new file mode 100644 index 0000000000..6ba868c5eb --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_anraphet.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_anraphet +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_anraphet() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_earthrager_ptah.cpp b/scripts/kalimdor/halls_of_origination/boss_earthrager_ptah.cpp new file mode 100644 index 0000000000..626626a758 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_earthrager_ptah.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_earthrager_ptah +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_earthrager_ptah() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_isiset.cpp b/scripts/kalimdor/halls_of_origination/boss_isiset.cpp new file mode 100644 index 0000000000..49f51c9fa2 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_isiset.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_isiset +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_isiset() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_rajh.cpp b/scripts/kalimdor/halls_of_origination/boss_rajh.cpp new file mode 100644 index 0000000000..8893314eb5 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_rajh.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_rajh +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_rajh() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_setesh.cpp b/scripts/kalimdor/halls_of_origination/boss_setesh.cpp new file mode 100644 index 0000000000..ae6df93043 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_setesh.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_setesh +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_setesh() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/boss_temple_guardian_anhuur.cpp b/scripts/kalimdor/halls_of_origination/boss_temple_guardian_anhuur.cpp new file mode 100644 index 0000000000..791bced05a --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/boss_temple_guardian_anhuur.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_temple_guardian_anhuur +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_temple_guardian_anhuur() +{ +} diff --git a/scripts/kalimdor/halls_of_origination/halls_of_origination.h b/scripts/kalimdor/halls_of_origination/halls_of_origination.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/halls_of_origination.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/halls_of_origination/instance_halls_of_origination.cpp b/scripts/kalimdor/halls_of_origination/instance_halls_of_origination.cpp new file mode 100644 index 0000000000..25783c4662 --- /dev/null +++ b/scripts/kalimdor/halls_of_origination/instance_halls_of_origination.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_halls_of_origination +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Halls of Origination +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_halls_of_origination() +{ +} diff --git a/scripts/kalimdor/lost_city_of_tolvir/boss_general_husam.cpp b/scripts/kalimdor/lost_city_of_tolvir/boss_general_husam.cpp new file mode 100644 index 0000000000..1b75724c9a --- /dev/null +++ b/scripts/kalimdor/lost_city_of_tolvir/boss_general_husam.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_general_husam +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Lost City of Tolvir +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_general_husam() +{ +} diff --git a/scripts/kalimdor/lost_city_of_tolvir/boss_lockmaw.cpp b/scripts/kalimdor/lost_city_of_tolvir/boss_lockmaw.cpp new file mode 100644 index 0000000000..7f7aa6a756 --- /dev/null +++ b/scripts/kalimdor/lost_city_of_tolvir/boss_lockmaw.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lockmaw +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Lost City of Tolvir +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lockmaw() +{ +} diff --git a/scripts/kalimdor/lost_city_of_tolvir/boss_prophet_barim.cpp b/scripts/kalimdor/lost_city_of_tolvir/boss_prophet_barim.cpp new file mode 100644 index 0000000000..5a23c69216 --- /dev/null +++ b/scripts/kalimdor/lost_city_of_tolvir/boss_prophet_barim.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_prophet_barim +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Lost City of Tolvir +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_prophet_barim() +{ +} diff --git a/scripts/kalimdor/lost_city_of_tolvir/boss_siamat.cpp b/scripts/kalimdor/lost_city_of_tolvir/boss_siamat.cpp new file mode 100644 index 0000000000..34bd8df0e2 --- /dev/null +++ b/scripts/kalimdor/lost_city_of_tolvir/boss_siamat.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_siamat +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Lost City of Tolvir +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_siamat() +{ +} diff --git a/scripts/kalimdor/lost_city_of_tolvir/instance_lost_city_of_tolvir.cpp b/scripts/kalimdor/lost_city_of_tolvir/instance_lost_city_of_tolvir.cpp new file mode 100644 index 0000000000..fed7b13910 --- /dev/null +++ b/scripts/kalimdor/lost_city_of_tolvir/instance_lost_city_of_tolvir.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_lost_city_of_tolvir +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Lost City of Tolvir +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_lost_city_of_tolvir() +{ +} diff --git a/scripts/kalimdor/lost_city_of_tolvir/lost_city_of_tolvir.h b/scripts/kalimdor/lost_city_of_tolvir/lost_city_of_tolvir.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/lost_city_of_tolvir/lost_city_of_tolvir.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ 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 b1495f9c4f..0000000000 --- a/scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "celebras_the_cursed"; - newscript->GetAI = &GetAI_celebras_the_cursed; - newscript->RegisterSelf(); -} diff --git a/scripts/kalimdor/maraudon/boss_landslide.cpp b/scripts/kalimdor/maraudon/boss_landslide.cpp deleted file mode 100644 index 69c211fd59..0000000000 --- a/scripts/kalimdor/maraudon/boss_landslide.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_landslide"; - newscript->GetAI = &GetAI_boss_landslide; - newscript->RegisterSelf(); -} diff --git a/scripts/kalimdor/maraudon/boss_noxxion.cpp b/scripts/kalimdor/maraudon/boss_noxxion.cpp index 7d9773d353..78b655fe10 100644 --- a/scripts/kalimdor/maraudon/boss_noxxion.cpp +++ b/scripts/kalimdor/maraudon/boss_noxxion.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,123 +24,98 @@ EndScriptData */ #include "precompiled.h" -#define SPELL_TOXICVOLLEY 21687 -#define SPELL_UPPERCUT 22916 +enum +{ + SPELL_TOXICVOLLEY = 21687, + SPELL_UPPERCUT = 22916, + SPELL_NOXXION_SPAWNS_AURA = 21708, + SPELL_NOXXION_SPAWNS_SUMMON = 21707, +}; struct MANGOS_DLL_DECL boss_noxxionAI : public ScriptedAI { boss_noxxionAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 ToxicVolley_Timer; - uint32 Uppercut_Timer; - uint32 Adds_Timer; - uint32 Invisible_Timer; - bool Invisible; - int Rand; - int RandX; - int RandY; - Creature* Summoned; + uint32 m_uiToxicVolleyTimer; + uint32 m_uiUppercutTimer; + uint32 m_uiSummonTimer; void Reset() { - ToxicVolley_Timer = 7000; - Uppercut_Timer = 16000; - Adds_Timer = 19000; - Invisible_Timer = 15000; //Too much too low? - Invisible = false; + m_uiToxicVolleyTimer = 7000; + m_uiUppercutTimer = 16000; + m_uiSummonTimer = 19000; } - void SummonAdds(Unit* victim) + void JustSummoned(Creature* pSummoned) override { - Rand = rand()%8; - switch(urand(0, 1)) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%8; - switch(urand(0, 1)) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Summoned = DoSpawnCreature(13456, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - if (Summoned) - Summoned->AI()->AttackStart(victim); + 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 (Invisible && Invisible_Timer < diff) - { - //Become visible again - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //Noxxion model - m_creature->SetDisplayId(11172); - Invisible = false; - //m_creature->m_canMove = true; - } else if (Invisible) - { - Invisible_Timer -= diff; - //Do nothing while invisible - return; - } - - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //ToxicVolley_Timer - if (ToxicVolley_Timer < diff) + if (m_uiToxicVolleyTimer < diff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_TOXICVOLLEY); - ToxicVolley_Timer = 9000; - }else ToxicVolley_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_TOXICVOLLEY) == CAST_OK) + m_uiToxicVolleyTimer = 9000; + } + else + m_uiToxicVolleyTimer -= diff; - //Uppercut_Timer - if (Uppercut_Timer < diff) + if (m_uiUppercutTimer < diff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 12000; - }else Uppercut_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_UPPERCUT) == CAST_OK) + m_uiUppercutTimer = 12000; + } + else + m_uiUppercutTimer -= diff; - //Adds_Timer - if (!Invisible && Adds_Timer < diff) + if (m_uiSummonTimer < diff) { - //Inturrupt any spell casting - //m_creature->m_canMove = true; - m_creature->InterruptNonMeleeSpells(false); - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // Invisible Model - m_creature->SetDisplayId(11686); - SummonAdds(m_creature->getVictim()); - SummonAdds(m_creature->getVictim()); - SummonAdds(m_creature->getVictim()); - SummonAdds(m_creature->getVictim()); - SummonAdds(m_creature->getVictim()); - Invisible = true; - Invisible_Timer = 15000; - - Adds_Timer = 40000; - }else Adds_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_NOXXION_SPAWNS_AURA) == CAST_OK) + m_uiSummonTimer = 40000; + } + else + m_uiSummonTimer -= diff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_noxxion(Creature* pCreature) { return new boss_noxxionAI(pCreature); } +bool EffectAuraDummy_spell_aura_dummy_noxxion_spawns(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_NOXXION_SPAWNS_AURA && pAura->GetEffIndex() == EFFECT_INDEX_0) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + if (bApply) + { + pTarget->CastSpell(pTarget, SPELL_NOXXION_SPAWNS_SUMMON, true); + pTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + else + pTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + return true; +} + void AddSC_boss_noxxion() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_noxxion"; - newscript->GetAI = &GetAI_boss_noxxion; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_noxxion"; + pNewScript->GetAI = &GetAI_boss_noxxion; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_noxxion_spawns; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/maraudon/boss_princess_theradras.cpp b/scripts/kalimdor/maraudon/boss_princess_theradras.cpp deleted file mode 100644 index 5d9574704f..0000000000 --- a/scripts/kalimdor/maraudon/boss_princess_theradras.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "boss_princess_theradras"; - newscript->GetAI = &GetAI_boss_ptheradras; - newscript->RegisterSelf(); -} diff --git a/scripts/kalimdor/molten_front.cpp b/scripts/kalimdor/molten_front.cpp new file mode 100644 index 0000000000..c1ed3277c6 --- /dev/null +++ b/scripts/kalimdor/molten_front.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Molten Front +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Molten Front +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_molten_front() +{ +} diff --git a/scripts/kalimdor/moonglade.cpp b/scripts/kalimdor/moonglade.cpp index 6211315184..2897ac70d9 100644 --- a/scripts/kalimdor/moonglade.cpp +++ b/scripts/kalimdor/moonglade.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,15 +17,14 @@ /* ScriptData SDName: Moonglade SD%Complete: 100 -SDComment: Quest support: 30, 272, 5929, 5930, 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 */ #include "precompiled.h" @@ -33,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->GetGUID()); - 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->GetGUID()); - } - 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->GetGUID()); - } - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(5376, pCreature->GetGUID()); - break; - } - return true; -} - -/*#### # npc_clintar_dw_spirit ####*/ @@ -116,15 +56,15 @@ struct MANGOS_DLL_DECL 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); @@ -142,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); @@ -152,12 +92,12 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI break; case 49: DoScriptText(SAY_END, m_creature, pPlayer); - pPlayer->TalkedToCreature(m_creature->GetEntry(), m_creature->GetGUID()); + pPlayer->TalkedToCreature(m_creature->GetEntry(), m_creature->GetObjectGuid()); break; } } - void Aggro(Unit* who) + void Aggro(Unit* /*who*/) override { DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature); } @@ -167,9 +107,9 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI 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)); @@ -178,19 +118,19 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI m_creature->SetVisibility(VISIBILITY_OFF); } - //called only from EffectDummy - void DoStart(uint64 uiPlayerGuid) + // 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; m_creature->SetVisibility(VISIBILITY_ON); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Start(false, uiPlayerGuid); + Start(false, pStarter && pStarter->GetTypeId() == TYPEID_PLAYER ? (Player*)pStarter : NULL); } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* summoned) override { summoned->AI()->AttackStart(m_creature); } @@ -201,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)) @@ -218,146 +158,828 @@ 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->GetGUID()); + 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 +## npc_keeper_remulos ######*/ -#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." +enum +{ + SPELL_CONJURE_RIFT = 25813, // summon Eranikus + SPELL_HEALING_TOUCH = 23381, + SPELL_REGROWTH = 20665, + 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 + + NPC_ERANIKUS_TYRANT = 15491, + NPC_NIGHTMARE_PHANTASM = 15629, // shadows summoned during the event - should cast 17228 and 21307 + NPC_REMULOS = 11832, + NPC_TYRANDE_WHISPERWIND = 15633, // appears with the priestess during the event to help the players - should cast healing spells + NPC_ELUNE_PRIESTESS = 15634, + + QUEST_NIGHTMARE_MANIFESTS = 8736, + + // yells -> in cronological order + SAY_REMULOS_INTRO_1 = -1000669, // remulos intro + SAY_REMULOS_INTRO_2 = -1000670, + SAY_REMULOS_INTRO_3 = -1000671, + SAY_REMULOS_INTRO_4 = -1000672, + SAY_REMULOS_INTRO_5 = -1000673, + + EMOTE_SUMMON_ERANIKUS = -1000674, // eranikus spawn - world emote + SAY_ERANIKUS_SPAWN = -1000675, + + SAY_REMULOS_TAUNT_1 = -1000676, // eranikus and remulos chat + EMOTE_ERANIKUS_LAUGH = -1000677, + SAY_ERANIKUS_TAUNT_2 = -1000678, + SAY_REMULOS_TAUNT_3 = -1000679, + SAY_ERANIKUS_TAUNT_4 = -1000680, + + EMOTE_ERANIKUS_ATTACK = -1000681, // start attack + SAY_REMULOS_DEFEND_1 = -1000682, + SAY_REMULOS_DEFEND_2 = -1000683, + SAY_ERANIKUS_SHADOWS = -1000684, + SAY_REMULOS_DEFEND_3 = -1000685, + SAY_ERANIKUS_ATTACK_1 = -1000686, + SAY_ERANIKUS_ATTACK_2 = -1000687, + SAY_ERANIKUS_ATTACK_3 = -1000688, + SAY_ERANIKUS_KILL = -1000706, + + SAY_TYRANDE_APPEAR = -1000689, // Tyrande appears + SAY_TYRANDE_HEAL = -1000690, // yelled by tyrande when healing is needed + SAY_TYRANDE_FORGIVEN_1 = -1000691, + SAY_TYRANDE_FORGIVEN_2 = -1000692, + SAY_TYRANDE_FORGIVEN_3 = -1000693, + SAY_ERANIKUS_DEFEAT_1 = -1000694, + SAY_ERANIKUS_DEFEAT_2 = -1000695, + SAY_ERANIKUS_DEFEAT_3 = -1000696, + EMOTE_ERANIKUS_REDEEM = -1000697, // world emote before WotLK + + EMOTE_TYRANDE_KNEEL = -1000698, + SAY_TYRANDE_REDEEMED = -1000699, + + SAY_REDEEMED_1 = -1000700, // eranikus redeemed + SAY_REDEEMED_2 = -1000701, + SAY_REDEEMED_3 = -1000702, + SAY_REDEEMED_4 = -1000703, + + SAY_REMULOS_OUTRO_1 = -1000704, // remulos outro + SAY_REMULOS_OUTRO_2 = -1000705, + + POINT_ID_ERANIKUS_FLIGHT = 0, + POINT_ID_ERANIKUS_COMBAT = 1, + POINT_ID_ERANIKUS_REDEEMED = 2, + + MAX_SHADOWS = 3, // the max shadows summoned per turn + MAX_SUMMON_TURNS = 10, // There are about 10 summoned shade waves +}; -bool GossipHello_npc_great_bear_spirit(Player* pPlayer, Creature* pCreature) +static const DialogueEntry aIntroDialogue[] = { - //ally or horde quest - if (pPlayer->GetQuestStatus(5929) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(5930) == QUEST_STATUS_INCOMPLETE) + {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 + {SAY_ERANIKUS_SPAWN, NPC_ERANIKUS_TYRANT, 11000}, + {SAY_REMULOS_TAUNT_1, NPC_REMULOS, 5000}, + {EMOTE_ERANIKUS_LAUGH, NPC_ERANIKUS_TYRANT, 3000}, + {SAY_ERANIKUS_TAUNT_2, NPC_ERANIKUS_TYRANT, 10000}, + {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 + {SAY_ERANIKUS_SHADOWS, NPC_ERANIKUS_TYRANT, 4000}, + {SAY_REMULOS_DEFEND_3, NPC_REMULOS, 0}, + {0, 0, 0}, +}; + +static EVENTLOCATION aEranikusLocations[] = +{ + {7881.72f, -2651.23f, 493.29f, 0.40f}, // eranikus spawn loc + {7929.86f, -2574.88f, 505.35f}, // eranikus flight move loc + {7912.98f, -2568.99f, 488.71f}, // eranikus combat move loc + {7906.57f, -2565.63f, 488.39f}, // eranikus redeemed loc +}; + +static EVENTLOCATION aTyrandeLocations[] = +{ + // Tyrande should appear along the pathway, but because of the missing pathfinding we'll summon here closer to Eranikus + {7948.89f, -2575.58f, 490.05f, 3.03f}, // tyrande spawn loc + {7888.32f, -2566.25f, 487.02f}, // tyrande heal loc + {7901.83f, -2565.24f, 488.04f}, // tyrande eranikus loc +}; + +static EVENTLOCATION aShadowsLocations[] = +{ + // Inside the house shades - first wave only + {7832.78f, -2604.57f, 489.29f}, + {7826.68f, -2538.46f, 489.30f}, + {7811.48f, -2573.20f, 488.49f}, + // Outside shade points - basically only the first set of coords is used for the summoning; there is no solid proof of using the other coords + {7888.32f, -2566.25f, 487.02f}, + {7946.12f, -2577.10f, 489.97f}, + {7963.00f, -2492.03f, 487.84f} +}; + +struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private DialogueHelper +{ + npc_keeper_remulosAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aIntroDialogue) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(4719, pCreature->GetGUID()); + Reset(); } - else - pPlayer->SEND_GOSSIP_MENU(4718, pCreature->GetGUID()); - return true; + uint32 m_uiHealTimer; + uint32 m_uiStarfireTimer; + uint32 m_uiShadesummonTimer; + uint32 m_uiOutroTimer; + + ObjectGuid m_eranikusGuid; + + uint8 m_uiOutroPhase; + uint8 m_uiSummonCount; + + bool m_bIsFirstWave; + + void Reset() + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiOutroTimer = 0; + m_uiOutroPhase = 0; + m_uiSummonCount = 0; + + m_eranikusGuid.Clear(); + + m_uiShadesummonTimer = 0; + m_uiHealTimer = 10000; + m_uiStarfireTimer = 25000; + + m_bIsFirstWave = true; + } + } + + void JustSummoned(Creature* pSummoned) override + { + 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_HOVER); + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pSummoned->SetLevitate(true); + break; + case NPC_NIGHTMARE_PHANTASM: + // ToDo: set faction to DB + pSummoned->setFaction(14); + pSummoned->AI()->AttackStart(m_creature); + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_ERANIKUS_TYRANT) + return; + + switch (uiPointId) + { + case POINT_ID_ERANIKUS_FLIGHT: + // Set Eranikus to face Remulos + pSummoned->SetFacingToObject(m_creature); + break; + case POINT_ID_ERANIKUS_COMBAT: + // Start attack + pSummoned->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pSummoned->AI()->AttackStart(m_creature); + DoScriptText(SAY_ERANIKUS_ATTACK_2, pSummoned); + break; + } + } + + void JustDied(Unit* pKiller) override + { + // Make Eranikus evade in order to despawn all the summons + if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) + pEranikus->AI()->EnterEvadeMode(); + + npc_escortAI::JustDied(pKiller); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_REMULOS_INTRO_1, m_creature, pPlayer); + break; + case 1: + DoScriptText(SAY_REMULOS_INTRO_2, m_creature); + break; + case 13: + StartNextDialogueText(NPC_REMULOS); + SetEscortPaused(true); + break; + case 17: + StartNextDialogueText(SAY_REMULOS_DEFEND_2); + SetEscortPaused(true); + break; + case 18: + SetEscortPaused(true); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_REMULOS: return m_creature; + case NPC_ERANIKUS_TYRANT: return m_creature->GetMap()->GetCreature(m_eranikusGuid); + + default: + return NULL; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case NPC_REMULOS: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_REMULOS_INTRO_3, m_creature, pPlayer); + break; + case SPELL_CONJURE_RIFT: + DoCastSpellIfCan(m_creature, SPELL_CONJURE_RIFT); + break; + case SAY_ERANIKUS_SPAWN: + // This big yellow emote was removed at some point in WotLK + // DoScriptText(EMOTE_SUMMON_ERANIKUS, pEranikus); + break; + case NPC_ERANIKUS_TYRANT: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_REMULOS_DEFEND_1, m_creature, pPlayer); + if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) + pEranikus->GetMotionMaster()->MovePoint(POINT_ID_ERANIKUS_FLIGHT, aEranikusLocations[1].m_fX, aEranikusLocations[1].m_fY, aEranikusLocations[1].m_fZ); + SetEscortPaused(false); + break; + case SAY_REMULOS_DEFEND_2: + if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) + m_creature->SetFacingToObject(pEranikus); + break; + case SAY_REMULOS_DEFEND_3: + SetEscortPaused(true); + m_uiShadesummonTimer = 5000; + break; + } + } + + void DoHandleOutro(Creature* pTarget) + { + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_NIGHTMARE_MANIFESTS, pTarget); + + m_uiOutroTimer = 3000; + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (m_uiOutroTimer) + { + if (m_uiOutroTimer <= uiDiff) + { + switch (m_uiOutroPhase) + { + case 0: + DoScriptText(SAY_REMULOS_OUTRO_1, m_creature); + m_uiOutroTimer = 3000; + break; + 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->ForcedDespawn(3000); + m_uiOutroTimer = 0; + break; + } + ++m_uiOutroPhase; + } + else + m_uiOutroTimer -= uiDiff; + } + + // during the battle + if (m_uiShadesummonTimer) + { + if (m_uiShadesummonTimer <= uiDiff) + { + // do this yell only first time + if (m_bIsFirstWave) + { + // 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); + + if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) + DoScriptText(SAY_ERANIKUS_ATTACK_1, pEranikus); + + ++m_uiSummonCount; + SetEscortPaused(false); + m_bIsFirstWave = false; + } + + // 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) ? uint32(MAX_SHADOWS) : urand(MAX_SHADOWS + 1, MAX_SHADOWS + 2); + + if (m_uiSummonCount < MAX_SUMMON_TURNS) + { + for (uint8 i = 0; i < MAX_SHADOWS; ++i) + { + m_creature->GetRandomPoint(aShadowsLocations[uiSummonPoint].m_fX, aShadowsLocations[uiSummonPoint].m_fY, aShadowsLocations[uiSummonPoint].m_fZ, 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_NIGHTMARE_PHANTASM, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + ++m_uiSummonCount; + } + + // If all the shades were summoned then set Eranikus in combat + // We don't count the dead shades, because the boss is usually set in combat before all shades are dead + if (m_uiSummonCount == MAX_SUMMON_TURNS) + { + m_uiShadesummonTimer = 0; + + if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) + { + pEranikus->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0); + pEranikus->SetLevitate(false); + pEranikus->GetMotionMaster()->MovePoint(POINT_ID_ERANIKUS_COMBAT, aEranikusLocations[2].m_fX, aEranikusLocations[2].m_fY, aEranikusLocations[2].m_fZ); + } + } + else + m_uiShadesummonTimer = urand(20000, 30000); + } + else + m_uiShadesummonTimer -= uiDiff; + } + + // Combat spells + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHealTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(DEFAULT_VISIBILITY_DISTANCE)) + { + switch (urand(0, 2)) + { + case 0: DoCastSpellIfCan(pTarget, SPELL_HEALING_TOUCH); break; + case 1: DoCastSpellIfCan(pTarget, SPELL_REJUVENATION); break; + case 2: DoCastSpellIfCan(pTarget, SPELL_REGROWTH); break; + } + } + m_uiHealTimer = 10000; + } + else + m_uiHealTimer -= uiDiff; + + if (m_uiStarfireTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_STARFIRE) == CAST_OK) + m_uiStarfireTimer = 20000; + } + } + else + m_uiStarfireTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_keeper_remulos(Creature* pCreature) +{ + return new npc_keeper_remulosAI(pCreature); } -bool GossipSelect_npc_great_bear_spirit(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestAccept_npc_keeper_remulos(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - switch(uiAction) + if (pQuest->GetQuestId() == QUEST_NIGHTMARE_MANIFESTS) { - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(4735, pCreature->GetGUID()); - if (pPlayer->GetQuestStatus(5929)==QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(5929); - if (pPlayer->GetQuestStatus(5930)==QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(5930); - break; + if (npc_keeper_remulosAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(true, pPlayer, pQuest); + + return true; } - return true; + + // Return false for other quests in order to handle DB scripts. Example: quest 8447 + return false; +} + +bool EffectDummyCreature_conjure_rift(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* /*pCreatureTarget*/, ObjectGuid /*originalCasterGuid*/) +{ + // 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 + return true; + } + + return false; } /*###### -## npc_silva_filnaveth +## boss_eranikus ######*/ -#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?" +enum +{ + NPC_KEEPER_REMULOS = 11832, + + SPELL_ACID_BREATH = 24839, + SPELL_NOXIOUS_BREATH = 24818, + SPELL_SHADOWBOLT_VOLLEY = 25586, + SPELL_ARCANE_CHANNELING = 23017, // used by Tyrande - not sure if it's the right id -bool GossipHello_npc_silva_filnaveth(Player* pPlayer, Creature* pCreature) + FACTION_FRIENDLY = 35, + MAX_PRIESTESS = 7, + + POINT_ID_TYRANDE_HEAL = 0, + POINT_ID_TYRANDE_ABSOLUTION = 1, +}; + +struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI { - if (pPlayer->getClass() != CLASS_DRUID) - pPlayer->SEND_GOSSIP_MENU(4913, pCreature->GetGUID()); - else if (pPlayer->GetTeam() != ALLIANCE) + boss_eranikusAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiAcidBreathTimer; + uint32 m_uiNoxiousBreathTimer; + uint32 m_uiShadowboltVolleyTimer; + uint32 m_uiEventTimer; + uint32 m_uiTyrandeMoveTimer; + + uint8 m_uiEventPhase; + uint8 m_uiTyrandeMovePoint; + uint8 m_uiHealthCheck; + + ObjectGuid m_remulosGuid; + ObjectGuid m_tyrandeGuid; + GuidList m_lPriestessList; + + void Reset() { - 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); + m_uiAcidBreathTimer = 10000; + m_uiNoxiousBreathTimer = 3000; + m_uiShadowboltVolleyTimer = 5000; + m_uiTyrandeMoveTimer = 0; + + m_remulosGuid.Clear(); + m_tyrandeGuid.Clear(); - pPlayer->SEND_GOSSIP_MENU(4915, pCreature->GetGUID()); + m_uiHealthCheck = 85; + m_uiEventPhase = 0; + m_uiEventTimer = 0; + + // For some reason the boss doesn't move in combat + SetCombatMovement(false); } - else if (pPlayer->getClass() == CLASS_DRUID && pPlayer->GetTeam() == ALLIANCE) + + void EnterEvadeMode() override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTHERAN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + if (m_creature->GetHealthPercent() < 20.0f) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + // Get Remulos guid and make him stop summoning shades + if (Creature* pRemulos = GetClosestCreatureWithEntry(m_creature, NPC_REMULOS, 50.0f)) + { + m_remulosGuid = pRemulos->GetObjectGuid(); + pRemulos->AI()->EnterEvadeMode(); + } + + // Despawn the priestess + DoDespawnSummoned(); + + // redeem eranikus + m_uiEventTimer = 5000; + m_creature->setFaction(FACTION_FRIENDLY); + } + else + { + // There may be a core issue related to the reached home function for summoned creatures so we are cleaning things up here + // if the creature evades while the event is in progress then we despawn all the summoned, including himself + m_creature->ForcedDespawn(); + DoDespawnSummoned(); - 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); + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + pTyrande->ForcedDespawn(); + } + } - pPlayer->SEND_GOSSIP_MENU(4914, pCreature->GetGUID()); + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_ERANIKUS_KILL, m_creature); } - return true; -} -bool GossipSelect_npc_silva_filnaveth(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) + void DoSummonHealers() { - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(5375, pCreature->GetGUID()); - break; + float fX, fY, fZ; + for (uint8 j = 0; j < MAX_PRIESTESS; ++j) + { + m_creature->GetRandomPoint(aTyrandeLocations[0].m_fX, aTyrandeLocations[0].m_fY, aTyrandeLocations[0].m_fZ, 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_ELUNE_PRIESTESS, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } } - return true; -} -/*###### -## -######*/ + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_TYRANDE_WHISPERWIND: + m_tyrandeGuid = pSummoned->GetObjectGuid(); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(POINT_ID_TYRANDE_HEAL, aTyrandeLocations[1].m_fX, aTyrandeLocations[1].m_fY, aTyrandeLocations[1].m_fZ); + break; + case NPC_ELUNE_PRIESTESS: + m_lPriestessList.push_back(pSummoned->GetObjectGuid()); + float fX, fY, fZ; + pSummoned->SetWalk(false); + m_creature->GetRandomPoint(aTyrandeLocations[1].m_fX, aTyrandeLocations[1].m_fY, aTyrandeLocations[1].m_fZ, 10.0f, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(POINT_ID_TYRANDE_HEAL, fX, fY, fZ); + break; + } + } + + void DoDespawnSummoned() + { + 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) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case POINT_ID_TYRANDE_HEAL: + if (pSummoned->GetEntry() == NPC_TYRANDE_WHISPERWIND) + { + // Unmont, yell and prepare to channel the spell on Eranikus + DoScriptText(SAY_TYRANDE_HEAL, pSummoned); + pSummoned->Unmount(); + m_uiTyrandeMoveTimer = 5000; + } + // Unmount the priestess - unk what is their exact purpose (maybe healer) + else if (pSummoned->GetEntry() == NPC_ELUNE_PRIESTESS) + pSummoned->Unmount(); + break; + case POINT_ID_TYRANDE_ABSOLUTION: + if (pSummoned->GetEntry() == NPC_TYRANDE_WHISPERWIND) + { + pSummoned->CastSpell(pSummoned, SPELL_ARCANE_CHANNELING, false); + DoScriptText(SAY_TYRANDE_FORGIVEN_1, pSummoned); + } + break; + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || uiPointId != POINT_ID_ERANIKUS_REDEEMED) + return; + + DoScriptText(SAY_REDEEMED_1, m_creature); + m_uiEventTimer = 11000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiEventPhase) + { + case 0: + // Eranikus is redeemed - make Tyrande kneel and stop casting + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + { + pTyrande->InterruptNonMeleeSpells(false); + pTyrande->SetStandState(UNIT_STAND_STATE_KNEEL); + DoScriptText(EMOTE_TYRANDE_KNEEL, pTyrande); + } + if (Creature* pRemulos = m_creature->GetMap()->GetCreature(m_remulosGuid)) + 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 + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + m_uiEventTimer = 5000; + break; + case 1: + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + DoScriptText(SAY_TYRANDE_REDEEMED, pTyrande); + m_uiEventTimer = 6000; + break; + case 2: + // Transform Eranikus into elf + DoCastSpellIfCan(m_creature, SPELL_ERANIKUS_REDEEMED); + m_uiEventTimer = 5000; + break; + case 3: + // Move Eranikus in front of Tyrande + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_ERANIKUS_REDEEMED, aEranikusLocations[3].m_fX, aEranikusLocations[3].m_fY, aEranikusLocations[3].m_fZ); + m_uiEventTimer = 0; + break; + case 4: + DoScriptText(SAY_REDEEMED_2, m_creature); + m_uiEventTimer = 11000; + break; + case 5: + DoScriptText(SAY_REDEEMED_3, m_creature); + m_uiEventTimer = 13000; + break; + case 6: + DoScriptText(SAY_REDEEMED_4, m_creature); + m_uiEventTimer = 7000; + break; + case 7: + // Complete Quest and end event + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + { + pTyrande->SetStandState(UNIT_STAND_STATE_STAND); + pTyrande->ForcedDespawn(9000); + } + if (Creature* pRemulos = m_creature->GetMap()->GetCreature(m_remulosGuid)) + ((npc_keeper_remulosAI*)pRemulos->AI())->DoHandleOutro(m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_BOW); + m_creature->ForcedDespawn(2000); + break; + } + ++m_uiEventPhase; + } + else + m_uiEventTimer -= uiDiff; + } + + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Move Tyrande after she is summoned + if (m_uiTyrandeMoveTimer) + { + if (m_uiTyrandeMoveTimer <= uiDiff) + { + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + pTyrande->GetMotionMaster()->MovePoint(POINT_ID_TYRANDE_ABSOLUTION, aTyrandeLocations[2].m_fX, aTyrandeLocations[2].m_fY, aTyrandeLocations[2].m_fZ); + m_uiTyrandeMoveTimer = 0; + } + else + m_uiTyrandeMoveTimer -= uiDiff; + } + + // 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) + { + case 85: + DoScriptText(SAY_ERANIKUS_ATTACK_3, m_creature); + // Here Tyrande only yells but she doesn't appear anywhere - we summon here for 1 second just to handle the yell + if (Creature* pTyrande = m_creature->SummonCreature(NPC_TYRANDE_WHISPERWIND, aTyrandeLocations[0].m_fX, aTyrandeLocations[0].m_fY, aTyrandeLocations[0].m_fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 1000)) + DoScriptText(SAY_TYRANDE_APPEAR, pTyrande); + m_uiHealthCheck = 75; + break; + case 75: + // Eranikus yells again + DoScriptText(SAY_ERANIKUS_ATTACK_3, m_creature); + m_uiHealthCheck = 50; + break; + case 50: + // Summon Tyrande - she enters the fight this time + m_creature->SummonCreature(NPC_TYRANDE_WHISPERWIND, aTyrandeLocations[0].m_fX, aTyrandeLocations[0].m_fY, aTyrandeLocations[0].m_fZ, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_uiHealthCheck = 35; + break; + case 35: + // Summon the priestess + DoSummonHealers(); + DoScriptText(SAY_ERANIKUS_DEFEAT_1, m_creature); + m_uiHealthCheck = 31; + break; + case 31: + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + DoScriptText(SAY_TYRANDE_FORGIVEN_2, pTyrande); + m_uiHealthCheck = 27; + break; + case 27: + if (Creature* pTyrande = m_creature->GetMap()->GetCreature(m_tyrandeGuid)) + DoScriptText(SAY_TYRANDE_FORGIVEN_3, pTyrande); + m_uiHealthCheck = 25; + break; + case 25: + DoScriptText(SAY_ERANIKUS_DEFEAT_2, m_creature); + m_uiHealthCheck = 20; + break; + case 20: + // Eranikus is redeemed - stop the fight + DoScriptText(SAY_ERANIKUS_DEFEAT_3, m_creature); + m_creature->AI()->EnterEvadeMode(); + m_uiHealthCheck = 0; + break; + } + } + + // Combat spells + if (m_uiAcidBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ACID_BREATH) == CAST_OK) + m_uiAcidBreathTimer = 15000; + } + else + m_uiAcidBreathTimer -= uiDiff; + + if (m_uiNoxiousBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NOXIOUS_BREATH) == CAST_OK) + m_uiNoxiousBreathTimer = 30000; + } + else + m_uiNoxiousBreathTimer -= uiDiff; + + if (m_uiShadowboltVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOWBOLT_VOLLEY) == CAST_OK) + m_uiShadowboltVolleyTimer = 25000; + } + else + m_uiShadowboltVolleyTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_eranikus(Creature* pCreature) +{ + return new boss_eranikusAI(pCreature); +} void AddSC_moonglade() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_bunthen_plainswind"; - newscript->pGossipHello = &GossipHello_npc_bunthen_plainswind; - newscript->pGossipSelect = &GossipSelect_npc_bunthen_plainswind; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_clintar_dw_spirit"; - newscript->GetAI = &GetAI_npc_clintar_dw_spirit; - newscript->pEffectDummyCreature = &EffectDummyCreature_npc_clintar_dw_spirit; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_great_bear_spirit"; - newscript->pGossipHello = &GossipHello_npc_great_bear_spirit; - newscript->pGossipSelect = &GossipSelect_npc_great_bear_spirit; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_silva_filnaveth"; - newscript->pGossipHello = &GossipHello_npc_silva_filnaveth; - newscript->pGossipSelect = &GossipSelect_npc_silva_filnaveth; - newscript->RegisterSelf(); + Script* pNewScript; + + 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_keeper_remulos"; + pNewScript->GetAI = &GetAI_npc_keeper_remulos; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_keeper_remulos; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_conjure_rift; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_eranikus"; + pNewScript->GetAI = &GetAI_boss_eranikus; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/mount_hyjal.cpp b/scripts/kalimdor/mount_hyjal.cpp new file mode 100644 index 0000000000..b47e18f363 --- /dev/null +++ b/scripts/kalimdor/mount_hyjal.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Mount Hyjal +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mount Hyjal +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_mount_hyjal() +{ +} diff --git a/scripts/kalimdor/mulgore.cpp b/scripts/kalimdor/mulgore.cpp index 47fba87a3f..1035fa08c9 100644 --- a/scripts/kalimdor/mulgore.cpp +++ b/scripts/kalimdor/mulgore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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" @@ -50,7 +49,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI bool m_bEvent; bool m_bIsMovingToLunch; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; uint32 m_uiEventTimer; uint8 m_uiEventPhase; @@ -58,7 +57,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI { m_bEvent = false; m_bIsMovingToLunch = false; - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_uiEventTimer = 5000; m_uiEventPhase = 0; @@ -66,12 +65,12 @@ 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) { if (pCaster->GetTypeId() == TYPEID_PLAYER) - m_uiPlayerGUID = pCaster->GetGUID(); + m_playerGuid = pCaster->GetObjectGuid(); if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) { @@ -82,11 +81,11 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI m_bEvent = true; DoScriptText(EMOTE_SEE_LUNCH, m_creature); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CREATURE_SPECIAL); + m_creature->HandleEmote(EMOTE_ONESHOT_CREATURE_SPECIAL); } } - 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,35 +106,51 @@ 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_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { - if (GameObject* pGo = pPlayer->GetGameObject(SPELL_LUNCH)) + GameObject* pGo = pPlayer->GetGameObject(SPELL_LUNCH); + + // Workaround for broken function GetGameObject + if (!pGo) + { + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_LUNCH); + + uint32 uiGameobjectEntry = pSpell->GetEffectMiscValue(EFFECT_INDEX_1); + + pGo = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2 * INTERACTION_DISTANCE); + } + + if (pGo) { m_bIsMovingToLunch = true; - m_creature->GetMotionMaster()->MovePoint(POINT_ID, pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ()); + + float fX, fY, fZ; + pGo->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); + + m_creature->GetMotionMaster()->MovePoint(POINT_ID, fX, fY, fZ); } } break; case 2: DoScriptText(EMOTE_EAT_LUNCH, m_creature); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USESTANDING); + m_creature->HandleEmote(EMOTE_STATE_USESTANDING); break; case 3: - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) - pPlayer->TalkedToCreature(m_creature->GetEntry(), m_creature->GetGUID()); + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->TalkedToCreature(m_creature->GetEntry(), m_creature->GetObjectGuid()); m_creature->UpdateEntry(NPC_KYLE_FRIENDLY); break; case 4: m_uiEventTimer = 30000; DoScriptText(EMOTE_DANCE, m_creature); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCESPECIAL); + m_creature->HandleEmote(EMOTE_STATE_DANCESPECIAL); break; case 5: - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + m_creature->HandleEmote(EMOTE_STATE_NONE); Reset(); m_creature->GetMotionMaster()->Clear(); break; @@ -152,43 +167,12 @@ 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->GetGUID()); - - 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->GetGUID()); - - 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->GetGUID()); - - return true; -} - void AddSC_mulgore() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_kyle_the_frenzied"; - newscript->GetAI = &GetAI_npc_kyle_the_frenzied; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_skorn_whitecloud"; - newscript->pGossipHello = &GossipHello_npc_skorn_whitecloud; - newscript->pGossipSelect = &GossipSelect_npc_skorn_whitecloud; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_kyle_the_frenzied"; + pNewScript->GetAI = &GetAI_npc_kyle_the_frenzied; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp b/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp index 913eafa6e5..0435a7f8f5 100644 --- a/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp +++ b/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Onyxia -SD%Complete: 70 -SDComment: Phase 3 need additional code. The spawning Whelps need GO-Support. Erruption needs GO-Support +SD%Complete: 85 +SDComment: Phase 3 need additional code. The spawning Whelps need GO-Support. SDCategory: Onyxia's Lair EndScriptData */ @@ -42,10 +42,8 @@ enum SPELL_KNOCK_AWAY = 19633, SPELL_FIREBALL = 18392, SPELL_FIREBALL_H = 68926, - SPELL_ERRUPTION = 17731, // does not work - SPELL_ERRUPTION_H = 69294, // does not work - //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" @@ -57,49 +55,59 @@ enum SPELL_BREATH_SW_TO_NE = 18596, // 12x in "array" SPELL_BREATH_NE_TO_SW = 18617, // 12x in "array" - //SPELL_BREATH = 21131, // 8x in "array", different initial cast than the other arrays + 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_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, - NPC_WHELP = 11262, - 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 sOnyxMove +struct OnyxiaMove { - uint32 uiLocId; - uint32 uiLocIdEnd; uint32 uiSpellId; float fX, fY, fZ; }; -static sOnyxMove 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 float afSpawnLocations[4][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 @@ -108,7 +116,6 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI { m_pInstance = (instance_onyxias_lair*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - m_uiMaxBreathPositions = sizeof(aMoveData)/sizeof(sOnyxMove); 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; - sOnyxMove* m_pPointData; uint32 m_uiFireballTimer; uint32 m_uiSummonWhelpsTimer; @@ -137,6 +143,8 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI bool m_bIsSummoningWhelps; + uint32 m_uiPhaseTimer; + void Reset() { if (!IsCombatMovement()) @@ -148,98 +156,152 @@ 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); - m_creature->SetInCombatWithZone(); + + if (m_pInstance) + 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->RemoveSplineFlag(SPLINEFLAG_FLYING); + m_creature->SetLevitate(false); m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ONYXIA, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustDied(Unit* /*pKiller*/) override { - pSummoned->GetMotionMaster()->MovePoint(0, afSpawnLocations[3][0], afSpawnLocations[3][1], afSpawnLocations[3][2]); - pSummoned->SetInCombatWithZone(); + if (m_pInstance) + m_pInstance->SetData(TYPE_ONYXIA, DONE); + } + + void JustSummoned(Creature* pSummoned) override + { + if (!m_pInstance) + return; + + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER)) + { + // Get some random point near the center + float fX, fY, fZ; + pSummoned->GetRandomPoint(pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 20.0f, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + else + pSummoned->SetInCombatWithZone(); - if (pSummoned->GetEntry() == NPC_WHELP) + if (pSummoned->GetEntry() == NPC_ONYXIA_WHELP) ++m_uiSummonCount; } - void KilledUnit(Unit* pVictim) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || uiPointId != 1 || !m_creature->getVictim()) + return; + + pSummoned->SetInCombatWithZone(); + } + + 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) { - if (m_pPointData = GetMoveData()) - { - if (!m_pInstance) - return; - - if (Creature* pTrigger = m_pInstance->instance->GetCreature(m_pInstance->GetOnyxiaTriggerGUID())) - { - m_creature->GetMap()->CreatureRelocation(m_creature, m_pPointData->fX, m_pPointData->fY, m_pPointData->fZ, m_creature->GetAngle(pTrigger)); - m_creature->SendMonsterMove(m_pPointData->fX, m_pPointData->fY, m_pPointData->fZ, SPLINETYPE_FACINGTARGET, m_creature->GetSplineFlags(), 1, NULL, pTrigger->GetGUID()); - } - } + // This was sent with SendMonsterMove - which resulted in better speed than now + 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); } } - sOnyxMove* 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + 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); + } + + bool DidSummonWhelps(const uint32 uiDiff) + { + if (m_uiSummonCount >= MAX_WHELPS_PER_PACK) + return true; - if (m_uiPhase == PHASE_BREATH) + if (m_uiWhelpTimer < uiDiff) { - if (Creature* pTrigger = m_pInstance->instance->GetCreature(m_pInstance->GetOnyxiaTriggerGUID())) - 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; @@ -289,22 +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->AddSplineFlag(SPLINEFLAG_FLYING); - - if (m_pPointData) - m_creature->GetMotionMaster()->MovePoint(m_pPointData->uiLocId, m_pPointData->fX, m_pPointData->fY, m_pPointData->fZ); - + 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; } @@ -315,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->RemoveSplineFlag(SPLINEFLAG_FLYING); - - 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; @@ -365,30 +427,19 @@ 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_WHELP, afSpawnLocations[0][0], afSpawnLocations[0][1], afSpawnLocations[0][2], 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); - m_creature->SummonCreature(NPC_WHELP, afSpawnLocations[1][0], afSpawnLocations[1][1], afSpawnLocations[1][2], 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); - m_uiWhelpTimer = 500; - } - else - m_uiWhelpTimer -= uiDiff; - } - else + if (DidSummonWhelps(uiDiff)) { m_bIsSummoningWhelps = false; m_uiSummonCount = 0; - m_uiSummonWhelpsTimer = 80000; // 90s -10s for summoning + m_uiSummonWhelpsTimer = 80000; // 90s - 10s for summoning } } else @@ -412,8 +463,50 @@ 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) override + { + // Check if players are hit by Onyxia's Deep Breath + if (pTarget->GetTypeId() != TYPEID_PLAYER || !m_pInstance) + return; + + // All and only the Onyxia Deep Breath Spells have these visuals + if (pSpell->GetSpellVisual() == SPELL_VISUAL_BREATH_A || pSpell->GetSpellVisual() == SPELL_VISUAL_BREATH_B) + m_pInstance->SetData(TYPE_ONYXIA, DATA_PLAYER_TOASTED); + } }; CreatureAI* GetAI_boss_onyxia(Creature* pCreature) @@ -424,6 +517,7 @@ CreatureAI* GetAI_boss_onyxia(Creature* pCreature) void AddSC_boss_onyxia() { Script* pNewScript; + pNewScript = new Script; pNewScript->Name = "boss_onyxia"; pNewScript->GetAI = &GetAI_boss_onyxia; diff --git a/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp b/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp index bcb0fde0eb..6ab5a58ad0 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -25,25 +25,68 @@ EndScriptData */ #include "onyxias_lair.h" instance_onyxias_lair::instance_onyxias_lair(Map* pMap) : ScriptedInstance(pMap), - m_uiOnyxTriggerGUID(0) + m_uiAchievWhelpsCount(0) { Initialize(); } void instance_onyxias_lair::Initialize() { + m_uiEncounter = NOT_STARTED; + m_tPhaseTwoStart = time(NULL); +} + +bool instance_onyxias_lair::IsEncounterInProgress() const +{ + return m_uiEncounter == IN_PROGRESS || m_uiEncounter >= DATA_LIFTOFF; } void instance_onyxias_lair::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ONYXIA_TRIGGER: - m_uiOnyxTriggerGUID = pCreature->GetGUID(); + m_mNpcEntryGuidStore[NPC_ONYXIA_TRIGGER] = pCreature->GetObjectGuid(); + break; + case NPC_ONYXIA_WHELP: + if (m_uiEncounter >= DATA_LIFTOFF && time_t(m_tPhaseTwoStart + TIME_LIMIT_MANY_WHELPS) >= time(NULL)) + ++m_uiAchievWhelpsCount; break; } } +void instance_onyxias_lair::SetData(uint32 uiType, uint32 uiData) +{ + if (uiType != TYPE_ONYXIA) + return; + + m_uiEncounter = uiData; + if (uiData == IN_PROGRESS) + { + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_ONYXIA_ID); + m_uiAchievWhelpsCount = 0; + } + if (uiData == DATA_LIFTOFF) + m_tPhaseTwoStart = time(NULL); + + // Currently no reason to save anything +} + +bool instance_onyxias_lair::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_MANY_WHELPS_N: + case ACHIEV_CRIT_MANY_WHELPS_H: + return m_uiAchievWhelpsCount >= ACHIEV_CRIT_REQ_MANY_WHELPS; + case ACHIEV_CRIT_NO_BREATH_N: + case ACHIEV_CRIT_NO_BREATH_H: + return m_uiEncounter != DATA_PLAYER_TOASTED; + default: + return false; + } +} + InstanceData* GetInstanceData_instance_onyxias_lair(Map* pMap) { return new instance_onyxias_lair(pMap); diff --git a/scripts/kalimdor/onyxias_lair/onyxias_lair.h b/scripts/kalimdor/onyxias_lair/onyxias_lair.h index 2751ba33a5..0c44dc8313 100644 --- a/scripts/kalimdor/onyxias_lair/onyxias_lair.h +++ b/scripts/kalimdor/onyxias_lair/onyxias_lair.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,7 +7,25 @@ enum { - NPC_ONYXIA_TRIGGER = 12758 + TYPE_ONYXIA = 0, + + // Special data fields for Onyxia + DATA_LIFTOFF = 4, + DATA_PLAYER_TOASTED = 5, + + NPC_ONYXIA_WHELP = 11262, + NPC_ONYXIA_TRIGGER = 12758, + + // Achievement Related + TIME_LIMIT_MANY_WHELPS = 10, // 10s timeframe to kill 50 whelps after liftoff + ACHIEV_CRIT_REQ_MANY_WHELPS = 50, + + ACHIEV_CRIT_MANY_WHELPS_N = 12565, // Achievements 4403, 4406 + ACHIEV_CRIT_MANY_WHELPS_H = 12568, + ACHIEV_CRIT_NO_BREATH_N = 12566, // Acheivements 4404, 4407 + ACHIEV_CRIT_NO_BREATH_H = 12569, + + ACHIEV_START_ONYXIA_ID = 6601, }; class MANGOS_DLL_DECL instance_onyxias_lair : public ScriptedInstance @@ -16,14 +34,21 @@ class MANGOS_DLL_DECL instance_onyxias_lair : public ScriptedInstance instance_onyxias_lair(Map* pMap); ~instance_onyxias_lair() {} - void Initialize(); + void Initialize() override; + + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; - uint64 GetOnyxiaTriggerGUID() { return m_uiOnyxTriggerGUID; } + void SetData(uint32 uiType, uint32 uiData) override; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; protected: - uint64 m_uiOnyxTriggerGUID; + uint32 m_uiEncounter; + uint32 m_uiAchievWhelpsCount; + + time_t m_tPhaseTwoStart; }; #endif diff --git a/scripts/kalimdor/orgrimmar.cpp b/scripts/kalimdor/orgrimmar.cpp index 557c783398..82481cc1f7 100644 --- a/scripts/kalimdor/orgrimmar.cpp +++ b/scripts/kalimdor/orgrimmar.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,52 +18,18 @@ /* ScriptData SDName: Orgrimmar SD%Complete: 100 -SDComment: Quest support: 2460, 5727, 6566 +SDComment: Quest support: 2460, 6566 SDCategory: Orgrimmar EndScriptData */ /* ContentData -npc_neeru_fireblade npc_text + gossip options text missing npc_shenthul npc_thrall_warchief +boss_voljin EndContentData */ #include "precompiled.h" -/*###### -## npc_neeru_fireblade -######*/ - -#define QUEST_5727 5727 - -bool GossipHello_npc_neeru_fireblade(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(QUEST_5727) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "You may speak frankly, Neeru...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(4513, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_neeru_fireblade(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] ...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(4513, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(QUEST_5727); - break; - } - return true; -} - /*###### ## npc_shenthul ######*/ @@ -76,56 +43,63 @@ struct MANGOS_DLL_DECL npc_shenthulAI : public ScriptedAI { npc_shenthulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool CanTalk; - bool CanEmote; - uint32 Salute_Timer; - uint32 Reset_Timer; - uint64 playerGUID; + uint32 m_uiSaluteTimer; + uint32 m_uiResetTimer; - void Reset() + ObjectGuid m_playerGuid; + + void Reset() override { - CanTalk = false; - CanEmote = false; - Salute_Timer = 6000; - Reset_Timer = 0; - playerGUID = 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) + { + m_playerGuid = pPlayer->GetObjectGuid(); + m_uiSaluteTimer = 6000; + } + + void UpdateAI(const uint32 uiDiff) override { - if (CanEmote) + if (m_uiResetTimer) { - if (Reset_Timer < diff) + if (m_uiResetTimer <= uiDiff) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(playerGUID)) + 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()) @@ -145,11 +119,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->playerGUID = pPlayer->GetGUID(); - } + pShenAI->DoStartQuestEvent(pPlayer); } + return true; } @@ -157,118 +129,165 @@ 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->GetGUID()); + 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->GetGUID()); + 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->SEND_GOSSIP_MENU(5733, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(5734, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(5735, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(5736, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(5737, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(5738, pCreature->GetGUID()); + 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; } +/*###### +## boss_voljin +######*/ + +enum +{ + SPELL_HEX = 16097, + SPELL_SHADOW_SHOCK = 17289, + SPELL_SHADOW_WORD_PAIN = 17146, + SPELL_SHOOT_VOLJIN = 20463, + SPELL_VEIL_OF_SHADOW = 17820, +}; + +struct MANGOS_DLL_DECL boss_voljinAI : public ScriptedAI +{ + boss_voljinAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiHexTimer; + uint32 m_uiShadowShockTimer; + uint32 m_uiShadowWordPainTimer; + uint32 m_uiShootTimer; + uint32 m_uiVeilOfShadowTimer; + + void Reset() + { + m_uiHexTimer = 20000; + m_uiShadowShockTimer = 12000; + m_uiShadowWordPainTimer = 8000; + m_uiShootTimer = 6000; + m_uiVeilOfShadowTimer = 15000; + } + + void UpdateAI(const uint32 uiDiff) override + { + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHexTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_HEX); + m_uiHexTimer = urand(15000, 20000); + } + else + m_uiHexTimer -= uiDiff; + + if (m_uiShadowShockTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SHADOW_SHOCK); + m_uiShadowShockTimer = urand(11000, 14000); + } + else + m_uiShadowShockTimer -= uiDiff; + + if (m_uiShadowWordPainTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(pTarget, SPELL_SHADOW_WORD_PAIN); + m_uiShadowWordPainTimer = 8000; + } + else + m_uiShadowWordPainTimer -= uiDiff; + + if (m_uiShootTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(pTarget, SPELL_SHOOT_VOLJIN); + m_uiShootTimer = urand(6000, 9000); + } + else + m_uiShootTimer -= uiDiff; + + if (m_uiVeilOfShadowTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_VEIL_OF_SHADOW); + m_uiVeilOfShadowTimer = urand(15000, 17000); + } + else + m_uiVeilOfShadowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_voljin(Creature* pCreature) +{ + return new boss_voljinAI(pCreature); +} void AddSC_orgrimmar() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_neeru_fireblade"; - newscript->pGossipHello = &GossipHello_npc_neeru_fireblade; - newscript->pGossipSelect = &GossipSelect_npc_neeru_fireblade; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_shenthul"; - newscript->GetAI = &GetAI_npc_shenthul; - newscript->pQuestAccept = &QuestAccept_npc_shenthul; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_thrall_warchief"; - newscript->GetAI = &GetAI_npc_thrall_warchief; - newscript->pGossipHello = &GossipHello_npc_thrall_warchief; - newscript->pGossipSelect = &GossipSelect_npc_thrall_warchief; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_shenthul"; + pNewScript->GetAI = &GetAI_npc_shenthul; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_shenthul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_thrall_warchief"; + pNewScript->pGossipHello = &GossipHello_npc_thrall_warchief; + pNewScript->pGossipSelect = &GossipSelect_npc_thrall_warchief; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_voljin"; + pNewScript->GetAI = &GetAI_boss_voljin; + 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 56b769b80c..0000000000 --- a/scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (C) 2006 - 2010 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() - { - 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 *newscript; - newscript = new Script; - newscript->Name = "boss_amnennar_the_coldbringer"; - newscript->GetAI = &GetAI_boss_amnennar_the_coldbringer; - newscript->RegisterSelf(); -} diff --git a/scripts/kalimdor/razorfen_downs/boss_tuten_kash.cpp b/scripts/kalimdor/razorfen_downs/boss_tuten_kash.cpp new file mode 100644 index 0000000000..2602c55a68 --- /dev/null +++ b/scripts/kalimdor/razorfen_downs/boss_tuten_kash.cpp @@ -0,0 +1,356 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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: +SD%Complete: +SDComment: Gong event && boss w/minions Support +SDCategory: +EndScriptData */ + +#include "precompiled.h" + +enum +{ +///-> TUTEN'KASH + SPELL_CURSE_OF_TUTEN = 12255, + SPELL_VIRULENT_POISON = 12251, + SPELL_WEB_SPARY = 12252, + NPC_TUTEN = 7355, +///-> END + +///-> TOMB FIEND + SPELL_POISON = 744, + NPC_TOMB_FIEND = 7349, +///-> END + +///-> TOMB REAVER + /// USES VIRULENT POISON + SPELL_WEB = 745, + NPC_TOMB_REAVER = 7351, +///-> END + +///-> STUFF + GO_TUTEN_GONG = 148917, +}; + +enum phase +{ + PHASE_ZERO = 0, ///-> GOgong has been used Once + PHASE_ZEROB = 1, + PHASE_ONE = 2, ///-> GOgong has been used twice + PHASE_ONEB = 3, + PHASE_TWO = 4, ///-> GOgong has been used thrice and final time + PHASE_TWOB = 5, +}; + +///-> phase count holder +uint8 m_uiGongPhase = PHASE_ZERO; + +///-> Death count holder +uint8 m_uiFiendDead; +uint8 m_uiReaverDead; + +/***** +* TUTEN'KASH +*****/ + +struct MANGOS_DLL_DECL boss_tuten_kashAI : public ScriptedAI +{ + boss_tuten_kashAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiCurse_Of_TutenTimer; + uint32 m_uiVirulent_Poison_Timer; + uint32 m_uiWebSpray_Timer; + + void Reset() + { + m_uiCurse_Of_TutenTimer = 10000; + m_uiVirulent_Poison_Timer = 7500; + m_uiWebSpray_Timer = 8500; + } + + void JustDied(Unit* pKiller) override + { + m_uiGongPhase = PHASE_TWOB; + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + m_uiGongPhase = PHASE_ZERO; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCurse_Of_TutenTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CURSE_OF_TUTEN); + m_uiCurse_Of_TutenTimer = 10000; + } + else + m_uiCurse_Of_TutenTimer -= uiDiff; + + if (m_uiVirulent_Poison_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_VIRULENT_POISON); + m_uiVirulent_Poison_Timer = 8000; + } + else + m_uiVirulent_Poison_Timer -= uiDiff; + + if (m_uiWebSpray_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WEB_SPARY); + m_uiWebSpray_Timer = 9000; + } + else + m_uiWebSpray_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_tuten_kash(Creature* pCreature) +{ + return new boss_tuten_kashAI(pCreature); +} + +/***** +* TOMB FIEND +*****/ + +struct MANGOS_DLL_DECL npc_tomb_fiendAI : public ScriptedAI +{ + npc_tomb_fiendAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_uiGongPhase = PHASE_ZEROB; +///-> using this only til when ever find out where exact spawn is + m_creature->SetInCombatWithZone(); + } + + uint32 m_uiPoison_Timer; + + void Reset() + { + m_uiPoison_Timer = 5500; + } + + void JustDied(Unit* pKiller) override + { + if (++m_uiFiendDead == 4) + { + m_uiGongPhase = PHASE_ONE; + } + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + m_uiGongPhase = PHASE_ZERO; + } + + void Aggro(Unit* pWho) + { + std::list lFiends; + GetCreatureListWithEntryInGrid(lFiends, m_creature, NPC_TOMB_FIEND, 90.0f); + if (!lFiends.empty()) + { + for (std::list::iterator iter = lFiends.begin(); iter != lFiends.end(); ++iter) + { + if ((*iter) && (*iter)->isAlive()) + (*iter)->AI()->AttackStart(pWho); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPoison_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISON); + m_uiPoison_Timer = 6000; + } + else + m_uiPoison_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_tomb_fiend(Creature* pCreature) +{ + return new npc_tomb_fiendAI(pCreature); +} + +/***** +* TOMB REAVER +*****/ + +struct MANGOS_DLL_DECL npc_tomb_reaverAI : public ScriptedAI +{ + npc_tomb_reaverAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_uiGongPhase = PHASE_TWOB; +///-> using this only til when ever find out where exact spawn is + m_creature->SetInCombatWithZone(); + } + + uint32 m_uiVirulent_Poison_Timer; + uint32 m_uiWeb_Timer; + + void Reset() + { + m_uiVirulent_Poison_Timer = 6500; + m_uiWeb_Timer = 7500; + } + + void Aggro(Unit* pWho) + { + std::list lReavers; + GetCreatureListWithEntryInGrid(lReavers, m_creature, NPC_TOMB_REAVER, 90.0f); + if (!lReavers.empty()) + { + for (std::list::iterator iter = lReavers.begin(); iter != lReavers.end(); ++iter) + { + if ((*iter) && (*iter)->isAlive()) + (*iter)->AI()->AttackStart(pWho); + } + } + } + + void JustDied(Unit* pKiller) override + { + if (++m_uiReaverDead == 2) + { + m_uiGongPhase = PHASE_TWO; + } + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + m_uiGongPhase = PHASE_ZERO; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiVirulent_Poison_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_VIRULENT_POISON); + m_uiVirulent_Poison_Timer = 7000; + } + else + m_uiVirulent_Poison_Timer -= uiDiff; + + if (m_uiWeb_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WEB); + m_uiWeb_Timer = 6000; + } + else + m_uiWeb_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_tomb_reaver(Creature* pCreature) +{ + return new npc_tomb_reaverAI(pCreature); +} + +/***** +* GOgong +*****/ + + +///->>>> !!!!! LOC AREN"T CORRECT need correct spawn how to !!!!!!!!!!!!! +///-> Fiends spawn +float PositionF1[4] = {2489.91f, 804.795f, 43.251f, 1.658f}; +float PositionF2[4] = {2488.91f, 804.795f, 43.251f, 1.658f}; +float PositionF3[4] = {2487.91f, 804.795f, 43.251f, 1.658f}; +float PositionF4[4] = {2489.91f, 805.795f, 43.251f, 1.658f}; +///-> reavers spawn +float PositionR1[4] = {2486.83f, 802.874f,43.198f, 2.91f}; +float PositionR2[4] = {2489.91f, 804.795f, 43.251f, 1.658f}; +///-> TuT spawn +float PositionTUT[4] = {2485.29f, 816.253f, 43.24f, 1.78f}; + +bool GOUse_go_gong_razor(Player* pPlayer, GameObject* pGo) +{ + switch(m_uiGongPhase) + { + case PHASE_ZERO: ///-> First time clicking + pGo->SummonCreature(NPC_TOMB_FIEND, PositionF1[0], PositionF1[1], PositionF1[2], PositionF1[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + pGo->SummonCreature(NPC_TOMB_FIEND, PositionF2[0], PositionF2[1], PositionF2[2], PositionF2[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + pGo->SummonCreature(NPC_TOMB_FIEND, PositionF3[0], PositionF3[1], PositionF3[2], PositionF3[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + pGo->SummonCreature(NPC_TOMB_FIEND, PositionF4[0], PositionF4[1], PositionF4[2], PositionF4[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + break; +///-> empty case to keep players from multi summon the wave they are on 8P damn cheaters + case PHASE_ZEROB: + break; + case PHASE_ONE: + pGo->SummonCreature(NPC_TOMB_REAVER, PositionR1[0], PositionR1[1], PositionR1[2], PositionR1[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + pGo->SummonCreature(NPC_TOMB_REAVER, PositionR2[0], PositionR2[1], PositionR2[2], PositionR2[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + break; + case PHASE_ONEB: + break; + case PHASE_TWO: + pGo->SummonCreature(NPC_TUTEN, PositionTUT[0], PositionTUT[1], PositionTUT[2], PositionTUT[3], TEMPSUMMON_TIMED_OOC_DESPAWN, 10*MINUTE*IN_MILLISECONDS); + break; + case PHASE_TWOB: + break; + } + return true; +} + +void AddSC_boss_tuten_kash() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_tuten_kash"; + pNewScript->GetAI = &GetAI_boss_tuten_kash; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tomb_fiend"; + pNewScript->GetAI = &GetAI_npc_tomb_fiend; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tomb_reaver"; + pNewScript->GetAI = &GetAI_npc_tomb_reaver; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_gong_razor"; + pNewScript->pGOUse = &GOUse_go_gong_razor; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp b/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp index b854a0bf69..d47e63dad1 100644 --- a/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp +++ b/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,57 +17,271 @@ /* ScriptData SDName: Razorfen_Downs SD%Complete: 100 -SDComment: Support for Henry Stern(2 recipes) +SDComment: Quest 3525 SDCategory: Razorfen Downs EndScriptData */ /* ContentData -npc_henry_stern +npc_belnistrasz EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*### -# npc_henry_stern +# npc_belnistrasz ####*/ enum { - SPELL_GOLDTHORN_TEA = 13028, - SPELL_TEACHING_GOLDTHORN_TEA = 13029, - SPELL_MIGHT_TROLLS_BLOOD_POTION = 3451, - SPELL_TEACHING_MIGHTY_TROLLS_BLOOD_POTION = 13030, - GOSSIP_TEXT_TEA_ANSWER = 2114, - GOSSIP_TEXT_POTION_ANSWER = 2115, + QUEST_EXTINGUISHING_THE_IDOL = 3525, + + SAY_BELNISTRASZ_READY = -1129005, + SAY_BELNISTRASZ_START_RIT = -1129006, + SAY_BELNISTRASZ_AGGRO_1 = -1129007, + SAY_BELNISTRASZ_AGGRO_2 = -1129008, + SAY_BELNISTRASZ_3_MIN = -1129009, + SAY_BELNISTRASZ_2_MIN = -1129010, + SAY_BELNISTRASZ_1_MIN = -1129011, + SAY_BELNISTRASZ_FINISH = -1129012, + + NPC_IDOL_ROOM_SPAWNER = 8611, + + NPC_WITHERED_BATTLE_BOAR = 7333, + NPC_WITHERED_QUILGUARD = 7329, + NPC_DEATHS_HEAD_GEOMANCER = 7335, + NPC_PLAGUEMAW_THE_ROTTING = 7356, + + GO_BELNISTRASZ_BRAZIER = 152097, + + SPELL_ARCANE_INTELLECT = 13326, // use this somewhere (he has it as default) + SPELL_FIREBALL = 9053, + SPELL_FROST_NOVA = 11831, + 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 }; -#define GOSSIP_ITEM_TEA "Teach me the cooking recipe" -#define GOSSIP_ITEM_POTION "Teach me the alchemy recipe" +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} +}; -bool GossipHello_npc_henry_stern (Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI { - if (pPlayer->GetBaseSkillValue(SKILL_COOKING) >= 175 && !pPlayer->HasSpell(SPELL_GOLDTHORN_TEA)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TEA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + npc_belnistraszAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_uiRitualPhase = 0; + m_uiRitualTimer = 1000; + m_bAggro = false; + Reset(); + } - if (pPlayer->GetBaseSkillValue(SKILL_ALCHEMY) >= 180 && !pPlayer->HasSpell(SPELL_MIGHT_TROLLS_BLOOD_POTION)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_POTION, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + uint8 m_uiRitualPhase; + uint32 m_uiRitualTimer; + bool m_bAggro; - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + uint32 m_uiFireballTimer; + uint32 m_uiFrostNovaTimer; -bool GossipSelect_npc_henry_stern (Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + void Reset() + { + m_uiFireballTimer = 1000; + m_uiFrostNovaTimer = 6000; + } + + 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); + m_bAggro = true; + } + + return; + } + + ScriptedAI::AttackedBy(pAttacker); + } + + void SpawnerSummon(Creature* pSummoner) + { + if (m_uiRitualPhase > 7) + { + 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) + { + uint32 uiEntry = 0; + + // ref TARGET_RANDOM_CIRCUMFERENCE_POINT + float angle = 2.0f * M_PI_F * rand_norm_f(); + float fX, fZ, fY; + pSummoner->GetClosePoint(fX, fZ, fY, 0.0f, 2.0f, angle); + + switch (i) + { + case 0: + case 1: + uiEntry = NPC_WITHERED_BATTLE_BOAR; + break; + case 2: + uiEntry = NPC_WITHERED_QUILGUARD; + break; + case 3: + uiEntry = NPC_DEATHS_HEAD_GEOMANCER; + break; + } + + pSummoner->SummonCreature(uiEntry, fX, fZ, fY, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + } + } + + void JustSummoned(Creature* pSummoned) override { - pCreature->CastSpell(pPlayer, SPELL_TEACHING_GOLDTHORN_TEA, true); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_TEA_ANSWER, pCreature->GetGUID()); + SpawnerSummon(pSummoned); } - if (uiAction == GOSSIP_ACTION_INFO_DEF + 2) + void DoSummonSpawner(int32 iType) + { + 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) override + { + if (uiPointId == 24) + { + DoScriptText(SAY_BELNISTRASZ_START_RIT, m_creature); + SetEscortPaused(true); + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (HasEscortState(STATE_ESCORT_PAUSED)) + { + if (m_uiRitualTimer < uiDiff) + { + switch (m_uiRitualPhase) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_IDOL_SHUTDOWN); + m_uiRitualTimer = 1000; + break; + case 1: + DoSummonSpawner(irand(1, 3)); + m_uiRitualTimer = 39000; + break; + case 2: + DoSummonSpawner(irand(1, 3)); + m_uiRitualTimer = 20000; + break; + case 3: + DoScriptText(SAY_BELNISTRASZ_3_MIN, m_creature, m_creature); + m_uiRitualTimer = 20000; + break; + case 4: + DoSummonSpawner(irand(1, 3)); + m_uiRitualTimer = 40000; + break; + case 5: + DoSummonSpawner(irand(1, 3)); + DoScriptText(SAY_BELNISTRASZ_2_MIN, m_creature, m_creature); + m_uiRitualTimer = 40000; + break; + case 6: + DoSummonSpawner(irand(1, 3)); + m_uiRitualTimer = 20000; + break; + case 7: + DoScriptText(SAY_BELNISTRASZ_1_MIN, m_creature, m_creature); + m_uiRitualTimer = 40000; + break; + case 8: + DoSummonSpawner(irand(1, 3)); + m_uiRitualTimer = 20000; + break; + case 9: + DoScriptText(SAY_BELNISTRASZ_FINISH, m_creature, m_creature); + m_uiRitualTimer = 3000; + break; + case 10: + { + if (Player* pPlayer = GetPlayerForEscort()) + { + pPlayer->GroupEventHappens(QUEST_EXTINGUISHING_THE_IDOL, m_creature); + + if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_BELNISTRASZ_BRAZIER, 10.0f)) + { + if (!pGo->isSpawned()) + { + pGo->SetRespawnTime(HOUR * IN_MILLISECONDS); + pGo->Refresh(); + } + } + } + + m_creature->RemoveAurasDueToSpell(SPELL_IDOL_SHUTDOWN); + SetEscortPaused(false); + break; + } + } + + ++m_uiRitualPhase; + } + else + m_uiRitualTimer -= uiDiff; + + return; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiFireballTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL); + m_uiFireballTimer = urand(2000, 3000); + } + else + m_uiFireballTimer -= uiDiff; + + if (m_uiFrostNovaTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_NOVA); + m_uiFrostNovaTimer = urand(10000, 15000); + } + else + m_uiFrostNovaTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_belnistrasz(Creature* pCreature) +{ + return new npc_belnistraszAI(pCreature); +} + +bool QuestAccept_npc_belnistrasz(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_EXTINGUISHING_THE_IDOL) { - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_POTION_ANSWER, pCreature->GetGUID()); - pCreature->CastSpell(pPlayer, SPELL_TEACHING_MIGHTY_TROLLS_BLOOD_POTION, true); + if (npc_belnistraszAI* pEscortAI = dynamic_cast(pCreature->AI())) + { + pEscortAI->Start(true, pPlayer, pQuest); + DoScriptText(SAY_BELNISTRASZ_READY, pCreature, pPlayer); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + } } return true; @@ -75,11 +289,11 @@ bool GossipSelect_npc_henry_stern (Player* pPlayer, Creature* pCreature, uint32 void AddSC_razorfen_downs() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_henry_stern"; - newscript->pGossipHello = &GossipHello_npc_henry_stern; - newscript->pGossipSelect = &GossipSelect_npc_henry_stern; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_belnistrasz"; + pNewScript->GetAI = &GetAI_npc_belnistrasz; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_belnistrasz; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp b/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp index 1cf6d3c714..94197ba787 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -25,7 +25,6 @@ EndScriptData */ #include "razorfen_kraul.h" instance_razorfen_kraul::instance_razorfen_kraul(Map* pMap) : ScriptedInstance(pMap), - m_uiAgathelosWardGUID(0), m_uiWardKeepersRemaining(0) { Initialize(); @@ -38,20 +37,19 @@ void instance_razorfen_kraul::Initialize() void instance_razorfen_kraul::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_AGATHELOS_WARD: - m_uiAgathelosWardGUID = pGo->GetGUID(); + m_mGoEntryGuidStore[GO_AGATHELOS_WARD] = pGo->GetObjectGuid(); if (m_auiEncounter[0] == DONE) - DoUseDoorOrButton(m_uiAgathelosWardGUID); + 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; @@ -61,14 +59,14 @@ 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; if (!m_uiWardKeepersRemaining) { m_auiEncounter[0] = uiData; - DoUseDoorOrButton(m_uiAgathelosWardGUID); + DoUseDoorOrButton(GO_AGATHELOS_WARD); } break; } @@ -80,7 +78,7 @@ void instance_razorfen_kraul::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -100,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; @@ -109,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]; @@ -126,9 +124,10 @@ InstanceData* GetInstanceData_instance_razorfen_kraul(Map* pMap) void AddSC_instance_razorfen_kraul() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_razorfen_kraul"; - newscript->GetInstanceData = &GetInstanceData_instance_razorfen_kraul; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_razorfen_kraul"; + pNewScript->GetInstanceData = &GetInstanceData_instance_razorfen_kraul; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp new file mode 100644 index 0000000000..47b9a79e09 --- /dev/null +++ b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp @@ -0,0 +1,270 @@ +/* Copyright (C) 2006 - 2013 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: Razorfen_Kraul +SD%Complete: 100 +SDComment: Quest support: 1144, 1221 +SDCategory: Razorfen Kraul +EndScriptData */ + +/* ContentData +quest_willix_the_importer +EndContentData */ + +#include "precompiled.h" +#include "escort_ai.h" +#include "pet_ai.h" + +/*###### +## npc_willix_the_importer +######*/ + +enum +{ + QUEST_WILLIX_THE_IMPORTER = 1144, + + SAY_WILLIX_READY = -1047000, + SAY_WILLIX_1 = -1047001, + SAY_WILLIX_2 = -1047002, + SAY_WILLIX_3 = -1047003, + SAY_WILLIX_4 = -1047004, + SAY_WILLIX_5 = -1047005, + SAY_WILLIX_6 = -1047006, + SAY_WILLIX_7 = -1047007, + SAY_WILLIX_END = -1047008, + + SAY_WILLIX_AGGRO_1 = -1047009, + SAY_WILLIX_AGGRO_2 = -1047010, + SAY_WILLIX_AGGRO_3 = -1047011, + SAY_WILLIX_AGGRO_4 = -1047012, + + NPC_RAGING_AGAMAR = 4514 +}; + +static const float aBoarSpawn[4][3] = +{ + {2151.420f, 1733.18f, 52.10f}, + {2144.463f, 1726.89f, 51.93f}, + {1956.433f, 1597.97f, 81.75f}, + {1958.971f, 1599.01f, 81.44f} +}; + +struct MANGOS_DLL_DECL npc_willix_the_importerAI : public npc_escortAI +{ + npc_willix_the_importerAI(Creature* m_creature) : npc_escortAI(m_creature) { Reset(); } + + void Reset() {} + + // 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) override + { + 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; + case 2: DoScriptText(SAY_WILLIX_AGGRO_3, m_creature, pWho); break; + case 3: DoScriptText(SAY_WILLIX_AGGRO_4, m_creature, pWho); break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->AI()->AttackStart(m_creature); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + DoScriptText(SAY_WILLIX_1, m_creature); + break; + case 6: + DoScriptText(SAY_WILLIX_2, m_creature); + break; + case 9: + DoScriptText(SAY_WILLIX_3, m_creature); + break; + 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_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); + break; + case 33: + DoScriptText(SAY_WILLIX_6, m_creature); + break; + 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_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); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + // Complete event + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_WILLIX_THE_IMPORTER, m_creature); + SetEscortPaused(true); + break; + } + } +}; + +CreatureAI* GetAI_npc_willix_the_importer(Creature* pCreature) +{ + return new npc_willix_the_importerAI(pCreature); +} + +bool QuestAccept_npc_willix_the_importer(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_WILLIX_THE_IMPORTER) + { + if (npc_willix_the_importerAI* pEscortAI = dynamic_cast(pCreature->AI())) + { + // After 4.0.1 set run = true + pEscortAI->Start(false, pPlayer, pQuest); + DoScriptText(SAY_WILLIX_READY, pCreature, pPlayer); + 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 MANGOS_DLL_DECL npc_snufflenose_gopherAI : public ScriptedPetAI +{ + npc_snufflenose_gopherAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + bool m_bIsMovementActive; + + ObjectGuid m_targetTubberGuid; + + void Reset() + { + 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() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_willix_the_importer"; + 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 a38b4d307f..c7c946f66c 100644 --- a/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h +++ b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -12,7 +12,7 @@ enum TYPE_AGATHELOS = 1, GO_AGATHELOS_WARD = 21099, - + NPC_WARD_KEEPER = 4625 }; @@ -22,22 +22,21 @@ class MANGOS_DLL_DECL instance_razorfen_kraul : public ScriptedInstance 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 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]; - std::string strInstData; + std::string m_strInstData; - uint64 m_uiAgathelosWardGUID; uint8 m_uiWardKeepersRemaining; }; #endif diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp index b074a7978a..0aac4d32e4 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,27 +16,43 @@ /* ScriptData SDName: Boss_Ayamiss -SD%Complete: 50 -SDComment: VERIFY SCRIPT +SD%Complete: 80 +SDComment: Timers and summon coords need adjustments SDCategory: Ruins of Ahn'Qiraj EndScriptData */ #include "precompiled.h" - -/* -To do: -make him fly from 70-100% -*/ +#include "ruins_of_ahnqiraj.h" enum { - SPELL_STINGERSPRAY = 25749, - SPELL_POISONSTINGER = 25748, //only used in phase1 - SPELL_SUMMONSWARMER = 25844, //might be 25708 - //SPELL_PARALYZE 23414 doesnt work correct (core) + 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_PARALYZE = 25725, + SPELL_LASH = 25852, + SPELL_FRENZY = 8269, + SPELL_TRASH = 3391, + + SPELL_FEED = 25721, // cast by the Larva when reaches the player on the altar + + NPC_LARVA = 15555, + NPC_SWARMER = 15546, + NPC_HORNET = 15934, + + PHASE_AIR = 0, + PHASE_GROUND = 1 +}; - PHASE_AIR = 0, - PHASE_GROUND = 1 +// Spawn locations +static const EVENTLOCATION 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 }; struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI @@ -46,74 +62,262 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI uint32 m_uiStingerSprayTimer; uint32 m_uiPoisonStingerTimer; uint32 m_uiSummonSwarmerTimer; + uint32 m_uiSwarmerAttackTimer; + uint32 m_uiParalyzeTimer; + uint32 m_uiLashTimer; + uint32 m_uiTrashTimer; uint8 m_uiPhase; + bool m_bHasFrenzy; + + ObjectGuid m_paralyzeTarget; + GuidList m_lSwarmersGuidList; + void Reset() { - m_uiStingerSprayTimer = 30000; - m_uiPoisonStingerTimer = 30000; - m_uiSummonSwarmerTimer = 60000; - + m_uiStingerSprayTimer = urand(20000, 30000); + m_uiPoisonStingerTimer = 5000; + m_uiSummonSwarmerTimer = 5000; + m_uiSwarmerAttackTimer = 60000; + m_uiParalyzeTimer = 15000; + m_uiLashTimer = urand(5000, 8000); + m_uiTrashTimer = urand(3000, 6000); + + m_bHasFrenzy = false; + m_uiPhase = PHASE_AIR; + SetCombatMovement(false); + } + + 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) override + { + // store the swarmers for a future attack + if (pSummoned->GetEntry() == NPC_SWARMER) + m_lSwarmersGuidList.push_back(pSummoned->GetObjectGuid()); + // move the larva to paralyze target position + else if (pSummoned->GetEntry() == NPC_LARVA) + { + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, aAyamissSpawnLocs[3].m_fX, aAyamissSpawnLocs[3].m_fY, aAyamissSpawnLocs[3].m_fZ); + } + else if (pSummoned->GetEntry() == NPC_HORNET) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 /*uiMotionType*/, uint32 uiPointId) override + { + if (uiPointId != 1 || pSummoned->GetEntry() != NPC_LARVA) + return; + + // Cast feed on target + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_paralyzeTarget)) + 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; + if (!m_bHasFrenzy && m_creature->GetHealthPercent() < 20.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); + m_bHasFrenzy = true; + } + } + // Stinger Spray if (m_uiStingerSprayTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_STINGERSPRAY); - m_uiStingerSprayTimer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_STINGER_SPRAY) == CAST_OK) + m_uiStingerSprayTimer = urand(15000, 20000); } else m_uiStingerSprayTimer -= uiDiff; - + + // Paralyze + if (m_uiParalyzeTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_PARALYZE, SELECT_FLAG_PLAYER); + if (!pTarget) + pTarget = m_creature->getVictim(); + + if (DoCastSpellIfCan(pTarget, SPELL_PARALYZE) == CAST_OK) + { + m_paralyzeTarget = pTarget->GetObjectGuid(); + m_uiParalyzeTimer = 15000; + + // 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_OOC_OR_CORPSE_DESPAWN, 30000); + } + } + else + m_uiParalyzeTimer -= uiDiff; + + // Summon Swarmer + if (m_uiSummonSwarmerTimer < uiDiff) + { + // The spell which summons these guys was removed in 2.0.1 -> therefore we need to summon them manually at a random location around the area + // The summon locations is guesswork - the real location is supposed to be handled by world triggers + // There should be about 24 swarmers per min + float fX, fY, fZ; + for (uint8 i = 0; i < 2; ++i) + { + m_creature->GetRandomPoint(aAyamissSpawnLocs[2].m_fX, aAyamissSpawnLocs[2].m_fY, aAyamissSpawnLocs[2].m_fZ, 80.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_SWARMER, fX, fY, aAyamissSpawnLocs[2].m_fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + m_uiSummonSwarmerTimer = 5000; + } + else + m_uiSummonSwarmerTimer -= uiDiff; + + // 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) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pTemp->AI()->AttackStart(pTarget); + } + } + m_lSwarmersGuidList.clear(); + m_uiSwarmerAttackTimer = 60000; + } + else + m_uiSwarmerAttackTimer -= uiDiff; + if (m_uiPhase == PHASE_AIR) { // Start ground phase at 70% of HP if (m_creature->GetHealthPercent() <= 70.0f) { m_uiPhase = PHASE_GROUND; + SetCombatMovement(true); + m_creature->SetLevitate(false); DoResetThreat(); + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } // Poison Stinger if (m_uiPoisonStingerTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISONSTINGER); - m_uiPoisonStingerTimer = 30000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISON_STINGER) == CAST_OK) + m_uiPoisonStingerTimer = urand(2000, 3000); } else m_uiPoisonStingerTimer -= uiDiff; } else { - //m_uiSummonSwarmerTimer - if (m_uiSummonSwarmerTimer < uiDiff) + if (m_uiLashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_LASH) == CAST_OK) + m_uiLashTimer = urand(8000, 15000); + } + else + m_uiLashTimer -= uiDiff; + + if (m_uiTrashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUMMONSWARMER); - m_uiSummonSwarmerTimer = 60000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiTrashTimer = urand(5000, 7000); } else - m_uiSummonSwarmerTimer -= uiDiff; + m_uiTrashTimer -= uiDiff; DoMeleeAttackIfReady(); } } }; + CreatureAI* GetAI_boss_ayamiss(Creature* pCreature) { return new boss_ayamissAI(pCreature); } +struct MANGOS_DLL_DECL npc_hive_zara_larvaAI : public ScriptedAI +{ + npc_hive_zara_larvaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ruins_of_ahnqiraj*)m_creature->GetInstanceData(); + Reset(); + } + + instance_ruins_of_ahnqiraj* m_pInstance; + + void Reset() { } + + void AttackStart(Unit* pWho) override + { + // don't attack anything during the Ayamiss encounter + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_AYAMISS) == IN_PROGRESS) + return; + } + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // don't attack anything during the Ayamiss encounter + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_AYAMISS) == IN_PROGRESS) + return; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_AYAMISS) == IN_PROGRESS) + return; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_hive_zara_larva(Creature* pCreature) +{ + return new npc_hive_zara_larvaAI(pCreature); +} + void AddSC_boss_ayamiss() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_ayamiss"; - newscript->GetAI = &GetAI_boss_ayamiss; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ayamiss"; + pNewScript->GetAI = &GetAI_boss_ayamiss; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_hive_zara_larva"; + pNewScript->GetAI = &GetAI_npc_hive_zara_larva; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp index 2eddb5e49d..a5f163957e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,11 +16,231 @@ /* ScriptData SDName: Boss_Buru -SD%Complete: 0 -SDComment: Place Holder +SD%Complete: 70 +SDComment: Timers; Kill eggs on transform NYI; Egg explode damage and Buru stun are missing SDCategory: Ruins of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "ruins_of_ahnqiraj.h" -#define EMOTE_TARGET -1509002 +enum +{ + EMOTE_TARGET = -1509002, + + // boss spells + SPELL_CREEPING_PLAGUE = 20512, + SPELL_DISMEMBER = 96, + SPELL_GATHERING_SPEED = 1834, + SPELL_FULL_SPEED = 1557, + SPELL_THORNS = 25640, + SPELL_BURU_TRANSFORM = 24721, + + // egg spells + SPELL_SUMMON_HATCHLING = 1881, + SPELL_EXPLODE = 19593, + SPELL_BURU_EGG_TRIGGER = 26646, + + // npcs + NPC_BURU_EGG_TRIGGER = 15964, + NPC_BURU_EGG = 15514, + NPC_HATCHLING = 15521, + + PHASE_EGG = 1, + PHASE_TRANSFORM = 2, +}; + +struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI +{ + boss_buruAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint8 m_uiPhase; + uint32 m_uiDismemberTimer; + uint32 m_uiCreepingPlagueTimer; + uint32 m_uiGatheringSpeedTimer; + uint32 m_uiFullSpeedTimer; + + void Reset() + { + m_uiDismemberTimer = 5000; + m_uiGatheringSpeedTimer = 9000; + m_uiCreepingPlagueTimer = 0; + m_uiFullSpeedTimer = 60000; + m_uiPhase = PHASE_EGG; + } + + void Aggro(Unit* pWho) override + { + DoScriptText(EMOTE_TARGET, m_creature, pWho); + DoCastSpellIfCan(m_creature, SPELL_THORNS); + m_creature->FixateTarget(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + // Attack a new random target when a player is killed + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoAttackNewTarget(); + } + + // Wrapper to attack a new target and remove the speed gathering buff + void DoAttackNewTarget() + { + if (m_uiPhase == PHASE_TRANSFORM) + return; + + m_creature->RemoveAurasDueToSpell(SPELL_FULL_SPEED); + m_creature->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + { + m_creature->FixateTarget(pTarget); + DoScriptText(EMOTE_TARGET, m_creature, pTarget); + } + + m_uiFullSpeedTimer = 60000; + m_uiGatheringSpeedTimer = 9000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_EGG: + + if (m_uiDismemberTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISMEMBER) == CAST_OK) + m_uiDismemberTimer = 5000; + } + else + m_uiDismemberTimer -= uiDiff; + + if (m_uiFullSpeedTimer) + { + if (m_uiGatheringSpeedTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GATHERING_SPEED) == CAST_OK) + m_uiGatheringSpeedTimer = 9000; + } + else + m_uiGatheringSpeedTimer -= uiDiff; + + if (m_uiFullSpeedTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FULL_SPEED) == CAST_OK) + m_uiFullSpeedTimer = 0; + } + else + m_uiFullSpeedTimer -= uiDiff; + } + + if (m_creature->GetHealthPercent() < 20.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_BURU_TRANSFORM) == CAST_OK) + { + // 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; + } + } + + break; + case PHASE_TRANSFORM: + + if (m_uiCreepingPlagueTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CREEPING_PLAGUE) == CAST_OK) + m_uiCreepingPlagueTimer = 6000; + } + else + m_uiCreepingPlagueTimer -= uiDiff; + + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_buru(Creature* pCreature) +{ + return new boss_buruAI(pCreature); +} + +struct MANGOS_DLL_DECL npc_buru_eggAI : public Scripted_NoMovementAI +{ + npc_buru_eggAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { } + + void JustSummoned(Creature* pSummoned) override + { + // The purpose of this is unk for the moment + if (pSummoned->GetEntry() == NPC_BURU_EGG_TRIGGER) + pSummoned->CastSpell(pSummoned, SPELL_BURU_EGG_TRIGGER, true); + // The Hatchling should attack a random target + else if (pSummoned->GetEntry() == NPC_HATCHLING) + { + if (m_pInstance) + { + if (Creature* pBuru = m_pInstance->GetSingleCreatureFromStorage(NPC_BURU)) + { + if (Unit* pTarget = pBuru->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + } + } + + void JustDied(Unit* /*pKiller*/) override + { + // Explode and Summon hatchling + DoCastSpellIfCan(m_creature, SPELL_EXPLODE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_HATCHLING, CAST_TRIGGERED, m_creature->GetObjectGuid()); + + // Reset Buru's target - this might have been done by spell, but currently this is unk to us + if (m_pInstance) + { + if (Creature* pBuru = m_pInstance->GetSingleCreatureFromStorage(NPC_BURU)) + { + if (boss_buruAI* pBuruAI = dynamic_cast(pBuru->AI())) + pBuruAI->DoAttackNewTarget(); + } + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_buru_egg(Creature* pCreature) +{ + return new npc_buru_eggAI(pCreature); +} + +void AddSC_boss_buru() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_buru"; + pNewScript->GetAI = &GetAI_boss_buru; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_buru_egg"; + pNewScript->GetAI = &GetAI_npc_buru_egg; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp index e6b65c3e35..b661a37932 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Kurinnaxx -SD%Complete: 100 -SDComment: VERIFY SCRIPT AND SQL +SD%Complete: 90 +SDComment: Summon Player ability NYI SDCategory: Ruins of Ahn'Qiraj EndScriptData */ @@ -25,11 +25,14 @@ EndScriptData */ enum { - SPELL_TRASH = 3391, - SPELL_WIDE_SLASH = 25814, - SPELL_MORTAL_WOUND = 25646, - SPELL_SANDTRAP = 25656, - SPELL_ENRAGE = 28798 + SPELL_TRASH = 3391, + SPELL_WIDE_SLASH = 25814, + SPELL_MORTAL_WOUND = 25646, + SPELL_SANDTRAP = 25648, // summons gameobject 180647 + SPELL_ENRAGE = 26527, + SPELL_SUMMON_PLAYER = 26446, + + GO_SAND_TRAP = 180647, }; struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI @@ -38,17 +41,34 @@ struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI uint32 m_uiMortalWoundTimer; uint32 m_uiSandTrapTimer; + uint32 m_uiTrashTimer; + uint32 m_uiWideSlashTimer; + uint32 m_uiTrapTriggerTimer; bool m_bEnraged; + ObjectGuid m_sandtrapGuid; + void Reset() { m_bEnraged = false; - m_uiMortalWoundTimer = 30000; - m_uiSandTrapTimer = 30000; + m_uiMortalWoundTimer = urand(8000, 10000); + m_uiSandTrapTimer = urand(5000, 10000); + m_uiTrashTimer = urand(1000, 5000); + m_uiWideSlashTimer = urand(10000, 15000); + m_uiTrapTriggerTimer = 0; + } + + void JustSummoned(GameObject* pGo) override + { + if (pGo->GetEntry() == GO_SAND_TRAP) + { + m_uiTrapTriggerTimer = 3000; + m_sandtrapGuid = pGo->GetObjectGuid(); + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -56,15 +76,15 @@ struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI // If we are belowe 30% HP cast enrage if (!m_bEnraged && m_creature->GetHealthPercent() <= 30.0f) { - m_bEnraged = true; - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENRAGE); + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bEnraged = true; } // Mortal Wound if (m_uiMortalWoundTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_WOUND); - m_uiMortalWoundTimer = 30000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_WOUND) == CAST_OK) + m_uiMortalWoundTimer = urand(8000, 10000); } else m_uiMortalWoundTimer -= uiDiff; @@ -72,12 +92,47 @@ struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI // Sand Trap if (m_uiSandTrapTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SANDTRAP); - m_uiSandTrapTimer = 30000; + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); + + pTarget->CastSpell(pTarget, SPELL_SANDTRAP, true, NULL, NULL, m_creature->GetObjectGuid()); + m_uiSandTrapTimer = urand(10000, 15000); } else m_uiSandTrapTimer -= uiDiff; + // Trigger the sand trap in 3 secs after spawn + if (m_uiTrapTriggerTimer) + { + if (m_uiTrapTriggerTimer <= uiDiff) + { + if (GameObject* pTrap = m_creature->GetMap()->GetGameObject(m_sandtrapGuid)) + pTrap->Use(m_creature); + m_uiTrapTriggerTimer = 0; + } + else + m_uiTrapTriggerTimer -= uiDiff; + } + + // Wide Slash + if (m_uiWideSlashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_WIDE_SLASH) == CAST_OK) + m_uiWideSlashTimer = urand(12000, 15000); + } + else + m_uiWideSlashTimer -= uiDiff; + + // Trash + if (m_uiTrashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiTrashTimer = urand(12000, 17000); + } + else + m_uiTrashTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -89,9 +144,10 @@ CreatureAI* GetAI_boss_kurinnaxx(Creature* pCreature) void AddSC_boss_kurinnaxx() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_kurinnaxx"; - newscript->GetAI = &GetAI_boss_kurinnaxx; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_kurinnaxx"; + pNewScript->GetAI = &GetAI_boss_kurinnaxx; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp index 88963cfa35..efa7039e69 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -46,40 +46,40 @@ struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI boss_moamAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint8 m_uiPhase; - - uint32 m_uiTrample_Timer; - uint32 m_uiManaDrain_Timer; - uint32 m_uiCheckoutMana_Timer; - uint32 m_uiSummonManaFiends_Timer; + + uint32 m_uiTrampleTimer; + uint32 m_uiManaDrainTimer; + uint32 m_uiCheckoutManaTimer; + uint32 m_uiSummonManaFiendsTimer; void Reset() { - m_uiTrample_Timer = 9000; - m_uiManaDrain_Timer = 3000; - m_uiSummonManaFiends_Timer = 90000; - m_uiCheckoutMana_Timer = 1500; + m_uiTrampleTimer = 9000; + m_uiManaDrainTimer = 3000; + m_uiSummonManaFiendsTimer = 90000; + m_uiCheckoutManaTimer = 1500; m_uiPhase = PHASE_ATTACKING; m_creature->SetPower(POWER_MANA, 0); 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_uiCheckoutMana_Timer <= uiDiff) + if (m_uiCheckoutManaTimer <= uiDiff) { - m_uiCheckoutMana_Timer = 1500; + m_uiCheckoutManaTimer = 1500; if (m_creature->GetPower(POWER_MANA) * 100 / m_creature->GetMaxPower(POWER_MANA) > 75.0f) { DoCastSpellIfCan(m_creature, SPELL_ENERGIZE); @@ -89,60 +89,43 @@ struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI } } else - m_uiCheckoutMana_Timer -= uiDiff; + m_uiCheckoutManaTimer -= uiDiff; - if (m_uiSummonManaFiends_Timer <= uiDiff) + if (m_uiSummonManaFiendsTimer <= uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUMMON_MANAFIEND_1, CAST_TRIGGERED); DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUMMON_MANAFIEND_2, CAST_TRIGGERED); DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUMMON_MANAFIEND_3, CAST_TRIGGERED); - m_uiSummonManaFiends_Timer = 90000; + m_uiSummonManaFiendsTimer = 90000; } else - m_uiSummonManaFiends_Timer -= uiDiff; + m_uiSummonManaFiendsTimer -= uiDiff; - if (m_uiManaDrain_Timer <= uiDiff) + if (m_uiManaDrainTimer <= uiDiff) { - m_uiManaDrain_Timer = urand(2000, 6000); - // choose random target with mana - std::list lTargets; - ThreatList const& threatlist = m_creature->getThreatManager().getThreatList(); - if (threatlist.empty()) - return; - - for (ThreatList::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_DRAIN_MANA, SELECT_FLAG_POWER_MANA)) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (pUnit && pUnit->isAlive() && pUnit->GetPower(POWER_MANA)) - lTargets.push_back(pUnit); + if (DoCastSpellIfCan(pTarget, SPELL_DRAIN_MANA) == CAST_OK) + m_uiManaDrainTimer = urand(2000, 6000); } - - if (lTargets.empty()) - return; - - std::list::iterator itr = lTargets.begin(); - std::advance(itr, urand(0, lTargets.size()-1)); - - DoCastSpellIfCan(*itr, SPELL_DRAIN_MANA); } else - m_uiManaDrain_Timer -= uiDiff; + m_uiManaDrainTimer -= uiDiff; - if (m_uiTrample_Timer <= uiDiff) + if (m_uiTrampleTimer <= uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRAMPLE); - m_uiTrample_Timer = 15000; + m_uiTrampleTimer = 15000; } else - m_uiTrample_Timer -= uiDiff; + m_uiTrampleTimer -= uiDiff; DoMeleeAttackIfReady(); break; case PHASE_ENERGIZING: - if (m_uiCheckoutMana_Timer <= uiDiff) + if (m_uiCheckoutManaTimer <= uiDiff) { - m_uiCheckoutMana_Timer = 1500; + m_uiCheckoutManaTimer = 1500; if (m_creature->GetPower(POWER_MANA) == m_creature->GetMaxPower(POWER_MANA)) { m_creature->RemoveAurasDueToSpell(SPELL_ENERGIZE); @@ -153,7 +136,7 @@ struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI } } else - m_uiCheckoutMana_Timer -= uiDiff; + m_uiCheckoutManaTimer -= uiDiff; break; } } @@ -166,9 +149,10 @@ CreatureAI* GetAI_boss_moam(Creature* pCreature) void AddSC_boss_moam() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_moam"; - newscript->GetAI = &GetAI_boss_moam; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_moam"; + pNewScript->GetAI = &GetAI_boss_moam; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp index e176b7cc12..3fdd19ec02 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,23 +16,267 @@ /* ScriptData SDName: Boss_Ossirian -SD%Complete: 0 -SDComment: Place holder +SD%Complete: 80% +SDComment: Weather missing SDCategory: Ruins of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "ruins_of_ahnqiraj.h" -#define SAY_SURPREME1 -1509018 -#define SAY_SURPREME2 -1509019 -#define SAY_SURPREME3 -1509020 +enum +{ + SAY_SUPREME_1 = -1509018, + SAY_SUPREME_2 = -1509019, + SAY_SUPREME_3 = -1509020, + SAY_RAND_INTRO_1 = -1509021, + SAY_RAND_INTRO_2 = -1509023, + SAY_RAND_INTRO_3 = -1509024, + SAY_AGGRO = -1509025, + SAY_SLAY = -1509026, + SAY_DEATH = -1509027, -#define SAY_RAND_INTRO1 -1509021 -#define SAY_RAND_INTRO2 -1509022 -#define SAY_RAND_INTRO3 -1509023 -#define SAY_RAND_INTRO4 -1509024 //possibly old? + SPELL_SILENCE = 25195, + SPELL_CYCLONE = 25189, + SPELL_STOMP = 25188, + SPELL_SUPREME = 25176, + SPELL_SUMMON_CRYSTAL = 25192, + SPELL_SAND_STORM = 25160, // tornado spell + SPELL_SUMMON = 20477, // TODO NYI -#define SAY_AGGRO -1509025 + MAX_CRYSTAL_POSITIONS = 1, // TODO -#define SAY_SLAY -1509026 -#define SAY_DEATH -1509027 + SPELL_WEAKNESS_FIRE = 25177, + SPELL_WEAKNESS_FROST = 25178, + SPELL_WEAKNESS_NATURE = 25180, + SPELL_WEAKNESS_ARCANE = 25181, + SPELL_WEAKNESS_SHADOW = 25183, + + NPC_SAND_VORTEX = 15428, // tornado npc +}; + +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 +{ + + boss_ossirianAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ruins_of_ahnqiraj*)m_creature->GetInstanceData(); + m_bSaidIntro = false; + Reset(); + } + + instance_ruins_of_ahnqiraj* m_pInstance; + + uint32 m_uiSupremeTimer; + uint32 m_uiCycloneTimer; + uint32 m_uiStompTimer; + uint32 m_uiSilenceTimer; + uint8 m_uiCrystalPosition; + + bool m_bSaidIntro; + + void Reset() + { + m_uiCrystalPosition = 0; + m_uiCycloneTimer = 20000; + m_uiStompTimer = 30000; + m_uiSilenceTimer = 30000; + m_uiSupremeTimer = 45000; + } + + 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); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(SAY_SLAY, m_creature); + } + + void DoSpawnNextCrystal() + { + if (!m_pInstance) + return; + + Creature* pOssirianTrigger = NULL; + if (m_uiCrystalPosition == 0) + { + // Respawn static spawned crystal trigger + pOssirianTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_OSSIRIAN_TRIGGER); + if (pOssirianTrigger && !pOssirianTrigger->isAlive()) + pOssirianTrigger->Respawn(); + } + 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); + + // Increase position + ++m_uiCrystalPosition %= MAX_CRYSTAL_POSITIONS; + } + + 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 < countof(aWeaknessSpell); ++i) + { + if (pSpell->Id == aWeaknessSpell[i]) + { + bIsWeaknessSpell = true; + break; + } + } + if (!bIsWeaknessSpell) + return; + + m_creature->RemoveAurasDueToSpell(SPELL_SUPREME); + m_uiSupremeTimer = 45000; + + ((Creature*)pCaster)->ForcedDespawn(); + DoSpawnNextCrystal(); + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + // TODO: Range guesswork + if (!m_bSaidIntro && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 75.0f, false)) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_RAND_INTRO_1, m_creature); break; + case 1: DoScriptText(SAY_RAND_INTRO_2, m_creature); break; + case 2: DoScriptText(SAY_RAND_INTRO_3, m_creature); break; + } + m_bSaidIntro = true; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Supreme + if (m_uiSupremeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUPREME, CAST_AURA_NOT_PRESENT) == CAST_OK) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_SUPREME_1, m_creature); break; + case 1: DoScriptText(SAY_SUPREME_2, m_creature); break; + case 2: DoScriptText(SAY_SUPREME_3, m_creature); break; + } + m_uiSupremeTimer = 45000; + } + else + m_uiSupremeTimer = 5000; + } + else + m_uiSupremeTimer -= uiDiff; + + // Stomp + if (m_uiStompTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_STOMP) == CAST_OK) + m_uiStompTimer = 30000; + } + else + m_uiStompTimer -= uiDiff; + + // Cyclone + if (m_uiCycloneTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CYCLONE) == CAST_OK) + m_uiCycloneTimer = 20000; + } + else + m_uiCycloneTimer -= uiDiff; + + // Silence + if (m_uiSilenceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = urand(20000, 30000); + } + else + m_uiSilenceTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ossirian(Creature* pCreature) +{ + return new boss_ossirianAI(pCreature); +} + +// This is actually a hack for a server-side spell +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); + + return true; +} + +void AddSC_boss_ossirian() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ossirian"; + pNewScript->GetAI = &GetAI_boss_ossirian; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_ossirian_crystal"; + pNewScript->pGOUse = &GOUse_go_ossirian_crystal; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp index 3abfe4d427..16274757c9 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 MANGOS_DLL_DECL 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() + { + 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 MANGOS_DLL_DECL 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() + { + 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 6c2ff364ef..e2345bd14e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,179 +17,350 @@ /* 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), + m_uiArmyDelayTimer(0), + m_uiCurrentArmyWave(0) +{ + Initialize(); +} -struct MANGOS_DLL_DECL instance_ruins_of_ahnqiraj : public ScriptedInstance +void instance_ruins_of_ahnqiraj::Initialize() { - instance_ruins_of_ahnqiraj(Map* pMap) : ScriptedInstance(pMap) {Initialize();} + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - std::string strInstData; - uint32 m_auiEncounter[MAX_ENCOUNTER]; +void instance_ruins_of_ahnqiraj::OnPlayerEnter(Player* /*pPlayer*/) +{ + // Spawn andorov if necessary + if (m_auiEncounter[TYPE_KURINNAXX] == DONE) + DoSapwnAndorovIfCan(); +} - uint64 m_uiOssirianGUID; - uint64 m_uiBuruGUID; - uint64 m_uiKurinnaxxGUID; - uint64 m_uiAndorovGUID; - uint64 m_uiRajaxxGUID; - uint64 m_uiQeezGUID; - uint64 m_uiTuubidGUID; - uint64 m_uiDrennGUID; - uint64 m_uiXurremGUID; - uint64 m_uiYeggethGUID; - uint64 m_uiPakkonGUID; - uint64 m_uiZerranGUID; +void instance_ruins_of_ahnqiraj::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_OSSIRIAN_TRIGGER: + // 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; + } +} - void Initialize() +void instance_ruins_of_ahnqiraj::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiOssirianGUID = 0; - m_uiBuruGUID = 0; - m_uiKurinnaxxGUID = 0; - m_uiAndorovGUID = 0; - m_uiQeezGUID = 0; - m_uiTuubidGUID = 0; - m_uiDrennGUID = 0; - m_uiXurremGUID = 0; - m_uiYeggethGUID = 0; - m_uiPakkonGUID = 0; - m_uiZerranGUID = 0; - m_uiRajaxxGUID = 0; + case NPC_KURINNAXX: SetData(TYPE_KURINNAXX, 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; + case NPC_OSSIRIAN: SetData(TYPE_OSSIRIAN, IN_PROGRESS); break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_ruins_of_ahnqiraj::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pCreature->GetEntry()) - { - case NPC_OSSIRIAN: m_uiOssirianGUID = pCreature->GetGUID(); break; - case NPC_BURU: m_uiBuruGUID = pCreature->GetGUID(); break; - case NPC_KURINNAXX: m_uiKurinnaxxGUID = pCreature->GetGUID(); break; - case NPC_GENERAL_ANDOROV: m_uiAndorovGUID = pCreature->GetGUID(); break; - case NPC_CAPTAIN_QEEZ: m_uiQeezGUID = pCreature->GetGUID(); break; - case NPC_CAPTAIN_TUUBID: m_uiTuubidGUID = pCreature->GetGUID(); break; - case NPC_CAPTAIN_DRENN: m_uiDrennGUID = pCreature->GetGUID(); break; - case NPC_CAPTAIN_XURREM: m_uiXurremGUID = pCreature->GetGUID(); break; - case NPC_MAJOR_YEGGETH: m_uiYeggethGUID = pCreature->GetGUID(); break; - case NPC_MAJOR_PAKKON: m_uiPakkonGUID = pCreature->GetGUID(); break; - case NPC_COLONEL_ZERRAN: m_uiZerranGUID = pCreature->GetGUID(); break; - case NPC_RAJAXX: m_uiRajaxxGUID = pCreature->GetGUID(); break; - } + case NPC_KURINNAXX: SetData(TYPE_KURINNAXX, 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; } +} + +void instance_ruins_of_ahnqiraj::OnCreatureDeath(Creature* pCreature) +{ + if (!pCreature) + return; + + ObjectGuid guid = pCreature->GetObjectGuid(); - void OnObjectCreate(GameObject* pGo) + switch (pCreature->GetEntry()) { - switch(pGo->GetEntry()) + case NPC_KURINNAXX: SetData(TYPE_KURINNAXX, DONE); break; + case NPC_RAJAXX: SetData(TYPE_RAJAXX, DONE); break; + case NPC_MOAM: SetData(TYPE_MOAM, DONE); break; + 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: { - case GO_OSSIRIAN_CRYSTAL: pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); break; //to make them unusable temporarily + // If event isn't started by Andorov, return + if (GetData(TYPE_RAJAXX) != IN_PROGRESS) + break; + + bool startNext = false; + { + MAPLOCK_WRITE(pCreature, MAP_LOCK_TYPE_DEFAULT); + GuidSet& army = m_sArmyWavesGuids[m_uiCurrentArmyWave - 1]; + + if (army.empty() || army.find(guid) == army.end()) + break; + + // Check if the dead creature belongs to the current wave + army.erase(guid); + startNext = army.empty(); + } + + // If all the soldiers from the current wave are dead, then send the next one + if (startNext) + DoSendNextArmyWave(); + + break; } + default: + break; } +} - bool IsEncounterInProgress() const +void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; + case TYPE_KURINNAXX: + if (uiData == DONE) + { + DoSapwnAndorovIfCan(); + + // Yell after kurinnaxx + DoOrSimulateScriptTextForThisInstance(SAY_OSSIRIAN_INTRO, NPC_OSSIRIAN); + } + 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: + case TYPE_OSSIRIAN: + 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_auiEncounter[5]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_ruins_of_ahnqiraj::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - return false; + return 0; +} + +void instance_ruins_of_ahnqiraj::DoSapwnAndorovIfCan() +{ + if (GetSingleCreatureFromStorage(NPC_GENERAL_ANDOROV)) + return; + + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + for (uint8 i = 0; i < MAX_HELPERS; ++i) + pPlayer->SummonCreature(aAndorovSpawnLocs[i].m_uiEntry, aAndorovSpawnLocs[i].m_fX, aAndorovSpawnLocs[i].m_fY, aAndorovSpawnLocs[i].m_fZ, aAndorovSpawnLocs[i].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); +} + +void instance_ruins_of_ahnqiraj::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; } - const char* Save() + 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]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - return strInstData.c_str(); + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } - uint64 GetData64(uint32 uiData) + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_ruins_of_ahnqiraj::Update(uint32 uiDiff) +{ + if (GetData(TYPE_RAJAXX) == IN_PROGRESS) { - switch(uiData) + if (m_uiArmyDelayTimer) { - case DATA_OSSIRIAN: return m_uiOssirianGUID; - case DATA_BURU: return m_uiBuruGUID; - case DATA_ANDOROV: return m_uiAndorovGUID; - case DATA_KURINNAXX: return m_uiKurinnaxxGUID; - case DATA_QEEZ: return m_uiQeezGUID; - case DATA_TUUBID: return m_uiTuubidGUID; - case DATA_DRENN: return m_uiDrennGUID; - case DATA_XURREM: return m_uiXurremGUID; - case DATA_YEGGETH: return m_uiYeggethGUID; - case DATA_PAKKON: return m_uiPakkonGUID; - case DATA_ZERRAN: return m_uiZerranGUID; - case DATA_RAJAXX: return m_uiRajaxxGUID; + if (m_uiArmyDelayTimer <= uiDiff) + { + DoSendNextArmyWave(); + m_uiArmyDelayTimer = 2 * MINUTE * IN_MILLISECONDS; + } + else + m_uiArmyDelayTimer -= uiDiff; } - return 0; } +} + +void instance_ruins_of_ahnqiraj::DoSortArmyWaves() +{ + std::list lCreatureList; - void SetData(uint32 uiType, uint32 uiData) + // 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) { - switch(uiType) - { - case TYPE_RAJAXX: - m_auiEncounter[0] = uiData; - break; - case TYPE_KURINNAXX: - m_auiEncounter[1] = uiData; - break; - } + // Clear all the army waves + m_sArmyWavesGuids[i].clear(); + lCreatureList.clear(); - if (uiData == DONE) + if (Creature* pTemp = GetSingleCreatureFromStorage(aArmySortingParameters[i].m_uiEntry)) { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " "; + GetCreatureListWithEntryInGrid(lCreatureList, pTemp, NPC_QIRAJI_WARRIOR, aArmySortingParameters[i].m_fSearchDist); + GetCreatureListWithEntryInGrid(lCreatureList, pTemp, NPC_SWARMGUARD_NEEDLER, aArmySortingParameters[i].m_fSearchDist); - strInstData = saveStream.str(); + for (std::list::const_iterator itr = lCreatureList.begin(); itr != lCreatureList.end(); ++itr) + { + if ((*itr)->isAlive()) + m_sArmyWavesGuids[i].insert((*itr)->GetObjectGuid()); + } - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; + if (pTemp->isAlive()) + m_sArmyWavesGuids[i].insert(pTemp->GetObjectGuid()); } } - void Load(const char* chrIn) + // 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 (!chrIn) + if (Creature* pRajaxx = GetSingleCreatureFromStorage(NPC_RAJAXX)) { - OUT_LOAD_INST_DATA_FAIL; - return; + DoScriptText(SAY_INTRO, pRajaxx); + pRajaxx->SetInCombatWithZone(); } + } + else + { + // Increase the wave id if some are already dead + while (m_sArmyWavesGuids[m_uiCurrentArmyWave].empty()) + ++m_uiCurrentArmyWave; - OUT_LOAD_INST_DATA(chrIn); - - std::istringstream loadStream(chrIn); + float fX, fY, fZ; - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; + // make copy of current guidSet - may be modified in another thread + GuidSet currentWave = m_sArmyWavesGuids[m_uiCurrentArmyWave]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (GuidSet::const_iterator itr = currentWave.begin(); itr != currentWave.end(); ++itr) { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + ObjectGuid guid = *itr; - OUT_LOAD_INST_DATA_COMPLETE; + if (guid.IsEmpty()) + continue; - //spawn andorov on load - if (m_auiEncounter[0] == DONE) - if (Creature* pRajaxx = instance->GetCreature(m_uiRajaxxGUID)) - pRajaxx->SummonCreature(NPC_GENERAL_ANDOROV, -8873.42f, 1647.67f, 21.386f, 5.69141f, TEMPSUMMON_CORPSE_DESPAWN, 0); - } + if (Creature* pTemp = instance->GetCreature(guid)) + { + if (!pTemp->isAlive()) + continue; - uint32 GetData(uint32 uiType) - { - switch(uiType) + 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) { - case TYPE_RAJAXX: - return m_auiEncounter[0]; - case TYPE_KURINNAXX: - return m_auiEncounter[1]; + if (Creature* pRajaxx = GetSingleCreatureFromStorage(NPC_RAJAXX)) + DoScriptText(aArmySortingParameters[m_uiCurrentArmyWave].m_uiYellEntry, pRajaxx); } - return 0; } -}; + + // 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) { @@ -198,9 +369,10 @@ InstanceData* GetInstanceData_instance_ruins_of_ahnqiraj(Map* pMap) void AddSC_instance_ruins_of_ahnqiraj() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_ruins_of_ahnqiraj"; - newscript->GetInstanceData = &GetInstanceData_instance_ruins_of_ahnqiraj; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_ruins_of_ahnqiraj"; + pNewScript->GetInstanceData = &GetInstanceData_instance_ruins_of_ahnqiraj; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp index 51f4d036d5..8ccc395c4c 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -38,7 +38,7 @@ enum SPELL_THUNDER_CLAP = 26554, SPELL_REFLECT_ARFR = 13022, SPELL_REFLECT_FSSH = 19595, - SPELL_ENRAGE = 8559, + SPELL_ENRAGE = 8599, SPELL_EXPLODE = 25698, SPELL_SUMMON_ANUB_SWARMGUARD = 17430, @@ -70,11 +70,11 @@ struct MANGOS_DLL_DECL mob_anubisath_guardianAI : public ScriptedAI void Reset() { - 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; @@ -162,9 +162,10 @@ CreatureAI* GetAI_mob_anubisath_guardian(Creature* pCreature) void AddSC_ruins_of_ahnqiraj() { - Script* newscript; - newscript = new Script; - newscript->Name = "mob_anubisath_guardian"; - newscript->GetAI = &GetAI_mob_anubisath_guardian; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_anubisath_guardian"; + pNewScript->GetAI = &GetAI_mob_anubisath_guardian; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h b/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h index 60dfa9c660..90b53b28ff 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,38 +7,129 @@ enum { - MAX_ENCOUNTER = 2, - - DATA_OSSIRIAN = 1, - DATA_BURU = 2, - DATA_ANDOROV = 3, - DATA_KURINNAXX = 4, - DATA_QEEZ = 5, - DATA_TUUBID = 6, - DATA_DRENN = 7, - DATA_XURREM = 8, - DATA_YEGGETH = 9, - DATA_PAKKON = 10, - DATA_ZERRAN = 11, - DATA_RAJAXX = 12, - - TYPE_RAJAXX = 13, - TYPE_KURINNAXX = 14, - - NPC_OSSIRIAN = 15339, - NPC_BURU = 15370, - NPC_KALDOREI_ELITE = 15473, - NPC_GENERAL_ANDOROV = 15471, - NPC_RAJAXX = 15341, - NPC_KURINNAXX = 15348, - 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, - - GO_OSSIRIAN_CRYSTAL = 180619 + MAX_ENCOUNTER = 6, + MAX_HELPERS = 5, + + TYPE_KURINNAXX = 0, + TYPE_RAJAXX = 1, + TYPE_MOAM = 2, + TYPE_BURU = 3, + TYPE_AYAMISS = 4, + TYPE_OSSIRIAN = 5, + + NPC_KURINNAXX = 15348, + NPC_MOAM = 15340, + NPC_BURU = 15370, + NPC_AYAMISS = 15369, + NPC_OSSIRIAN = 15339, + 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_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 + + // 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 +}; + +// Spawn coords for Andorov and his team +static const SPAWNLOCATION aAndorovSpawnLocs[MAX_HELPERS] = +{ + {NPC_GENERAL_ANDOROV, -8660.4f, 1510.29f, 32.449f, 2.2184f}, + {NPC_KALDOREI_ELITE, -8655.84f, 1509.78f, 32.462f, 2.33341f}, + {NPC_KALDOREI_ELITE, -8657.39f, 1506.28f, 32.418f, 2.33346f}, + {NPC_KALDOREI_ELITE, -8660.96f, 1504.9f, 32.1567f, 2.33306f}, + {NPC_KALDOREI_ELITE, -8664.45f, 1506.44f, 32.0944f, 2.33302f} +}; + +// 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 MANGOS_DLL_DECL instance_ruins_of_ahnqiraj : public ScriptedInstance +{ + public: + instance_ruins_of_ahnqiraj(Map* pMap); + ~instance_ruins_of_ahnqiraj() {} + + void Initialize() override; + + // bool IsEncounterInProgress() const override; // not active in AQ20 + + void OnCreatureCreate(Creature* pCreature) override; + void OnPlayerEnter(Player* pPlayer) override; + + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void GetKaldoreiGuidList(GuidList& lList) { lList = m_lKaldoreiGuidList; } + + 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 4c36854c77..99f763dcd2 100644 --- a/scripts/kalimdor/silithus.cpp +++ b/scripts/kalimdor/silithus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,236 +17,662 @@ /* ScriptData SDName: Silithus SD%Complete: 100 -SDComment: Quest support: 7785, 8304. +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 +## npc_anachronos_the_ancient ###*/ -#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 + // Dragons + NPC_MERITHRA_OF_THE_DREAM = 15378, + NPC_CAELESTRASZ = 15379, + NPC_ARYGOS = 15380, + NPC_ANACHRONOS_THE_ANCIENT = 15381, + NPC_ANACHRONOS_QUEST_TRIGGER = 15454, // marks some movement for the dragons + + // Elfs + NPC_FANDRAL_STAGHELM = 15382, + NPC_KALDOREI_INFANTRY = 15423, + + // Qiraji warriors + NPC_QIRAJI_WASP = 15414, + NPC_QIRAJI_DRONE = 15421, + NPC_QIRAJI_TANK = 15422, + NPC_ANUBISATH_CONQUEROR = 15424, + + QUEST_A_PAWN_ON_THE_ETERNAL_BOARD = 8519, + + // Yells -> in chronological order + SAY_ANACHRONOS_INTRO_1 = -1000740, + SAY_FANDRAL_INTRO_2 = -1000741, + SAY_MERITHRA_INTRO_3 = -1000742, + EMOTE_ARYGOS_NOD = -1000743, + SAY_CAELESTRASZ_INTRO_4 = -1000744, + EMOTE_MERITHRA_GLANCE = -1000745, + SAY_MERITHRA_INTRO_5 = -1000746, + + SAY_MERITHRA_ATTACK_1 = -1000747, + SAY_ARYGOS_ATTACK_2 = -1000748, + SAY_ARYGOS_ATTACK_3 = -1000749, + SAY_CAELESTRASZ_ATTACK_4 = -1000750, + SAY_CAELESTRASZ_ATTACK_5 = -1000751, + + SAY_ANACHRONOS_SEAL_1 = -1000752, + SAY_FANDRAL_SEAL_2 = -1000753, + SAY_ANACHRONOS_SEAL_3 = -1000754, + SAY_ANACHRONOS_SEAL_4 = -1000755, + SAY_ANACHRONOS_SEAL_5 = -1000756, + SAY_FANDRAL_SEAL_6 = -1000757, + + EMOTE_FANDRAL_EXHAUSTED = -1000758, + SAY_ANACHRONOS_EPILOGUE_1 = -1000759, + SAY_ANACHRONOS_EPILOGUE_2 = -1000760, + SAY_ANACHRONOS_EPILOGUE_3 = -1000761, + EMOTE_ANACHRONOS_SCEPTER = -1000762, + SAY_FANDRAL_EPILOGUE_4 = -1000763, + SAY_FANDRAL_EPILOGUE_5 = -1000764, + EMOTE_FANDRAL_SHATTER = -1000765, + SAY_ANACHRONOS_EPILOGUE_6 = -1000766, + SAY_FANDRAL_EPILOGUE_7 = -1000767, + EMOTE_ANACHRONOS_DISPPOINTED = -1000768, + EMOTE_ANACHRONOS_PICKUP = -1000769, + SAY_ANACHRONOS_EPILOGUE_8 = -1000770, + + // The transform spell for Anachronos was removed from DBC + DISPLAY_ID_BRONZE_DRAGON = 15500, + + // Spells + 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_MERITHRA_WAKE = 25145, // should trigger 25172 on targets + SPELL_ARYGOS_VENGEANCE = 25149, + SPELL_CAELESTRASZ_MOLTEN_RAIN = 25150, + + SPELL_TIME_STOP = 25158, // Anachronos stops the battle - should trigger 25171 + SPELL_GLYPH_OF_WARDING = 25166, // Sends event 9427 - should activate Go 176148 + SPELL_PRISMATIC_BARRIER = 25159, // Sends event 9425 - should activate Go 176146 + SPELL_CALL_ANCIENTS = 25167, // Sends event 9426 - should activate Go 176147 + SPELL_SHATTER_HAMMER = 25182, // Breakes the scepter - needs DB coords + + POINT_ID_DRAGON_ATTACK = 1, + POINT_ID_EXIT = 2, + POINT_ID_GATE = 3, + POINT_ID_SCEPTER_1 = 4, + POINT_ID_SCEPTER_2 = 5, + POINT_ID_EPILOGUE = 6, + DATA_HANDLE_SCEPTER = 7, // dummy members - used in dialogue helper + DATA_MERITHRA_ATTACK = 8, + DATA_CAELASTRASZ_ATTACK = 9, + + MAX_DRAGONS = 4, + MAX_CONQUERORS = 3, + MAX_QIRAJI = 6, + MAX_KALDOREI = 20, }; -bool GossipHello_npc_highlord_demitrian(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); +/* Known event issues: + * The Kaldorei and Qiraji soldiers don't have the correct flags and factions in DB + * The Ahn'Qiraj gate gameobjects are missing from DB + * The spells used by the dragons upon the Qiraji need core support + * The script events sent by the spells which close the AQ gate needs DB support + * Can't make Fandral equip the Scepter when Anachronos handles it to him + */ - 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); +static const DialogueEntry aEventDialogue[] = +{ + {NPC_ANACHRONOS_THE_ANCIENT, 0, 2000}, // summon the dragons + {SAY_ANACHRONOS_INTRO_1, NPC_ANACHRONOS_THE_ANCIENT, 3000}, + {EMOTE_ONESHOT_SHOUT, NPC_ANACHRONOS_THE_ANCIENT, 3000}, // make Anachronos shout and summon the warriors + {SAY_FANDRAL_INTRO_2, NPC_FANDRAL_STAGHELM, 6000}, + {EMOTE_MERITHRA_GLANCE, NPC_MERITHRA_OF_THE_DREAM, 2000}, + {SAY_MERITHRA_INTRO_3, NPC_MERITHRA_OF_THE_DREAM, 3000}, + {EMOTE_ARYGOS_NOD, NPC_ARYGOS, 4000}, + {SAY_CAELESTRASZ_INTRO_4, NPC_CAELESTRASZ, 9000}, + {SAY_MERITHRA_INTRO_5, NPC_MERITHRA_OF_THE_DREAM, 5000}, + {NPC_ANACHRONOS_QUEST_TRIGGER, 0, 0}, // send Merithra to fight + {DATA_MERITHRA_ATTACK, 0, 5000}, // make Merithra wait + {SAY_MERITHRA_ATTACK_1, NPC_MERITHRA_OF_THE_DREAM, 1000}, + {SPELL_GREEN_DRAGON_TRANSFORM, 0, 6000}, + {SAY_ARYGOS_ATTACK_2, NPC_ARYGOS, 5000}, + {NPC_ARYGOS, 0, 1000}, // send Arygos to fight + {POINT_ID_EXIT, 0, 4000}, // make Merithra exit + {SAY_ARYGOS_ATTACK_3, NPC_ARYGOS, 4000}, + {SPELL_BLUE_DRAGON_TRANSFORM, 0, 5000}, + {SPELL_ARYGOS_VENGEANCE, 0, 7000}, + {POINT_ID_DRAGON_ATTACK, 0, 1000}, // make Arygos exit + {SAY_CAELESTRASZ_ATTACK_4, NPC_CAELESTRASZ, 5000}, + {NPC_CAELESTRASZ, 0, 0}, // send Caelestrasz to fight + {DATA_CAELASTRASZ_ATTACK, 0, 3000}, // make Caelestrasz wait + {SAY_CAELESTRASZ_ATTACK_5, NPC_CAELESTRASZ, 5000}, + {SPELL_RED_DRAGON_TRANSFORM, 0, 4000}, // transform Caelestrasz + {SPELL_CAELESTRASZ_MOLTEN_RAIN, 0, 6000}, // Caelestrasz casts molten rain + {SAY_ANACHRONOS_SEAL_1, NPC_ANACHRONOS_THE_ANCIENT, 5000}, + {SAY_FANDRAL_SEAL_2, NPC_FANDRAL_STAGHELM, 3000}, + {SAY_ANACHRONOS_SEAL_3, NPC_ANACHRONOS_THE_ANCIENT, 1000}, + {POINT_ID_GATE, 0, 1000}, // send Anachronos to the gate + {NPC_FANDRAL_STAGHELM, 0, 0}, // send Fandral to the gate + {SPELL_TIME_STOP, 0, 7000}, // Anachronos casts Time Stop + {SPELL_PRISMATIC_BARRIER, 0, 15000}, + {SPELL_GLYPH_OF_WARDING, 0, 4000}, + {SAY_ANACHRONOS_SEAL_5, NPC_ANACHRONOS_THE_ANCIENT, 3000}, + {SAY_FANDRAL_SEAL_6, NPC_FANDRAL_STAGHELM, 9000}, + {EMOTE_FANDRAL_EXHAUSTED, NPC_FANDRAL_STAGHELM, 1000}, + {SAY_ANACHRONOS_EPILOGUE_1, NPC_ANACHRONOS_THE_ANCIENT, 6000}, + {SAY_ANACHRONOS_EPILOGUE_2, NPC_ANACHRONOS_THE_ANCIENT, 5000}, + {SAY_ANACHRONOS_EPILOGUE_3, NPC_ANACHRONOS_THE_ANCIENT, 15000}, + {DATA_HANDLE_SCEPTER, NPC_ANACHRONOS_THE_ANCIENT, 3000}, // handle the scepter + {SAY_FANDRAL_EPILOGUE_4, NPC_FANDRAL_STAGHELM, 3000}, + {POINT_ID_SCEPTER_2, 0, 4000}, // make Anachronos stand + {SAY_FANDRAL_EPILOGUE_5, NPC_FANDRAL_STAGHELM, 12000}, + {EMOTE_FANDRAL_SHATTER, NPC_FANDRAL_STAGHELM, 3000}, + {SAY_ANACHRONOS_EPILOGUE_6, NPC_ANACHRONOS_THE_ANCIENT, 0}, + {SAY_FANDRAL_EPILOGUE_7, NPC_FANDRAL_STAGHELM, 8000}, + {POINT_ID_EPILOGUE, 0, 4000}, // move Fandral to Anachronos + {EMOTE_ANACHRONOS_DISPPOINTED, NPC_ANACHRONOS_THE_ANCIENT, 1000}, + {POINT_ID_SCEPTER_1, 0, 0}, // make Anachronos pick the pieces + {0, 0, 0}, +}; - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); +static EVENTLOCATION 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}, +}; - return true; -} +static EVENTLOCATION 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 +}; -bool GossipSelect_npc_highlord_demitrian(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private DialogueHelper { - switch(uiAction) + npc_anachronos_the_ancientAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aEventDialogue) { - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN7, pCreature->GetGUID()); - - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_VESSEL_OF_REBIRTH, 1)) - pPlayer->SendNewItem(pItem, 1, true, false); - - break; + Reset(); } - return true; -} -/*### -## npcs_rutgar_and_frankal -###*/ + uint32 m_uiEventTimer; -//gossip item text best guess -#define GOSSIP_ITEM_SEEK1 "I seek information about Natalia" + uint8 m_uiEventStage; -#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?" + ObjectGuid m_fandralGuid; + ObjectGuid m_merithraGuid; + ObjectGuid m_CaelestraszGuid; + ObjectGuid m_arygosGuid; + ObjectGuid m_playerGuid; + ObjectGuid m_triggerGuid; -#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..." + GuidList m_lQirajiWarriorsList; -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 -}; + void Reset() + { + // We summon the rest of the dragons on timer + m_uiEventTimer = 100; + m_uiEventStage = 0; + } -bool GossipHello_npcs_rutgar_and_frankal(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case NPC_ANACHRONOS_THE_ANCIENT: + // Call the other dragons + DoSummonDragons(); + break; + case EMOTE_ONESHOT_SHOUT: + // Summon warriors + DoSummonWarriors(); + m_creature->HandleEmote(EMOTE_ONESHOT_SHOUT); + break; + case SAY_FANDRAL_INTRO_2: + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->SetFacingToObject(m_creature); + break; + case EMOTE_MERITHRA_GLANCE: + if (Creature* pMerithra = m_creature->GetMap()->GetCreature(m_merithraGuid)) + { + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->SetFacingToObject(pMerithra); + } + break; + case NPC_ANACHRONOS_QUEST_TRIGGER: + // Move Merithra to attack + if (Creature* pTrigger = GetClosestCreatureWithEntry(m_creature, NPC_ANACHRONOS_QUEST_TRIGGER, 35.0f)) + { + m_triggerGuid = pTrigger->GetObjectGuid(); + if (Creature* pMerithra = m_creature->GetMap()->GetCreature(m_merithraGuid)) + { + pMerithra->SetWalk(false); + pMerithra->GetMotionMaster()->MovePoint(POINT_ID_DRAGON_ATTACK, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ()); + } + } + break; + case SPELL_GREEN_DRAGON_TRANSFORM: + if (Creature* pMerithra = m_creature->GetMap()->GetCreature(m_merithraGuid)) + pMerithra->CastSpell(pMerithra, SPELL_GREEN_DRAGON_TRANSFORM, false); + break; + case SAY_ARYGOS_ATTACK_2: + if (Creature* pMerithra = m_creature->GetMap()->GetCreature(m_merithraGuid)) + pMerithra->CastSpell(pMerithra, SPELL_MERITHRA_WAKE, false); + break; + case NPC_ARYGOS: + // Move Arygos to attack + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_triggerGuid)) + { + if (Creature* pArygos = m_creature->GetMap()->GetCreature(m_arygosGuid)) + { + pArygos->SetWalk(false); + pArygos->GetMotionMaster()->MovePoint(POINT_ID_DRAGON_ATTACK, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ()); + } + } + break; + case POINT_ID_EXIT: + // 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_HOVER); + pMerithra->SetLevitate(true); + pMerithra->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[0].m_fX, aEternalBoardMovement[0].m_fY, aEternalBoardMovement[0].m_fZ); + pMerithra->ForcedDespawn(9000); + } + break; + case SPELL_BLUE_DRAGON_TRANSFORM: + if (Creature* pArygos = m_creature->GetMap()->GetCreature(m_arygosGuid)) + pArygos->CastSpell(pArygos, SPELL_BLUE_DRAGON_TRANSFORM, false); + break; + case SPELL_ARYGOS_VENGEANCE: + if (Creature* pArygos = m_creature->GetMap()->GetCreature(m_arygosGuid)) + pArygos->CastSpell(pArygos, SPELL_ARYGOS_VENGEANCE, false); + break; + case POINT_ID_DRAGON_ATTACK: + // 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_HOVER); + pArygos->SetLevitate(true); + pArygos->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[0].m_fX, aEternalBoardMovement[0].m_fY, aEternalBoardMovement[0].m_fZ); + pArygos->ForcedDespawn(9000); + } + break; + case NPC_CAELESTRASZ: + // Move Caelestrasz to attack + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_triggerGuid)) + { + if (Creature* pCaelestrasz = m_creature->GetMap()->GetCreature(m_CaelestraszGuid)) + { + pCaelestrasz->SetWalk(false); + pCaelestrasz->GetMotionMaster()->MovePoint(POINT_ID_DRAGON_ATTACK, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ()); + } + } + break; + case SPELL_RED_DRAGON_TRANSFORM: + if (Creature* pCaelestrasz = m_creature->GetMap()->GetCreature(m_CaelestraszGuid)) + pCaelestrasz->CastSpell(pCaelestrasz, SPELL_RED_DRAGON_TRANSFORM, false); + break; + case SPELL_CAELESTRASZ_MOLTEN_RAIN: + if (Creature* pCaelestrasz = m_creature->GetMap()->GetCreature(m_CaelestraszGuid)) + pCaelestrasz->CastSpell(pCaelestrasz, SPELL_CAELESTRASZ_MOLTEN_RAIN, false); + break; + case SAY_ANACHRONOS_SEAL_1: + // 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_HOVER); + pCaelestrasz->SetLevitate(true); + pCaelestrasz->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[0].m_fX, aEternalBoardMovement[0].m_fY, aEternalBoardMovement[0].m_fZ); + pCaelestrasz->ForcedDespawn(9000); + } + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + m_creature->SetFacingToObject(pFandral); + break; + case SAY_FANDRAL_SEAL_2: + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->SetFacingToObject(m_creature); + break; + case POINT_ID_GATE: + // Send Anachronos to the gate + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_GATE, aEternalBoardMovement[1].m_fX, aEternalBoardMovement[1].m_fY, aEternalBoardMovement[1].m_fZ); + break; + case NPC_FANDRAL_STAGHELM: + // Send Fandral to the gate + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + { + pFandral->SetWalk(false); + pFandral->GetMotionMaster()->MovePoint(POINT_ID_GATE, aEternalBoardMovement[2].m_fX, aEternalBoardMovement[2].m_fY, aEternalBoardMovement[2].m_fZ); + } + break; + case SPELL_PRISMATIC_BARRIER: + DoCastSpellIfCan(m_creature, SPELL_PRISMATIC_BARRIER); + break; + case SPELL_GLYPH_OF_WARDING: + DoCastSpellIfCan(m_creature, SPELL_GLYPH_OF_WARDING); + break; + case SAY_FANDRAL_SEAL_6: + // Here Anachronos should continue to cast something + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->CastSpell(pFandral, SPELL_CALL_ANCIENTS, false); + break; + case EMOTE_FANDRAL_EXHAUSTED: + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + { + pFandral->SetStandState(UNIT_STAND_STATE_KNEEL); + m_creature->SetFacingToObject(pFandral); + } + break; + case DATA_HANDLE_SCEPTER: + // Give the scepter to Fandral (it should equip it somehow) + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + DoScriptText(EMOTE_ANACHRONOS_SCEPTER, m_creature, pFandral); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case SAY_FANDRAL_EPILOGUE_4: + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->SetStandState(UNIT_STAND_STATE_STAND); + break; + case POINT_ID_SCEPTER_2: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + break; + case EMOTE_FANDRAL_SHATTER: + // Shatter the scepter + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->CastSpell(pFandral, SPELL_SHATTER_HAMMER, false); + break; + case SAY_ANACHRONOS_EPILOGUE_6: + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + { + pFandral->SetWalk(true); + pFandral->GetMotionMaster()->MovePoint(POINT_ID_SCEPTER_1, aEternalBoardMovement[3].m_fX, aEternalBoardMovement[3].m_fY, aEternalBoardMovement[3].m_fZ); + } + break; + case POINT_ID_EPILOGUE: + // Make Fandral leave + if (Creature* pFandral = m_creature->GetMap()->GetCreature(m_fandralGuid)) + pFandral->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[7].m_fX, aEternalBoardMovement[7].m_fY, aEternalBoardMovement[7].m_fZ); + break; + case POINT_ID_SCEPTER_1: + // Anachronos collects the pieces + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_SCEPTER_1, aEternalBoardMovement[5].m_fX, aEternalBoardMovement[5].m_fY, aEternalBoardMovement[5].m_fZ); + break; + } + } - 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); + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_ANACHRONOS_THE_ANCIENT: return m_creature; + case NPC_ARYGOS: return m_creature->GetMap()->GetCreature(m_arygosGuid); + case NPC_CAELESTRASZ: return m_creature->GetMap()->GetCreature(m_CaelestraszGuid); + case NPC_MERITHRA_OF_THE_DREAM: return m_creature->GetMap()->GetCreature(m_merithraGuid); + case NPC_FANDRAL_STAGHELM: return m_creature->GetMap()->GetCreature(m_fandralGuid); - 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); + default: + return NULL; + } + } - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RF, pCreature->GetGUID()); + void DoSummonDragons() + { + for (uint8 i = 0; i < MAX_DRAGONS; ++i) + m_creature->SummonCreature(aEternalBoardNPCs[i].m_uiEntry, aEternalBoardNPCs[i].m_fX, aEternalBoardNPCs[i].m_fY, aEternalBoardNPCs[i].m_fZ, aEternalBoardNPCs[i].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0); - return true; + // Also summon the 3 anubisath conquerors + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_CONQUERORS; ++i) + { + m_creature->GetRandomPoint(aEternalBoardMovement[10].m_fX, aEternalBoardMovement[10].m_fY, aEternalBoardMovement[10].m_fZ, 20.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_ANUBISATH_CONQUEROR, fX, fY, fZ, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + } + + void DoSummonWarriors() + { + float fX, fY, fZ; + // Summon kaldorei warriors + 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) + { + 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); + + 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_DRONE, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + + 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_TANK, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + } + + void DoUnsummonArmy() + { + 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) override + { + // Also remove npc flags where needed + switch (pSummoned->GetEntry()) + { + case NPC_FANDRAL_STAGHELM: + m_fandralGuid = pSummoned->GetObjectGuid(); + break; + case NPC_MERITHRA_OF_THE_DREAM: + m_merithraGuid = pSummoned->GetObjectGuid(); + pSummoned->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + break; + case NPC_CAELESTRASZ: + m_CaelestraszGuid = pSummoned->GetObjectGuid(); + pSummoned->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + break; + case NPC_ARYGOS: + m_arygosGuid = pSummoned->GetObjectGuid(); + pSummoned->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + break; + case NPC_ANUBISATH_CONQUEROR: + case NPC_QIRAJI_WASP: + case NPC_QIRAJI_DRONE: + case NPC_QIRAJI_TANK: + case NPC_KALDOREI_INFANTRY: + m_lQirajiWarriorsList.push_back(pSummoned->GetObjectGuid()); + break; + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case POINT_ID_GATE: + // Cast time stop when he reaches the gate + DoCastSpellIfCan(m_creature, SPELL_TIME_STOP); + StartNextDialogueText(SPELL_TIME_STOP); + break; + case POINT_ID_SCEPTER_1: + // Pickup the pieces + DoScriptText(EMOTE_ANACHRONOS_PICKUP, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiEventTimer = 2000; + break; + case POINT_ID_SCEPTER_2: + // Pickup the pieces + DoScriptText(SAY_ANACHRONOS_EPILOGUE_8, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiEventTimer = 4000; + break; + case POINT_ID_EXIT: + // Spell was removed, manually change the display + // 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) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (pSummoned->GetEntry() == NPC_FANDRAL_STAGHELM) + { + switch (uiPointId) + { + case POINT_ID_EPILOGUE: + // Face Anachronos and restart the dialogue + pSummoned->SetFacingToObject(m_creature); + StartNextDialogueText(SAY_FANDRAL_EPILOGUE_7); + DoUnsummonArmy(); + break; + case POINT_ID_SCEPTER_1: + pSummoned->GetMotionMaster()->MovePoint(POINT_ID_EPILOGUE, aEternalBoardMovement[4].m_fX, aEternalBoardMovement[4].m_fY, aEternalBoardMovement[4].m_fZ); + break; + case POINT_ID_EXIT: + pSummoned->ForcedDespawn(); + break; + } + } + else if (uiPointId == POINT_ID_DRAGON_ATTACK) + { + switch (pSummoned->GetEntry()) + { + case NPC_MERITHRA_OF_THE_DREAM: + StartNextDialogueText(DATA_MERITHRA_ATTACK); + break; + case NPC_CAELESTRASZ: + StartNextDialogueText(DATA_CAELASTRASZ_ATTACK); + break; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiEventStage) + { + case 0: + // Start the dialogue + StartNextDialogueText(NPC_ANACHRONOS_THE_ANCIENT); + m_uiEventTimer = 0; + break; + case 1: + // Do the epilogue movement + m_creature->GetMotionMaster()->MovePoint(POINT_ID_SCEPTER_2, aEternalBoardMovement[6].m_fX, aEternalBoardMovement[6].m_fY, aEternalBoardMovement[6].m_fZ); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiEventTimer = 0; + break; + case 2: + // Complete quest and despawn gate + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->GroupEventHappens(QUEST_A_PAWN_ON_THE_ETERNAL_BOARD, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiEventTimer = 4000; + break; + case 3: + // Move to exit + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[8].m_fX, aEternalBoardMovement[8].m_fY, aEternalBoardMovement[8].m_fZ); + m_uiEventTimer = 0; + break; + case 4: + // Take off and fly + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + 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); + m_uiEventTimer = 0; + break; + } + ++m_uiEventStage; + } + else + m_uiEventTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_anachronos_the_ancient(Creature* pCreature) +{ + return new npc_anachronos_the_ancientAI(pCreature); } -bool GossipSelect_npcs_rutgar_and_frankal(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestAcceptGO_crystalline_tear(Player* pPlayer, GameObject* pGo, const Quest* pQuest) { - switch(uiAction) + // Summon the controller dragon at GO position (orientation is wrong - hardcoded) + if (pQuest->GetQuestId() == QUEST_A_PAWN_ON_THE_ETERNAL_BOARD) { - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR7, pCreature->GetGUID()); - //'kill' our trigger to update quest status - pPlayer->KilledMonsterCredit(TRIGGER_RUTGAR, pCreature->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 14: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL6, pCreature->GetGUID()); - //'kill' our trigger to update quest status - pPlayer->KilledMonsterCredit(TRIGGER_FRANKAL, pCreature->GetGUID()); - break; + // Check if event is already in progress first + 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)) + { + // Send the player's guid in order to handle the quest complete + if (npc_anachronos_the_ancientAI* pAnachronosAI = dynamic_cast(pAnachronos->AI())) + pAnachronosAI->m_playerGuid = pPlayer->GetObjectGuid(); + } } + return true; } void AddSC_silithus() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_highlord_demitrian"; - newscript->pGossipHello = &GossipHello_npc_highlord_demitrian; - newscript->pGossipSelect = &GossipSelect_npc_highlord_demitrian; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npcs_rutgar_and_frankal"; - newscript->pGossipHello = &GossipHello_npcs_rutgar_and_frankal; - newscript->pGossipSelect = &GossipSelect_npcs_rutgar_and_frankal; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_anachronos_the_ancient"; + pNewScript->GetAI = &GetAI_npc_anachronos_the_ancient; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_crystalline_tear"; + pNewScript->pQuestAcceptGO = &QuestAcceptGO_crystalline_tear; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/stonetalon_mountains.cpp b/scripts/kalimdor/stonetalon_mountains.cpp index 33ab44f491..9b3cfe5158 100644 --- a/scripts/kalimdor/stonetalon_mountains.cpp +++ b/scripts/kalimdor/stonetalon_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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->GetGUID()); - - 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->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(5819, pCreature->GetGUID()); - - 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 ######*/ @@ -88,26 +47,26 @@ struct MANGOS_DLL_DECL npc_kayaAI : public npc_escortAI void Reset() { } - 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,15 +84,15 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -144,17 +103,11 @@ bool QuestAccept_npc_kaya(Player* pPlayer, Creature* pCreature, Quest const* pQu void AddSC_stonetalon_mountains() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_braug_dimspirit"; - newscript->pGossipHello = &GossipHello_npc_braug_dimspirit; - newscript->pGossipSelect = &GossipSelect_npc_braug_dimspirit; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_kaya"; - newscript->GetAI = &GetAI_npc_kaya; - newscript->pQuestAccept = &QuestAccept_npc_kaya; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_kaya"; + pNewScript->GetAI = &GetAI_npc_kaya; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kaya; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/tanaris.cpp b/scripts/kalimdor/tanaris.cpp index 4a8954090d..d11e4b7a6c 100644 --- a/scripts/kalimdor/tanaris.cpp +++ b/scripts/kalimdor/tanaris.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,16 +17,14 @@ /* ScriptData SDName: Tanaris SD%Complete: 80 -SDComment: Quest support: 648, 1560, 2954, 4005, 10277, 10279(Special flight path). 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_steward_of_time npc_stone_watcher_of_norgannon npc_tooga EndContentData */ @@ -39,89 +37,101 @@ EndContentData */ ## mob_aquementas ######*/ -#define AGGRO_YELL_AQUE -1000168 +enum +{ + AGGRO_YELL_AQUE = -1000168, + + SPELL_AQUA_JET = 13586, + SPELL_FROST_SHOCK = 15089, + + ITEM_SILVER_TOTEM = 11522, + ITEM_BOOK_AQUOR = 11169, + ITEM_SILVERY_CLAWS = 11172, + ITEM_IRONTREE_HEART = 11173, -#define SPELL_AQUA_JET 13586 -#define SPELL_FROST_SHOCK 15089 + FACTION_FRIENDLY = 35, + FACTION_ELEMENTAL = 91, +}; struct MANGOS_DLL_DECL mob_aquementasAI : public ScriptedAI { - mob_aquementasAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 SendItem_Timer; - uint32 SwitchFaction_Timer; - bool isFriendly; + mob_aquementasAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 FrostShock_Timer; - uint32 AquaJet_Timer; + uint32 m_uiSwitchFactionTimer; + uint32 m_uiFrostShockTimer; + uint32 m_uiAquaJetTimer; void Reset() { - 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 || !pReceiver->IsInWorld()) + return; + + 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, true)) { - 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); + if (!pWho || !pWho->GetObjectGuid().IsPlayer()) + return; + 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); @@ -131,33 +141,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 +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 MANGOS_DLL_DECL 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; @@ -178,26 +196,24 @@ 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 *who) + void MoveInLineOfSight(Unit* pWho) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) return; - if (who->GetTypeId() == TYPEID_PLAYER) + if (pWho->GetTypeId() == TYPEID_PLAYER) { - if (((Player*)who)->HasAura(34877, EFFECT_INDEX_1) && ((Player*)who)->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(who, Radius)) - Start(false, who->GetGUID()); + if (m_creature->IsWithinDistInMap(pWho, fRadius)) + Start(false, (Player*)pWho); } } } @@ -210,31 +226,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->GetGUID()); - - 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->GetGUID()); - - return true; -} - -bool GossipSelect_npc_marin_noggenfogger(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - - return true; -} - /*###### ## npc_oox17tn ######*/ @@ -259,7 +250,7 @@ struct MANGOS_DLL_DECL 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(); @@ -268,14 +259,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); @@ -283,7 +274,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: @@ -296,17 +287,17 @@ struct MANGOS_DLL_DECL npc_oox17tnAI : public npc_escortAI void Reset() { } - 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); } @@ -326,52 +317,14 @@ 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->GetGUID(), pQuest); - } - return true; -} - -/*###### -## npc_steward_of_time -######*/ - -#define GOSSIP_ITEM_FLIGHT "Please take me to the master's lair." - -bool GossipHello_npc_steward_of_time(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(10279) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestRewardStatus(10279)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(9978, pCreature->GetGUID()); + pEscortAI->Start(false, pPlayer, pQuest); } - else - pPlayer->SEND_GOSSIP_MENU(9977, pCreature->GetGUID()); - - return true; -} - -bool QuestAccept_npc_steward_of_time(Player* pPlayer, Creature* pCreature, const Quest* pQuest) -{ - if (pQuest->GetQuestId() == 10279) //Quest: To The Master's Lair - pPlayer->CastSpell(pPlayer,34891,true); //(Flight through Caverns) - - return false; -} - -bool GossipSelect_npc_steward_of_time(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) - pPlayer->CastSpell(pPlayer,34891,true); //(Flight through Caverns) - return true; } @@ -389,39 +342,39 @@ bool GossipSelect_npc_steward_of_time(Player* pPlayer, Creature* pCreature, uint bool GossipHello_npc_stone_watcher_of_norgannon(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(2954) == QUEST_STATUS_INCOMPLETE) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(1674, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(1674, pCreature->GetObjectGuid()); 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->SEND_GOSSIP_MENU(1675, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(1676, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(1677, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(1678, pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(1679, pCreature->GetGUID()); + 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: pPlayer->CLOSE_GOSSIP_MENU(); @@ -452,7 +405,7 @@ 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 { @@ -473,7 +426,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI pTorta = NULL; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); @@ -493,7 +446,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); @@ -504,11 +457,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) @@ -517,12 +470,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); @@ -557,7 +510,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; @@ -592,46 +545,33 @@ bool QuestAccept_npc_tooga(Player* pPlayer, Creature* pCreature, const Quest* pQ void AddSC_tanaris() { - Script *newscript; - - newscript = new Script; - newscript->Name = "mob_aquementas"; - newscript->GetAI = &GetAI_mob_aquementas; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_custodian_of_time"; - newscript->GetAI = &GetAI_npc_custodian_of_time; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_marin_noggenfogger"; - newscript->pGossipHello = &GossipHello_npc_marin_noggenfogger; - newscript->pGossipSelect = &GossipSelect_npc_marin_noggenfogger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_oox17tn"; - newscript->GetAI = &GetAI_npc_oox17tn; - newscript->pQuestAccept = &QuestAccept_npc_oox17tn; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_steward_of_time"; - newscript->pGossipHello = &GossipHello_npc_steward_of_time; - newscript->pGossipSelect = &GossipSelect_npc_steward_of_time; - newscript->pQuestAccept = &QuestAccept_npc_steward_of_time; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_stone_watcher_of_norgannon"; - newscript->pGossipHello = &GossipHello_npc_stone_watcher_of_norgannon; - newscript->pGossipSelect = &GossipSelect_npc_stone_watcher_of_norgannon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tooga"; - newscript->GetAI = &GetAI_npc_tooga; - newscript->pQuestAccept = &QuestAccept_npc_tooga; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_aquementas"; + pNewScript->GetAI = &GetAI_mob_aquementas; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_custodian_of_time"; + pNewScript->GetAI = &GetAI_npc_custodian_of_time; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_oox17tn"; + pNewScript->GetAI = &GetAI_npc_oox17tn; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_oox17tn; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_stone_watcher_of_norgannon"; + pNewScript->pGossipHello = &GossipHello_npc_stone_watcher_of_norgannon; + pNewScript->pGossipSelect = &GossipSelect_npc_stone_watcher_of_norgannon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tooga"; + pNewScript->GetAI = &GetAI_npc_tooga; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_tooga; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/teldrassil.cpp b/scripts/kalimdor/teldrassil.cpp index 3a8efbbfa6..999851f9bd 100644 --- a/scripts/kalimdor/teldrassil.cpp +++ b/scripts/kalimdor/teldrassil.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,6 +24,8 @@ EndScriptData */ /* ContentData npc_mist +Tyrande Whisperwind +Archdruid Fandral Staghelm EndContentData */ #include "precompiled.h" @@ -45,9 +48,9 @@ struct MANGOS_DLL_DECL 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 +74,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; @@ -101,13 +104,171 @@ bool QuestAccept_npc_mist(Player* pPlayer, Creature* pCreature, const Quest* pQu return true; } +/*#### +# Tyrande Whisperwind +####*/ + +enum +{ + SPELL_CLEAVE_TYRANDE = 20691, + SPELL_MOONFIRE = 20690, + SPELL_SEARING_ARROW = 20688, + SPELL_STARFALL = 20687, +}; + +struct MANGOS_DLL_DECL boss_tyrande_whisperwindAI : public ScriptedAI +{ + boss_tyrande_whisperwindAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiCleaveTimer; + uint32 m_uiMoonfireTimer; + uint32 m_uiStarfallTimer; + uint32 m_uiSearingArrowTimer; + + void Reset() + { + m_uiCleaveTimer = 5000; + m_uiMoonfireTimer = 12000; + m_uiStarfallTimer = 15000; + m_uiSearingArrowTimer = 8000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCleaveTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE_TYRANDE); + m_uiCleaveTimer = urand(5000, 8000); + } + else + m_uiCleaveTimer -= uiDiff; + + if (m_uiMoonfireTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(pTarget, SPELL_MOONFIRE); + m_uiMoonfireTimer = urand(11000, 15000); + } + else + m_uiMoonfireTimer -= uiDiff; + + if (m_uiStarfallTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(pTarget, SPELL_STARFALL); + m_uiStarfallTimer = urand(15000, 19000); + } + else + m_uiStarfallTimer -= uiDiff; + + if (m_uiSearingArrowTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(pTarget, SPELL_SEARING_ARROW); + m_uiSearingArrowTimer = 8000; + } + else + m_uiSearingArrowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_tyrande_whisperwind(Creature* pCreature) +{ + return new boss_tyrande_whisperwindAI(pCreature); +} + +/*#### +# Archdruid Fandral Staghelm +####*/ + +enum +{ + SPELL_ENTANGLING_ROOTS = 20699, + // SPELL_REJUVENATION = 20701, + SPELL_SUMMON_TREANTS = 20702, + SPELL_WRATH = 20698, + NPC_TREANT = 31802, +}; + +struct MANGOS_DLL_DECL boss_fandral_staghelmAI : public ScriptedAI +{ + boss_fandral_staghelmAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + uint32 m_uiEntanglingTimer; + uint32 m_uiWrathTimer; + uint32 m_uiSummonAlyTimer; + //uint32 m_uiRejuvinationTimer; + + void Reset() + { + m_uiEntanglingTimer = 7000; + m_uiWrathTimer = 5000; + m_uiSummonAlyTimer = 15000; + //m_uiRejuvinationTimer = 10000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEntanglingTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(pTarget, SPELL_ENTANGLING_ROOTS); + m_uiEntanglingTimer = urand(7000, 11000); + } + else + m_uiEntanglingTimer -= uiDiff; + + if (m_uiWrathTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + DoCast(m_creature, SPELL_WRATH); + m_uiWrathTimer = urand(5000, 8000); + } + else + m_uiWrathTimer -= uiDiff; + + if (m_uiSummonAlyTimer < uiDiff) + { + DoCast(m_creature, SPELL_SUMMON_TREANTS); + m_uiSummonAlyTimer = urand(25000, 30000); + } + else + m_uiSummonAlyTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_fandral_staghelm(Creature* pCreature) +{ + return new boss_fandral_staghelmAI(pCreature); +} + void AddSC_teldrassil() { - Script *newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_mist"; + pNewScript->GetAI = &GetAI_npc_mist; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_mist; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_tyrande_whisperwind"; + pNewScript->GetAI = &GetAI_boss_tyrande_whisperwind; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_mist"; - newscript->GetAI = &GetAI_npc_mist; - newscript->pQuestAccept = &QuestAccept_npc_mist; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_fandral_staghelm"; + pNewScript->GetAI = &GetAI_boss_fandral_staghelm; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp index ed05f27edb..6ea7c234b6 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,25 +15,33 @@ */ /* ScriptData -SDName: boss_kri, boss_yauj, boss_vem : The Bug Trio -SD%Complete: 100 -SDComment: +SDName: bug_trio +SD%Complete: 75 +SDComment: Summon Player spell NYI; Poison Cloud damage spell NYI; Timers need adjustments SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" #include "temple_of_ahnqiraj.h" -#define SPELL_CLEAVE 26350 -#define SPELL_TOXIC_VOLLEY 25812 -#define SPELL_POISON_CLOUD 38718 //Only Spell with right dmg. -#define SPELL_ENRAGE 34624 //Changed cause 25790 is casted on gamers too. Same prob with old explosion of twin emperors. +enum +{ + // kri + SPELL_CLEAVE = 26350, + SPELL_TOXIC_VOLLEY = 25812, + SPELL_SUMMON_CLOUD = 26590, // summons 15933 + + // vem + SPELL_CHARGE = 26561, + SPELL_VENGEANCE = 25790, + SPELL_KNOCKBACK = 26027, -#define SPELL_CHARGE 26561 -#define SPELL_KNOCKBACK 26027 + // yauj + SPELL_HEAL = 25807, + SPELL_FEAR = 26580, -#define SPELL_HEAL 25807 -#define SPELL_FEAR 19408 + NPC_YAUJ_BROOD = 15621 +}; struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI { @@ -45,73 +53,60 @@ struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 Cleave_Timer; - uint32 ToxicVolley_Timer; - uint32 Check_Timer; - - bool VemDead; - bool Death; + uint32 m_uiCleaveTimer; + uint32 m_uiToxicVolleyTimer; void Reset() { - Cleave_Timer = urand(4000, 8000); - ToxicVolley_Timer = urand(6000, 12000); - Check_Timer = 2000; - - VemDead = false; - Death = false; + m_uiCleaveTimer = urand(4000, 8000); + m_uiToxicVolleyTimer = urand(6000, 12000); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { - if (m_pInstance) - { - if (m_pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) - // Unlootable if death - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + // poison cloud on death + DoCastSpellIfCan(m_creature, SPELL_SUMMON_CLOUD, CAST_TRIGGERED); - m_pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); + if (!m_pInstance) + return; + + // If the other 2 bugs are still alive, make unlootable + if (m_pInstance->GetData(TYPE_BUG_TRIO) != DONE) + { + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + m_pInstance->SetData(TYPE_BUG_TRIO, SPECIAL); } } - void UpdateAI(const uint32 diff) + + void JustReachedHome() override { - //Return since we have no target + if (m_pInstance) + m_pInstance->SetData(TYPE_BUG_TRIO, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = urand(5000, 12000); - }else Cleave_Timer -= diff; - - //ToxicVolley_Timer - if (ToxicVolley_Timer < diff) + // Cleave_Timer + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_TOXIC_VOLLEY); - ToxicVolley_Timer = urand(10000, 15000); - }else ToxicVolley_Timer -= diff; - - if (m_creature->GetHealthPercent() < 5.0f && !Death) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_POISON_CLOUD); - Death = true; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(5000, 12000); } + else + m_uiCleaveTimer -= uiDiff; - if (!VemDead) + // ToxicVolley_Timer + if (m_uiToxicVolleyTimer < uiDiff) { - //Checking if Vem is dead. If yes we will enrage. - if (Check_Timer < diff) - { - if (m_pInstance && m_pInstance->GetData(TYPE_VEM) == DONE) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - VemDead = true; - } - Check_Timer = 2000; - }else Check_Timer -=diff; + if (DoCastSpellIfCan(m_creature, SPELL_TOXIC_VOLLEY) == CAST_OK) + m_uiToxicVolleyTimer = urand(10000, 15000); } + else + m_uiToxicVolleyTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -127,65 +122,68 @@ struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 Charge_Timer; - uint32 KnockBack_Timer; - uint32 Enrage_Timer; - - bool Enraged; + uint32 m_uiChargeTimer; + uint32 m_uiKnockBackTimer; void Reset() { - Charge_Timer = urand(15000, 27000); - KnockBack_Timer = urand(8000, 20000); - Enrage_Timer = 120000; - - Enraged = false; + m_uiChargeTimer = urand(15000, 27000); + m_uiKnockBackTimer = urand(8000, 20000); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { - if (m_pInstance) - { - m_pInstance->SetData(TYPE_VEM, DONE); + // Enrage the other bugs + DoCastSpellIfCan(m_creature, SPELL_VENGEANCE, CAST_TRIGGERED); - // Unlootable if death - if (m_pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + if (!m_pInstance) + return; - m_pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); + // If the other 2 bugs are still alive, make unlootable + if (m_pInstance->GetData(TYPE_BUG_TRIO) != DONE) + { + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + m_pInstance->SetData(TYPE_BUG_TRIO, SPECIAL); } } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - //Return since we have no target + if (m_pInstance) + m_pInstance->SetData(TYPE_BUG_TRIO, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Charge_Timer - if (Charge_Timer < diff) + // Charge_Timer + if (m_uiChargeTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_CHARGE); - - Charge_Timer = urand(8000, 16000); - }else Charge_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) + m_uiChargeTimer = urand(8000, 16000); + } + } + else + m_uiChargeTimer -= uiDiff; - //KnockBack_Timer - if (KnockBack_Timer < diff) + // KnockBack_Timer + if (m_uiKnockBackTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKBACK); - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); - KnockBack_Timer = urand(15000, 25000); - }else KnockBack_Timer -= diff; - - //Enrage_Timer - if (!Enraged && Enrage_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_ENRAGE); - Enraged = true; - }else Charge_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_KNOCKBACK) == CAST_OK) + { + if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -80); + + m_uiKnockBackTimer = urand(15000, 25000); + } + } + else + m_uiKnockBackTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -201,97 +199,71 @@ struct MANGOS_DLL_DECL boss_yaujAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 Heal_Timer; - uint32 Fear_Timer; - uint32 Check_Timer; - - bool VemDead; + uint32 m_uiHealTimer; + uint32 m_uiFearTimer; void Reset() { - Heal_Timer = urand(25000, 40000); - Fear_Timer = urand(12000, 24000); - Check_Timer = 2000; - - VemDead = false; + m_uiHealTimer = urand(25000, 40000); + m_uiFearTimer = urand(12000, 24000); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*Killer*/) override { - if (m_pInstance) + // Spawn 10 yauj brood on death + float fX, fY, fZ; + for (int i = 0; i < 10; ++i) { - if (m_pInstance->GetData(DATA_BUG_TRIO_DEATH) < 2) - // Unlootable if death - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - m_pInstance->SetData(DATA_BUG_TRIO_DEATH, 1); + 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_OOC_DESPAWN, 30000); } - for(int i = 0; i < 10; ++i) + if (!m_pInstance) + return; + + // If the other 2 bugs are still alive, make unlootable + if (m_pInstance->GetData(TYPE_BUG_TRIO) != DONE) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - Creature* Summoned = m_creature->SummonCreature(15621,m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(),0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,90000); - if (Summoned && target) - Summoned->AI()->AttackStart(target); + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + m_pInstance->SetData(TYPE_BUG_TRIO, SPECIAL); } } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - //Return since we have no target + if (m_pInstance) + m_pInstance->SetData(TYPE_BUG_TRIO, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Fear_Timer - if (Fear_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FEAR); - DoResetThreat(); - Fear_Timer = 20000; - }else Fear_Timer -= diff; - - //Casting Heal to other twins or herself. - if (Heal_Timer < diff) + // Fear_Timer + if (m_uiFearTimer < uiDiff) { - if (m_pInstance) + if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) { - Creature *pKri = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_KRI)); - Creature *pVem = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_VEM)); - - switch(urand(0, 2)) - { - case 0: - if (pKri) - DoCastSpellIfCan(pKri, SPELL_HEAL); - break; - case 1: - if (pVem) - DoCastSpellIfCan(pVem, SPELL_HEAL); - break; - case 2: - DoCastSpellIfCan(m_creature, SPELL_HEAL); - break; - } + DoResetThreat(); + m_uiFearTimer = 20000; } + } + else + m_uiFearTimer -= uiDiff; - Heal_Timer = urand(15000, 30000); - }else Heal_Timer -= diff; - - //Checking if Vem is dead. If yes we will enrage. - if (Check_Timer < diff) + // Heal + if (m_uiHealTimer < uiDiff) { - if (!VemDead) + if (Unit* pTarget = DoSelectLowestHpFriendly(100.0f)) { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_VEM) == DONE) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - VemDead = true; - } - } + if (DoCastSpellIfCan(pTarget, SPELL_HEAL) == CAST_OK) + m_uiHealTimer = urand(15000, 30000); } - Check_Timer = 2000; - }else Check_Timer -= diff; + } + else + m_uiHealTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -314,19 +286,20 @@ CreatureAI* GetAI_boss_kri(Creature* pCreature) void AddSC_bug_trio() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_kri"; - newscript->GetAI = &GetAI_boss_kri; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_vem"; - newscript->GetAI = &GetAI_boss_vem; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_yauj"; - newscript->GetAI = &GetAI_boss_yauj; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_kri"; + pNewScript->GetAI = &GetAI_boss_kri; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_vem"; + pNewScript->GetAI = &GetAI_boss_vem; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_yauj"; + pNewScript->GetAI = &GetAI_boss_yauj; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp index 02fc0497aa..00b3c06d2e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,1339 +17,812 @@ /* 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 */ #include "precompiled.h" #include "temple_of_ahnqiraj.h" -//Text emote -#define EMOTE_WEAKENED -1531011 - -#define PI 3.14 - -//****** Out of Combat ****** -//Random Wispers - No txt only sound -#define RANDOM_SOUND_WHISPER 8663 - -//***** Phase 1 ******** - -//Mobs -#define BOSS_EYE_OF_CTHUN 15589 -#define MOB_CLAW_TENTACLE 15725 -#define MOB_EYE_TENTACLE 15726 -#define MOB_SMALL_PORTAL 15904 - -//Eye Spells -#define SPELL_GREEN_BEAM 26134 -#define SPELL_DARK_GLARE 26029 -#define SPELL_RED_COLORATION 22518 //Probably not the right spell but looks similar - -//Eye Tentacles Spells -#define SPELL_MIND_FLAY 26143 - -//Claw Tentacles Spells -#define SPELL_GROUND_RUPTURE 26139 -#define SPELL_HAMSTRING 26141 - -#define MOB_ - -//*****Phase 2****** -//Body spells -//#define SPELL_CARAPACE_CTHUN 26156 //Was removed from client dbcs -#define SPELL_TRANSFORM 26232 - -//Eye Tentacles Spells -//SAME AS PHASE1 - -//Giant Claw Tentacles -#define SPELL_MASSIVE_GROUND_RUPTURE 26100 - -//Also casts Hamstring -#define SPELL_THRASH 3391 - -//Giant Eye Tentacles -//CHAIN CASTS "SPELL_GREEN_BEAM" - -//Stomach Spells -#define SPELL_MOUTH_TENTACLE 26332 -#define SPELL_EXIT_STOMACH_KNOCKBACK 25383 -#define SPELL_DIGESTIVE_ACID 26476 - -//Mobs -#define MOB_BODY_OF_CTHUN 15809 -#define MOB_GIANT_CLAW_TENTACLE 15728 -#define MOB_GIANT_EYE_TENTACLE 15334 -#define MOB_FLESH_TENTACLE 15802 -#define MOB_GIANT_PORTAL 15910 - -//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 -#define KICK_X -8545.0f -#define KICK_Y 1984.0f -#define KICK_Z -96.0f - -struct MANGOS_DLL_DECL flesh_tentacleAI : public ScriptedAI +enum { - flesh_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature), Parent(0) - { - SetCombatMovement(false); - Reset(); - } - - uint64 Parent; - uint32 CheckTimer; - - void SpawnedByCthun(uint64 p) - { - Parent = p; - } - - void Reset() - { - CheckTimer = 1000; - } + EMOTE_WEAKENED = -1531011, + + // ***** Phase 1 ******** + 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 ****** + // 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, + + // 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 + + // 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, + + 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. + + AREATRIGGER_STOMACH_1 = 4033, + AREATRIGGER_STOMACH_2 = 4034, + + MAX_FLESH_TENTACLES = 2, + MAX_EYE_TENTACLES = 8, +}; - void UpdateAI(const uint32 diff); +static const float afCthunLocations[4][4] = +{ + { -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 MANGOS_DLL_DECL 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 PhaseTimer; + CThunPhase m_Phase; - //Eye beam phase - uint32 BeamTimer; - uint32 EyeTentacleTimer; - uint32 ClawTentacleTimer; + uint32 m_uiClawTentacleTimer; + uint32 m_uiEyeTentacleTimer; + uint32 m_uiBeamTimer; + uint32 m_uiDarkGlareTimer; + uint32 m_uiDarkGlareEndTimer; - //Dark Glare phase - uint32 DarkGlareTick; - uint32 DarkGlareTickTimer; - float DarkGlareAngle; - bool ClockWise; + GuidList m_lEyeTentaclesList; void Reset() { - //Phase information - PhaseTimer = 50000; //First dark glare in 50 seconds - - //Eye beam phase 50 seconds - BeamTimer = 3000; - EyeTentacleTimer = 45000; //Always spawns 5 seconds before Dark Beam - ClawTentacleTimer = 12500; //4 per Eye beam phase (unsure if they spawn durring Dark beam) + m_Phase = PHASE_EYE_NORMAL; - //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks) - DarkGlareTick = 0; - DarkGlareTickTimer = 1000; - DarkGlareAngle = 0; - ClockWise = false; + m_uiDarkGlareTimer = 45000; + m_uiDarkGlareEndTimer = 40000; + m_uiClawTentacleTimer = urand(10000, 15000); + m_uiBeamTimer = 0; + m_uiEyeTentacleTimer = 45000; + } - //Reset flags - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, IN_PROGRESS); + } - //Reset Phase + void JustDied(Unit* pKiller) override + { + // Allow the body to begin the transition if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, 0); + { + 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 Aggro(Unit* pWho) + void JustReachedHome() override { - m_creature->SetInCombatWithZone(); + // Despawn Eye tentacles on evade + DoDespawnEyeTentacles(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, FAIL); } - void SpawnEyeTentacle(float x, float y) + void JustSummoned(Creature* pSummoned) override { - Creature* Spawned; - Spawned = (Creature*)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 (Spawned) + switch (pSummoned->GetEntry()) { - Unit* target; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - - if (target) - Spawned->AI()->AttackStart(target); + 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 UpdateAI(const uint32 diff) + void SummonedCreatureJustDied(Creature* pSummoned) override { - //Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + // Despawn the tentacle portal - this applies to all the summoned tentacles + if (Creature* pPortal = GetClosestCreatureWithEntry(pSummoned, NPC_TENTACLE_PORTAL, 5.0f)) + pPortal->ForcedDespawn(); + } - //No instance - if (!m_pInstance) + void SummonedCreatureDespawn(Creature* pSummoned) override + { + // Used only after evade + if (SelectHostileTarget()) return; - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + // 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(); + } + + // Wrapper to kill the eye tentacles before summoning new ones + void DoDespawnEyeTentacles() + { + for (GuidList::const_iterator itr = m_lEyeTentaclesList.begin(); itr != m_lEyeTentaclesList.end(); ++itr) { - case 0: - { - //BeamTimer - if (BeamTimer < diff) - { - //SPELL_GREEN_BEAM - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(target,SPELL_GREEN_BEAM); + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } - //Correctly update our target - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - } + m_lEyeTentaclesList.clear(); + } - //Beam every 3 seconds - BeamTimer = 3000; - }else BeamTimer -= diff; + // Custom threat management + bool SelectHostileTarget() + { + Unit* pTarget = NULL; + Unit* pOldTarget = m_creature->getVictim(); - //ClawTentacleTimer - if (ClawTentacleTimer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - { - Creature* Spawned = NULL; + if (!m_creature->getThreatManager().isThreatListEmpty()) + pTarget = m_creature->getThreatManager().getHostileTarget(); - //Spawn claw tentacle on the random target - Spawned = (Creature*)m_creature->SummonCreature(MOB_CLAW_TENTACLE,target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,500); + if (pTarget) + { + if (pOldTarget != pTarget && m_Phase == PHASE_EYE_NORMAL) + AttackStart(pTarget); - if (Spawned) - Spawned->AI()->AttackStart(target); - } + // 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); + } - //One claw tentacle every 12.5 seconds - ClawTentacleTimer = 12500; - }else ClawTentacleTimer -= diff; + return true; + } - //EyeTentacleTimer - if (EyeTentacleTimer < diff) - { - //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 - EyeTentacleTimer = 45000; - }else EyeTentacleTimer -= diff; - - //PhaseTimer - if (PhaseTimer < diff) - { - //Switch to Dark Beam - m_pInstance->SetData(TYPE_CTHUN_PHASE, 1); + // Will call EnterEvadeMode if fit + return m_creature->SelectHostileTarget(); + } - m_creature->InterruptNonMeleeSpells(false); + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectHostileTarget()) + return; - //Select random target for dark beam to start on - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + switch (m_Phase) + { + case PHASE_EYE_NORMAL: - if (target) + if (m_uiBeamTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - //Correctly update our target - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - - //Face our target - DarkGlareAngle = m_creature->GetAngle(target); - DarkGlareTickTimer = 1000; - DarkGlareTick = 0; - ClockWise = urand(0, 1); + if (DoCastSpellIfCan(pTarget, SPELL_EYE_BEAM) == CAST_OK) + { + m_creature->SetTargetGuid(pTarget->GetObjectGuid()); + m_uiBeamTimer = 3000; + } } + } + else + m_uiBeamTimer -= uiDiff; - //Add red coloration to C'thun - DoCastSpellIfCan(m_creature,SPELL_RED_COLORATION); - - //Freeze animation - - //Darkbeam for 35 seconds - PhaseTimer = 35000; - }else PhaseTimer -= diff; - - } - break; - case 1: - { - //EyeTentacleTimer - if (DarkGlareTick < 35) - if (DarkGlareTickTimer < diff) + if (m_uiDarkGlareTimer < uiDiff) { - //Remove any target - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - //Set angle and cast - if (ClockWise) - m_creature->SetOrientation(DarkGlareAngle + ((float)DarkGlareTick*PI/35)); - else m_creature->SetOrientation(DarkGlareAngle - ((float)DarkGlareTick*PI/35)); - - m_creature->StopMoving(); - - //Actual dark glare cast, maybe something missing here? - m_creature->CastSpell(NULL, SPELL_DARK_GLARE, false); + // Cast the rotation spell + if (DoCastSpellIfCan(m_creature, SPELL_ROTATE_TRIGGER) == CAST_OK) + { + // Remove the target focus but allow the boss to face the current victim + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->SetFacingToObject(m_creature->getVictim()); - //Increase tick - ++DarkGlareTick; + // Switch to Dark Glare phase + m_uiDarkGlareTimer = 45000; + m_Phase = PHASE_EYE_DARK_GLARE; + } + } + else + m_uiDarkGlareTimer -= uiDiff; - //1 second per tick - DarkGlareTickTimer = 1000; - }else DarkGlareTickTimer -= diff; + break; + case PHASE_EYE_DARK_GLARE: - //PhaseTimer - if (PhaseTimer < diff) + if (m_uiDarkGlareEndTimer < uiDiff) { - //Switch to Eye Beam - m_pInstance->SetData(TYPE_CTHUN_PHASE, 0); - - BeamTimer = 3000; - EyeTentacleTimer = 45000; //Always spawns 5 seconds before Dark Beam - ClawTentacleTimer = 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); - - //Freeze animation - m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); - - //Eye Beam for 50 seconds - PhaseTimer = 50000; - }else PhaseTimer -= diff; - }break; + // Remove rotation auras + m_creature->RemoveAurasDueToSpell(SPELL_ROTATE_360_LEFT); + m_creature->RemoveAurasDueToSpell(SPELL_ROTATE_360_RIGHT); + + // Switch to Eye Beam + m_uiDarkGlareEndTimer = 40000; + m_uiBeamTimer = 1000; + m_Phase = PHASE_EYE_NORMAL; + } + else + m_uiDarkGlareEndTimer -= uiDiff; - //Transition phase - case 2: - { - //Remove any target - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - m_creature->SetHealth(0); - } + break; + } - //Dead phase - case 5: + 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); + // 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); } } - } + else + m_uiClawTentacleTimer -= uiDiff; - void DamageTaken(Unit *done_by, uint32 &damage) - { - //No instance - if (!m_pInstance) - return; - - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + if (m_uiEyeTentacleTimer <= uiDiff) { - case 0: - case 1: - { - //Only if it will kill - if (damage < 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->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - //Death animation/respawning; - m_pInstance->SetData(TYPE_CTHUN_PHASE, 2); - - m_creature->SetHealth(0); - damage = 0; + // Despawn the eye tentacles if necessary + DoDespawnEyeTentacles(); - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - } - break; - - case 5: + // 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 - damage = 0; - return; - } - break; + m_uiEyeTentacleTimer = 45000; } + else + m_uiEyeTentacleTimer -= uiDiff; } }; -struct MANGOS_DLL_DECL cthunAI : public ScriptedAI +/*###### +## boss_cthun +######*/ + +struct MANGOS_DLL_DECL 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 WisperTimer; + CThunPhase m_Phase; - //Global variables - uint32 PhaseTimer; + // Global variables + uint32 m_uiPhaseTimer; + uint8 m_uiFleshTentaclesKilled; + uint32 m_uiEyeTentacleTimer; + uint32 m_uiGiantClawTentacleTimer; + uint32 m_uiGiantEyeTentacleTimer; + uint32 m_uiDigestiveAcidTimer; - //------------------- + // Body Phase + uint32 m_uiMouthTentacleTimer; + uint32 m_uiStomachEnterTimer; - //Phase transition - uint64 HoldPlayer; + GuidList m_lEyeTentaclesList; + GuidList m_lPlayersInStomachList; - //Body Phase - uint32 EyeTentacleTimer; - uint8 FleshTentaclesKilled; - uint32 GiantClawTentacleTimer; - uint32 GiantEyeTentacleTimer; - uint32 StomachAcidTimer; - uint32 StomachEnterTimer; - uint32 StomachEnterVisTimer; - uint64 StomachEnterTarget; - - //Stomach map, bool = true then in stomach - UNORDERED_MAP Stomach_Map; + ObjectGuid m_stomachEnterTargetGuid; void Reset() { - //One random wisper every 90 - 300 seconds - WisperTimer = 90000; - - //Phase information - PhaseTimer = 10000; //Emerge in 10 seconds - - //No hold player for transition - HoldPlayer = 0; + // Phase information + m_Phase = PHASE_TRANSITION; - //Body Phase - EyeTentacleTimer = 30000; - FleshTentaclesKilled = 0; - GiantClawTentacleTimer = 15000; //15 seconds into body phase (1 min repeat) - GiantEyeTentacleTimer = 45000; //15 seconds into body phase (1 min repeat) - StomachAcidTimer = 4000; //Every 4 seconds - StomachEnterTimer = 10000; //Every 10 seconds - StomachEnterVisTimer = 0; //Always 3.5 seconds after Stomach Enter Timer - StomachEnterTarget = 0; //Target to be teleported to stomach + m_uiPhaseTimer = 5000; + m_uiFleshTentaclesKilled = 0; + m_uiEyeTentacleTimer = 35000; + m_uiGiantClawTentacleTimer = 20000; + m_uiGiantEyeTentacleTimer = 50000; + m_uiDigestiveAcidTimer = 4000; - //Clear players in stomach and outside - Stomach_Map.clear(); + // Body Phase + m_uiMouthTentacleTimer = 15000; + m_uiStomachEnterTimer = 0; - //Reset flags - m_creature->RemoveAurasDueToSpell(SPELL_TRANSFORM); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + // Clear players in stomach + m_lPlayersInStomachList.clear(); - if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, 0); + // Reset flags + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { - m_creature->SetInCombatWithZone(); + // 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 SpawnEyeTentacle(float x, float y) + void EnterEvadeMode() override { - Creature* Spawned; - Spawned = (Creature*)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 (Spawned) + // 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) { - Unit* target; - - target = SelectRandomNotStomach(); - - if (target) - Spawned->AI()->AttackStart(target); + // 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(); } - Unit* SelectRandomNotStomach() + void JustReachedHome() override { - if (Stomach_Map.empty()) - return NULL; + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, FAIL); + } - UNORDERED_MAP::iterator i = Stomach_Map.begin(); + void JustDied(Unit* /*pKiller*/) override + { + m_creature->SetActiveObjectState(false); - std::list temp; - std::list::iterator j; + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, DONE); + } - //Get all players in map - while (i != Stomach_Map.end()) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - //Check for valid player - Unit* pUnit = m_creature->GetMap()->GetUnit(i->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 (pUnit && i->second == false) - { - temp.push_back(pUnit); - } - ++i; - } - - if (temp.empty()) - return NULL; - - j = temp.begin(); - - //Get random but only if we have more than one unit on threat list - if (temp.size() > 1) - advance (j , rand() % (temp.size() - 1)); + 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); - return (*j); + pSummoned->SummonCreature(NPC_GIANT_TENTACLE_PORTAL, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + } } - void UpdateAI(const uint32 diff) + void SummonedCreatureJustDied(Creature* pSummoned) override { - //Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + switch (pSummoned->GetEntry()) { - //No target so we'll use this section to do our random wispers instance wide - //WisperTimer - if (WisperTimer < diff) - { - Map *map = m_creature->GetMap(); - if (!map->IsDungeon()) - return; - - //Play random sound to the zone - Map::PlayerList const &PlayerList = map->GetPlayers(); - - if (!PlayerList.isEmpty()) + // 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) { - for(Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + if (DoCastSpellIfCan(m_creature, SPELL_CTHUN_VULNERABLE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - if (Player* pPlr = itr->getSource()) - pPlr->PlayDirectSound(RANDOM_SOUND_WHISPER,pPlr); + DoScriptText(EMOTE_WEAKENED, m_creature); + m_uiPhaseTimer = 45000; + m_Phase = PHASE_CTHUN_WEAKENED; } } - - //One random wisper every 90 - 300 seconds - WisperTimer = urand(90000, 300000); - }else WisperTimer -= diff; - - return; + break; } + } - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); + // Wrapper to handle the Flesh Tentacles spawn + void DoSpawnFleshTentacles() + { + m_uiFleshTentaclesKilled = 0; - //No instance - if (!m_pInstance) - return; + // 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); + } - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + // Wrapper to kill the eye tentacles before summoning new ones + void DoDespawnEyeTentacles() + { + for (GuidList::const_iterator itr = m_lEyeTentaclesList.begin(); itr != m_lEyeTentaclesList.end(); ++itr) { - //Transition phase - case 2: - { - //PhaseTimer - if (PhaseTimer < diff) - { - //Switch - m_pInstance->SetData(TYPE_CTHUN_PHASE, 3); - - //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(); - - //Place all units in threat list on outside of stomach - Stomach_Map.clear(); - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) - { - //Outside stomach - Stomach_Map[(*i)->getUnitGuid()] = false; - } - - //Spawn 2 flesh tentacles - FleshTentaclesKilled = 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 (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } - if (!pSpawned) - ++FleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature->GetGUID()); - } + m_lEyeTentaclesList.clear(); + } - //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); + // Wrapper to remove a stored player from the stomach + void DoRemovePlayerFromStomach(Player* pPlayer) + { + if (pPlayer) + m_lPlayersInStomachList.remove(pPlayer->GetObjectGuid()); + } - if (!pSpawned) - ++FleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature->GetGUID()); - } + // Custom threat management + bool SelectHostileTarget() + { + Unit* pTarget = NULL; + Unit* pOldTarget = m_creature->getVictim(); - PhaseTimer = 0; - }else PhaseTimer -= diff; + if (!m_creature->getThreatManager().isThreatListEmpty()) + pTarget = m_creature->getThreatManager().getHostileTarget(); - }break; + if (pTarget) + { + if (pOldTarget != pTarget) + AttackStart(pTarget); - //Body Phase - case 3: + // Set victim to old target + if (pOldTarget && pOldTarget->isAlive()) { - //Remove Target field - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - //Weaken - if (FleshTentaclesKilled > 1) - { - m_pInstance->SetData(TYPE_CTHUN_PHASE, 4); - - DoScriptText(EMOTE_WEAKENED, m_creature); - PhaseTimer = 45000; - - DoCastSpellIfCan(m_creature, SPELL_RED_COLORATION, CAST_TRIGGERED); - - UNORDERED_MAP::iterator i = Stomach_Map.begin(); - - //Kick all players out of stomach - while (i != Stomach_Map.end()) - { - //Check for valid player - Unit* pUnit = m_creature->GetMap()->GetUnit(i->first); - - //Only move units in stomach - if (pUnit && i->second == true) - { - //Teleport each player out - DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+10, rand()%6); + m_creature->SetTargetGuid(pOldTarget->GetObjectGuid()); + m_creature->SetInFront(pOldTarget); + } - //Cast knockback on them - DoCastSpellIfCan(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, CAST_TRIGGERED); + return true; + } - //Remove the acid debuff - pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + // Will call EnterEvadeMode if fit + return m_creature->SelectHostileTarget(); + } - i->second = false; - } - ++i; - } + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectHostileTarget()) + return; - return; - } + switch (m_Phase) + { + case PHASE_TRANSITION: - //Stomach acid - if (StomachAcidTimer < diff) + if (m_uiPhaseTimer < uiDiff) { - //Apply aura to all players in stomach - UNORDERED_MAP::iterator i = Stomach_Map.begin(); + // 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); - while (i != Stomach_Map.end()) + // Transform and start C'thun phase + if (DoCastSpellIfCan(m_creature, SPELL_TRANSFORM) == CAST_OK) { - //Check for valid player - Unit* pUnit = m_creature->GetMap()->GetUnit(i->first); - - //Only apply to units in stomach - if (pUnit && i->second == true) - { - //Cast digestive acid on them - DoCastSpellIfCan(pUnit, SPELL_DIGESTIVE_ACID, CAST_TRIGGERED); - - //Check if player should be kicked from stomach - if (pUnit->IsWithinDist3d(KICK_X, KICK_Y, KICK_Z, 15.0f)) - { - //Teleport each player out - DoTeleportPlayer(pUnit, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+10, rand()%6); - - //Cast knockback on them - DoCastSpellIfCan(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, CAST_TRIGGERED); - - //Remove the acid debuff - pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoSpawnFleshTentacles(); - i->second = false; - } - } - ++i; + m_Phase = PHASE_CTHUN; + m_uiPhaseTimer = 0; } + } + else + m_uiPhaseTimer -= uiDiff; - StomachAcidTimer = 4000; - }else StomachAcidTimer -= diff; + break; + case PHASE_CTHUN: - //Stomach Enter Timer - if (StomachEnterTimer < diff) + if (m_uiMouthTentacleTimer < uiDiff) { - Unit* target = NULL; - target = SelectRandomNotStomach(); - - if (target) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_LOS)) { - //Set target in stomach - Stomach_Map[target->GetGUID()] = true; - target->InterruptNonMeleeSpells(false); - target->CastSpell(target, SPELL_MOUTH_TENTACLE, true, NULL, NULL, m_creature->GetGUID()); - StomachEnterTarget = target->GetGUID(); - StomachEnterVisTimer = 3800; - } - - StomachEnterTimer = 13800; - }else StomachEnterTimer -= diff; + // 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(); - if (StomachEnterVisTimer && StomachEnterTarget) - if (StomachEnterVisTimer <= diff) - { - //Check for valid player - Unit* pUnit = m_creature->GetMap()->GetUnit(StomachEnterTarget); - - if (pUnit) - { - DoTeleportPlayer(pUnit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); + m_uiStomachEnterTimer = 3800; + m_uiMouthTentacleTimer = urand(13000, 15000); } + } + else + m_uiMouthTentacleTimer -= uiDiff; - StomachEnterTarget = 0; - StomachEnterVisTimer = 0; - }else StomachEnterVisTimer -= diff; - - //GientClawTentacleTimer - if (GiantClawTentacleTimer < diff) + // Teleport the target to the stomach after a few seconds + if (m_uiStomachEnterTimer) { - Unit* target = NULL; - target = SelectRandomNotStomach(); - if (target) + if (m_uiStomachEnterTimer <= uiDiff) { - Creature* Spawned = NULL; - - //Spawn claw tentacle on the random target - Spawned = (Creature*)m_creature->SummonCreature(MOB_GIANT_CLAW_TENTACLE,target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,500); + // Check for valid player + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_stomachEnterTargetGuid)) + { + DoTeleportPlayer(pPlayer, afCthunLocations[2][0], afCthunLocations[2][1], afCthunLocations[2][2], afCthunLocations[2][3]); + m_lPlayersInStomachList.push_back(pPlayer->GetObjectGuid()); + } - if (Spawned) - Spawned->AI()->AttackStart(target); + m_stomachEnterTargetGuid.Clear(); + m_uiStomachEnterTimer = 0; } + else + m_uiStomachEnterTimer -= uiDiff; + } - //One giant claw tentacle every minute - GiantClawTentacleTimer = 60000; - }else GiantClawTentacleTimer -= diff; + break; + case PHASE_CTHUN_WEAKENED: - //GiantEyeTentacleTimer - if (GiantEyeTentacleTimer < diff) + // Handle Flesh Tentacles respawn when the vulnerability spell expires + if (m_uiPhaseTimer < uiDiff) { - Unit* target = NULL; - target = SelectRandomNotStomach(); - if (target) - { - - Creature* Spawned = NULL; + DoSpawnFleshTentacles(); - //Spawn claw tentacle on the random target - Spawned = (Creature*)m_creature->SummonCreature(MOB_GIANT_EYE_TENTACLE,target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,500); + m_uiPhaseTimer = 0; + m_Phase = PHASE_CTHUN; + } + else + m_uiPhaseTimer -= uiDiff; - if (Spawned) - Spawned->AI()->AttackStart(target); - } + break; + } - //One giant eye tentacle every minute - GiantEyeTentacleTimer = 60000; - }else GiantEyeTentacleTimer -= diff; + if (m_uiGiantClawTentacleTimer < uiDiff) + { + // 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); - //EyeTentacleTimer - if (EyeTentacleTimer < diff) - { - //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 + m_uiGiantClawTentacleTimer = 60000; + } + else + m_uiGiantClawTentacleTimer -= uiDiff; - SpawnEyeTentacle(0, -25); //north - SpawnEyeTentacle(-12, -12); //north east - SpawnEyeTentacle(-25, 0); // east - SpawnEyeTentacle(-12, 12); // south east + if (m_uiGiantEyeTentacleTimer < uiDiff) + { + // 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); - //These spawn at every 30 seconds - EyeTentacleTimer = 30000; - }else EyeTentacleTimer -= diff; + m_uiGiantEyeTentacleTimer = 60000; + } + else + m_uiGiantEyeTentacleTimer -= uiDiff; - }break; + if (m_uiEyeTentacleTimer < uiDiff) + { + DoDespawnEyeTentacles(); - //Weakened state - case 4: + // Spawn 8 Eye Tentacles every 30 seconds + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_EYE_TENTACLES; ++i) { - //PhaseTimer - if (PhaseTimer < diff) - { - //Switch - m_pInstance->SetData(TYPE_CTHUN_PHASE, 3); - - //Remove red coloration - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - - //Spawn 2 flesh tentacles - FleshTentaclesKilled = 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) - ++FleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature->GetGUID()); - } - - //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) - ++FleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature->GetGUID()); - } - - PhaseTimer = 0; - }else PhaseTimer -= diff; + 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); } - } - } - - void JustDied(Unit* pKiller) - { - //Switch - if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, 5); - } - void DamageTaken(Unit *done_by, uint32 &damage) - { - //No instance - if (!m_pInstance) - return; + m_uiEyeTentacleTimer = 30000; + } + else + m_uiEyeTentacleTimer -= uiDiff; - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + // Note: this should be handled by the maps + if (m_uiDigestiveAcidTimer < uiDiff) { - case 3: + // 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) { - //Not weakened so reduce damage by 99% - if (damage / 99 > 0) damage/= 99; - else damage = 1; - - //Prevent death in non-weakened state - if (damage >= m_creature->GetHealth()) - damage = 0; - - return; + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(*itr)) + pPlayer->CastSpell(pPlayer, SPELL_DIGESTIVE_ACID, true, NULL, NULL, m_creature->GetObjectGuid()); } - break; - - case 4: - { - //Weakened - takes normal damage - return; - } - - default: - damage = 0; - break; + m_uiDigestiveAcidTimer = 4000; } - } - - void FleshTentcleKilled() - { - ++FleshTentaclesKilled; + else + m_uiDigestiveAcidTimer -= uiDiff; } }; -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)) - Portal = pPortal->GetGUID(); - } +/*###### +## npc_giant_claw_tentacle +######*/ - uint32 MindflayTimer; - uint32 KillSelfTimer; - uint64 Portal; - - void JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(Portal)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - - void Reset() - { - //Mind flay half a second after we spawn - MindflayTimer = 500; - - //This prevents eyes from overlapping - KillSelfTimer = 35000; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //KillSelfTimer - if (KillSelfTimer < diff) - { - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - - return; - }else KillSelfTimer -= diff; - - //MindflayTimer - if (MindflayTimer < diff) - { - 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); - - //Mindflay every 10 seconds - MindflayTimer = 10100; - }else MindflayTimer -= diff; - } -}; - -struct MANGOS_DLL_DECL claw_tentacleAI : public ScriptedAI +struct MANGOS_DLL_DECL npc_giant_claw_tentacleAI : public Scripted_NoMovementAI { - 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_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = pPortal->GetGUID(); } - uint32 GroundRuptureTimer; - uint32 HamstringTimer; - uint32 EvadeTimer; - uint64 Portal; + ScriptedInstance* m_pInstance; - void JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(Portal)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } + uint32 m_uiThrashTimer; + uint32 m_uiHamstringTimer; + uint32 m_uiDistCheckTimer; void Reset() { - //First rupture should happen half a second after we spawn - GroundRuptureTimer = 500; - HamstringTimer = 2000; - EvadeTimer = 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 diff) + void UpdateAI(const uint32 uiDiff) override { - //Check if we have a target + // Check if we have a target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //EvadeTimer - if (!m_creature->IsWithinDist(m_creature->getVictim(), ATTACK_DISTANCE)) - if (EvadeTimer < diff) + if (m_uiDistCheckTimer < uiDiff) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(Portal)) - 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) + // 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) { - 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)) - { - m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = pPortal->GetGUID(); + if (Creature* pCthun = m_pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) + { + 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); - GroundRuptureTimer = 500; - HamstringTimer = 2000; - EvadeTimer = 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; + } + } } + else + m_uiDistCheckTimer = 5000; + } + else + m_uiDistCheckTimer -= uiDiff; - m_creature->SetVisibility(VISIBILITY_ON); - - }else EvadeTimer -= diff; - - //GroundRuptureTimer - if (GroundRuptureTimer < diff) + if (m_uiThrashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GROUND_RUPTURE); - GroundRuptureTimer = 30000; - }else GroundRuptureTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_THRASH) == CAST_OK) + m_uiThrashTimer = 10000; + } + else + m_uiThrashTimer -= uiDiff; - //HamstringTimer - if (HamstringTimer < diff) + if (m_uiHamstringTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HAMSTRING); - HamstringTimer = 5000; - }else HamstringTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING) == CAST_OK) + m_uiHamstringTimer = 10000; + } + else + m_uiHamstringTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL giant_claw_tentacleAI : public ScriptedAI +/*###### +## at_stomach_cthun +######*/ + +bool AreaTrigger_at_stomach_cthun(Player* pPlayer, AreaTriggerEntry const* pAt) { - giant_claw_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) + if (pAt->id == AREATRIGGER_STOMACH_1) { - SetCombatMovement(false); - Reset(); + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; - if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = pPortal->GetGUID(); - } - - uint32 GroundRuptureTimer; - uint32 ThrashTimer; - uint32 HamstringTimer; - uint32 EvadeTimer; - uint64 Portal; + // 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 JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(Portal)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + // 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 Reset() - { - //First rupture should happen half a second after we spawn - GroundRuptureTimer = 500; - HamstringTimer = 2000; - ThrashTimer = 5000; - EvadeTimer = 5000; - } - - void Aggro(Unit* pWho) + else if (pAt->id == AREATRIGGER_STOMACH_2) { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //EvadeTimer - if (m_creature->IsWithinDist(m_creature->getVictim(), ATTACK_DISTANCE)) - if (EvadeTimer < diff) + if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(Portal)) - 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 = pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) { - m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + // Remove player from the Stomach + if (boss_cthunAI* pBossAI = dynamic_cast(pCthun->AI())) + pBossAI->DoRemovePlayerFromStomach(pPlayer); - if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = pPortal->GetGUID(); + // 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)); - GroundRuptureTimer = 500; - HamstringTimer = 2000; - ThrashTimer = 5000; - EvadeTimer = 5000; - AttackStart(target); + // Note: the real knockback spell id should be 26230 + pPlayer->CastSpell(pPlayer, SPELL_EXIT_STOMACH_KNOCKBACK, true, NULL, NULL, pCthun->GetObjectGuid()); } - - m_creature->SetVisibility(VISIBILITY_ON); - - }else EvadeTimer -= diff; - - //GroundRuptureTimer - if (GroundRuptureTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GROUND_RUPTURE); - GroundRuptureTimer = 30000; - }else GroundRuptureTimer -= diff; - - //ThrashTimer - if (ThrashTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_THRASH); - ThrashTimer = 10000; - }else ThrashTimer -= diff; - - //HamstringTimer - if (HamstringTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HAMSTRING); - HamstringTimer = 10000; - }else HamstringTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -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)) - Portal = pPortal->GetGUID(); - } - - uint32 BeamTimer; - uint64 Portal; - - void JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(Portal)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - - void Reset() - { - //Green Beam half a second after we spawn - BeamTimer = 500; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 diff) - { - //Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //BeamTimer - if (BeamTimer < diff) - { - 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 - BeamTimer = 2100; - }else BeamTimer -= diff; - } -}; - -//Flesh tentacle functions -void flesh_tentacleAI::UpdateAI(const uint32 diff) -{ - //Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (Parent) - if (CheckTimer < diff) - { - Creature* pParent = m_creature->GetMap()->GetCreature(Parent); - - if (!pParent || !pParent->isAlive() || !pParent->isInCombat()) - { - Parent = 0; - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - return; } - - CheckTimer = 1000; - }else CheckTimer -= diff; - - DoMeleeAttackIfReady(); -} - -void flesh_tentacleAI::JustDied(Unit* killer) -{ - if (!Parent) - { - error_log("SD2: flesh_tentacle: No Parent variable"); - return; } - if (Creature* pCthun = m_creature->GetMap()->GetCreature(Parent)) - { - 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 *newscript; - - //Eye - newscript = new Script; - newscript->Name = "boss_eye_of_cthun"; - newscript->GetAI = &GetAI_eye_of_cthun; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_cthun"; - newscript->GetAI = &GetAI_cthun; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_eye_tentacle"; - newscript->GetAI = &GetAI_eye_tentacle; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_claw_tentacle"; - newscript->GetAI = &GetAI_claw_tentacle; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_giant_claw_tentacle"; - newscript->GetAI = &GetAI_giant_claw_tentacle; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_giant_eye_tentacle"; - newscript->GetAI = &GetAI_giant_eye_tentacle; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_giant_flesh_tentacle"; - newscript->GetAI = &GetAI_flesh_tentacle; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_eye_of_cthun"; + pNewScript->GetAI = &GetAI_boss_eye_of_cthun; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_cthun"; + pNewScript->GetAI = &GetAI_boss_cthun; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_giant_claw_tentacle"; + pNewScript->GetAI = &GetAI_npc_giant_claw_tentacle; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 7ff51e8ee7..b606b5c3e2 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,161 +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 { - boss_fankrissAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_fankrissAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; - uint32 MortalWound_Timer; - uint32 SpawnHatchlings_Timer; - uint32 SpawnSpawns_Timer; - int Rand; - int RandX; - int RandY; + uint32 m_uiMortalWoundTimer; + uint32 m_uiSummonWormTimer; + uint32 m_uiEntangleTimer; + uint32 m_uiEntangleSummonTimer; - Creature* Hatchling; - Creature* Spawn; + ObjectGuid m_EntangleTargetGuid; void Reset() { - MortalWound_Timer = urand(10000, 15000); - SpawnHatchlings_Timer = urand(6000, 12000); - SpawnSpawns_Timer = urand(15000, 45000); + m_uiMortalWoundTimer = urand(10000, 15000); + m_uiSummonWormTimer = urand(30000, 50000); + m_uiEntangleTimer = urand(25000, 40000); + m_uiEntangleSummonTimer = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FANKRISS, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FANKRISS, FAIL); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FANKRISS, DONE); } - void SummonSpawn(Unit* pVictim) + void JustSummoned(Creature* pSummoned) override { - Rand = 10 + (rand()%10); - switch(urand(0, 1)) + 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); - }else SpawnSpawns_Timer -= diff; + uint8 uiSpawnIndex = urand(0, 2); + if (DoCastSpellIfCan(m_creature, aSummonWormSpells[uiSpawnIndex]) == CAST_OK) + m_uiSummonWormTimer = urand(15000, 40000); + } + else + 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)) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + uint8 uiEntangleIndex = urand(0, 2); + if (DoCastSpellIfCan(pTarget, aEntangleSpells[uiEntangleIndex]) == CAST_OK) { - DoCastSpellIfCan(target, SPELL_ROOT); - - if (m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -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(target, -8106.0142f, 1289.2900f, -74.419533f, 5.112f); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - break; - case 1: - DoTeleportPlayer(target, -7990.135354f, 1155.1907f, -78.849319f, 2.608f); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - break; - case 2: - DoTeleportPlayer(target, -8159.7753f, 1127.9064f, -76.868660f, 0.675f); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()-3, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-3, target->GetPositionY()+3, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()-5, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = m_creature->SummonCreature(15962, target->GetPositionX()-5, target->GetPositionY()+5, target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - 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); } + m_uiEntangleSummonTimer = 0; } - SpawnHatchlings_Timer = urand(45000, 60000); - }else SpawnHatchlings_Timer -= diff; + } + else + m_uiEntangleSummonTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -190,9 +174,10 @@ CreatureAI* GetAI_boss_fankriss(Creature* pCreature) void AddSC_boss_fankriss() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_fankriss"; - newscript->GetAI = &GetAI_boss_fankriss; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_fankriss"; + pNewScript->GetAI = &GetAI_boss_fankriss; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp index 655ebfd766..b3eac775d8 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,112 +16,129 @@ /* ScriptData SDName: Boss_Huhuran -SD%Complete: 100 -SDComment: +SD%Complete: 90 +SDComment: Timed enrage NYI; Timers SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" -#define EMOTE_GENERIC_FRENZY_KILL -1000001 -#define EMOTE_GENERIC_BERSERK -1000004 - -#define SPELL_FRENZY 26051 -#define SPELL_BERSERK 26068 -#define SPELL_POISONBOLT 26052 -#define SPELL_NOXIOUSPOISON 26053 -#define SPELL_WYVERNSTING 26180 -#define SPELL_ACIDSPIT 26050 +enum +{ + EMOTE_GENERIC_FRENZY_KILL = -1000001, + EMOTE_GENERIC_BERSERK = -1000004, + + SPELL_ENRAGE = 26051, // triggers 26052 + SPELL_BERSERK = 26068, // triggers 26052 + SPELL_NOXIOUS_POISON = 26053, + SPELL_WYVERN_STING = 26180, + SPELL_ACID_SPIT = 26050 +}; struct MANGOS_DLL_DECL 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 Frenzy_Timer; - uint32 Wyvern_Timer; - uint32 Spit_Timer; - uint32 PoisonBolt_Timer; - uint32 NoxiousPoison_Timer; - uint32 FrenzyBack_Timer; + uint32 m_uiFrenzyTimer; + uint32 m_uiWyvernTimer; + uint32 m_uiSpitTimer; + uint32 m_uiNoxiousPoisonTimer; - bool Frenzy; - bool Berserk; + bool m_bIsBerserk; void Reset() { - Frenzy_Timer = urand(25000, 35000); - Wyvern_Timer = urand(18000, 28000); - Spit_Timer = 8000; - PoisonBolt_Timer = 4000; - NoxiousPoison_Timer = urand(10000, 20000); - FrenzyBack_Timer = 15000; - - Frenzy = false; - Berserk = false; + m_uiFrenzyTimer = urand(25000, 35000); + m_uiWyvernTimer = urand(18000, 28000); + m_uiSpitTimer = 8000; + m_uiNoxiousPoisonTimer = urand(10000, 20000); + m_bIsBerserk = false; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HUHURAN, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - //Return since we have no target + 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()) return; - //Frenzy_Timer - if (!Frenzy && Frenzy_Timer < diff) + // Frenzy_Timer + if (!m_bIsBerserk) { - DoCastSpellIfCan(m_creature, SPELL_FRENZY); - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - Frenzy = true; - PoisonBolt_Timer = 3000; - Frenzy_Timer = urand(25000, 35000); - }else Frenzy_Timer -= diff; + if (m_uiFrenzyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); + m_uiFrenzyTimer = urand(25000, 35000); + } + } + else + m_uiFrenzyTimer -= uiDiff; + } // Wyvern Timer - if (Wyvern_Timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_WYVERNSTING); - Wyvern_Timer = urand(15000, 32000); - }else Wyvern_Timer -= diff; - - //Spit Timer - if (Spit_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ACIDSPIT); - Spit_Timer = urand(5000, 10000); - }else Spit_Timer -= diff; - - //NoxiousPoison_Timer - if (NoxiousPoison_Timer < diff) + if (m_uiWyvernTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_NOXIOUSPOISON); - NoxiousPoison_Timer = urand(12000, 24000); - }else NoxiousPoison_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_WYVERN_STING) == CAST_OK) + m_uiWyvernTimer = urand(15000, 32000); + } + } + else + m_uiWyvernTimer -= uiDiff; - //PoisonBolt only if frenzy or berserk - if (Frenzy || Berserk) + // Spit Timer + if (m_uiSpitTimer < uiDiff) { - if (PoisonBolt_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_POISONBOLT); - PoisonBolt_Timer = 3000; - }else PoisonBolt_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ACID_SPIT) == CAST_OK) + m_uiSpitTimer = urand(5000, 10000); } + else + m_uiSpitTimer -= uiDiff; - //FrenzyBack_Timer - if (Frenzy && FrenzyBack_Timer < diff) + // NoxiousPoison_Timer + if (m_uiNoxiousPoisonTimer < uiDiff) { - m_creature->InterruptNonMeleeSpells(false); - Frenzy = false; - FrenzyBack_Timer = 15000; - }else FrenzyBack_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_NOXIOUS_POISON) == CAST_OK) + m_uiNoxiousPoisonTimer = urand(12000, 24000); + } + else + m_uiNoxiousPoisonTimer -= uiDiff; - if (!Berserk && m_creature->GetHealthPercent() < 31.0f) + // Berserk + if (!m_bIsBerserk && m_creature->GetHealthPercent() < 30.0f) { - m_creature->InterruptNonMeleeSpells(false); - DoScriptText(EMOTE_GENERIC_BERSERK, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - Berserk = true; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_BERSERK, m_creature); + m_bIsBerserk = true; + } } DoMeleeAttackIfReady(); @@ -135,9 +152,10 @@ CreatureAI* GetAI_boss_huhuran(Creature* pCreature) void AddSC_boss_huhuran() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_huhuran"; - newscript->GetAI = &GetAI_boss_huhuran; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_huhuran"; + pNewScript->GetAI = &GetAI_boss_huhuran; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp index 39b8a0b916..e3431a9f41 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,111 @@ 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, - - SPELL_DIRTMOUND_PASSIVE = 26092, + // emerge spells + SPELL_BIRTH = 26262, // The Birth Animation + SPELL_GROUND_RUPTURE = 26100, // spell not confirmed + SPELL_SUMMON_BASE = 26133, // summons gameobject 180795 + + // submerge spells SPELL_SUBMERGE_VISUAL = 26063, - - NPC_OURO_SCARAB = 15718, - NPC_OURO_SPAWNER = 15957, - NPC_OURO_TRIGGER = 15717 + SPELL_SUMMON_OURO_MOUND = 26058, // summons 5 dirt mounds + SPELL_SUMMON_TRIGGER = 26284, + + SPELL_SUMMON_OURO = 26642, + 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 MANGOS_DLL_DECL 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; + ObjectGuid m_ouroTriggerGuid; + void Reset() { - 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; + 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 Aggro(Unit* pWho) + void JustDied(Unit* /*pKiller*/) override { - DoCastSpellIfCan(m_creature, SPELL_BIRTH); + if (m_pInstance) + m_pInstance->SetData(TYPE_OURO, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override + { + 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) override { // Return since we have no pTarget if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -85,11 +138,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,82 +163,163 @@ 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; } + else + { + // Summon 1 mound every 10 secs when enraged + if (m_uiSummonMoundTimer < uiDiff) + { + DoSpawnCreature(NPC_DIRT_MOUND, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_uiSummonMoundTimer = 10000; + } + else + m_uiSummonMoundTimer -= uiDiff; + } - DoMeleeAttackIfReady(); + // 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) + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_BOULDER); + } + } } else { - // Change Target - if (m_uiChangeTargetTimer < uiDiff) + // Resume combat + if (m_uiSubmergeTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + // 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); + + if (DoCastSpellIfCan(m_creature, SPELL_BIRTH) == CAST_OK) { - m_creature->GetMap()->CreatureRelocation(m_creature, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f); - m_creature->SendMonsterMove(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, 1); - } + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_uiChangeTargetTimer = urand(10000, 20000); + m_bSubmerged = false; + m_uiSummonBaseTimer = 2000; + m_uiSubmergeTimer = 90000; + } } else - m_uiChangeTargetTimer -= uiDiff; + m_uiSubmergeTimer -= uiDiff; + } + } +}; - // Back - if (m_uiBackTimer < uiDiff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); +CreatureAI* GetAI_boss_ouro(Creature* pCreature) +{ + return new boss_ouroAI(pCreature); +} - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GROUND_RUPTURE); +struct MANGOS_DLL_DECL npc_ouro_spawnerAI : public Scripted_NoMovementAI +{ + npc_ouro_spawnerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} + + uint32 m_uiQuakeTimer; + bool m_bHasSummoned; - m_bSubmerged = false; - m_uiSubmergeTimer = urand(60000, 120000); + void Reset() + { + m_uiQuakeTimer = 1000; + m_bHasSummoned = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + // Spawn Ouro on LoS check + if (!m_bHasSummoned && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, 50.0f)) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_OURO) == CAST_OK) + m_bHasSummoned = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + 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 + { + if (m_bHasSummoned) + { + if (m_uiQuakeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_QUAKE) == CAST_OK) + m_uiQuakeTimer = 1000; } else - m_uiBackTimer -= uiDiff; + m_uiQuakeTimer -= uiDiff; } } }; -CreatureAI* GetAI_boss_ouro(Creature* pCreature) +CreatureAI* GetAI_npc_ouro_spawner(Creature* pCreature) { - return new boss_ouroAI(pCreature); + return new npc_ouro_spawnerAI(pCreature); } void AddSC_boss_ouro() { - Script* newscript; - newscript = new Script; - newscript->Name = "boss_ouro"; - newscript->GetAI = &GetAI_boss_ouro; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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 c60fccdd1a..5b7ecd0af7 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,248 +22,276 @@ SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" -#define SAY_AGGRO -1531008 -#define SAY_SLAY -1531009 -#define SAY_DEATH -1531010 +enum +{ + SAY_AGGRO = -1531008, + SAY_SLAY = -1531009, + SAY_DEATH = -1531010, -#define SPELL_WHIRLWIND 26083 -#define SPELL_ENRAGE 28747 //Not sure if right ID. -#define SPELL_ENRAGEHARD 28798 + SPELL_WHIRLWIND = 26083, + SPELL_ENRAGE = 28747, // Not sure if right ID. + SPELL_ENRAGEHARD = 28798, -//Guard Spell -#define SPELL_WHIRLWINDADD 26038 -#define SPELL_KNOCKBACK 26027 + // Guard Spell + SPELL_WHIRLWIND_ADD = 26038, + SPELL_KNOCKBACK = 26027, +}; struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI { - boss_sarturaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_sarturaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } - uint32 WhirlWind_Timer; - uint32 WhirlWindRandom_Timer; - uint32 WhirlWindEnd_Timer; - uint32 AggroReset_Timer; - uint32 AggroResetEnd_Timer; - uint32 EnrageHard_Timer; + ScriptedInstance* m_pInstance; - bool Enraged; - bool EnragedHard; - bool WhirlWind; - bool AggroReset; + uint32 m_uiWhirlWindTimer; + uint32 m_uiWhirlWindRandomTimer; + uint32 m_uiWhirlWindEndTimer; + uint32 m_uiAggroResetTimer; + uint32 m_uiAggroResetEndTimer; + uint32 m_uiEnrageHardTimer; + + bool m_bIsEnraged; void Reset() { - WhirlWind_Timer = 30000; - WhirlWindRandom_Timer = urand(3000, 7000); - WhirlWindEnd_Timer = 15000; - AggroReset_Timer = urand(45000, 55000); - AggroResetEnd_Timer = 5000; - EnrageHard_Timer = 10*60000; - - WhirlWind = false; - AggroReset = false; - Enraged = false; - EnragedHard = false; - + m_uiWhirlWindTimer = 30000; + m_uiWhirlWindRandomTimer = urand(3000, 7000); + m_uiWhirlWindEndTimer = 0; + m_uiAggroResetTimer = urand(45000, 55000); + m_uiAggroResetEndTimer = 0; + m_uiEnrageHardTimer = 10 * 60000; + + m_bIsEnraged = false; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTURA, IN_PROGRESS); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY, m_creature); } - void JustDied(Unit* Killer) + 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (WhirlWind) + if (m_uiWhirlWindEndTimer) // Is in Whirlwind { - if (WhirlWindRandom_Timer < diff) + // While whirlwind, switch to random targets often + if (m_uiWhirlWindRandomTimer < uiDiff) { - //Attack random Gamers - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); - if (target) - m_creature->AddThreat(target); - m_creature->TauntApply(target); - AttackStart(target); - - WhirlWindRandom_Timer = urand(3000, 7000); - }else WhirlWindRandom_Timer -= diff; - - if (WhirlWindEnd_Timer < diff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->FixateTarget(pTarget); + + m_uiWhirlWindRandomTimer = urand(3000, 7000); + } + else + m_uiWhirlWindRandomTimer -= uiDiff; + + // End Whirlwind Phase + if (m_uiWhirlWindEndTimer <= uiDiff) { - WhirlWind = false; - WhirlWind_Timer = urand(25000, 40000); - }else WhirlWindEnd_Timer -= diff; + m_creature->FixateTarget(NULL); + m_uiWhirlWindEndTimer = 0; + m_uiWhirlWindTimer = urand(25000, 40000); + } + else + m_uiWhirlWindEndTimer -= uiDiff; } - - if (!WhirlWind) + else // if (!m_uiWhirlWindEndTimer) // Is not in whirlwind { - if (WhirlWind_Timer < diff) + // Enter Whirlwind Phase + if (m_uiWhirlWindTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - WhirlWind = true; - WhirlWindEnd_Timer = 15000; - }else WhirlWind_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + { + m_uiWhirlWindEndTimer = 15000; + m_uiWhirlWindRandomTimer = 500; + } + } + else + m_uiWhirlWindTimer -= uiDiff; - if (AggroReset_Timer < diff) - { - //Attack random Gamers - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); - if (target) - m_creature->AddThreat(target); - m_creature->TauntApply(target); - AttackStart(target); - - AggroReset = true; - AggroReset_Timer = urand(2000, 5000); - }else AggroReset_Timer -= diff; - - if (AggroReset) + // Aquire a new target sometimes + if (!m_uiAggroResetEndTimer) // No random target picket { - if (AggroResetEnd_Timer SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + m_creature->FixateTarget(pTarget); - //If she is 20% enrage - if (!Enraged) + m_uiAggroResetEndTimer = 5000; + } + else + m_uiAggroResetTimer -= uiDiff; + } + else // Reset from recent random target { - if (m_creature->GetHealthPercent() <= 20.0f && !m_creature->IsNonMeleeSpellCasted(false)) + // Remove remaining taunts + if (m_uiAggroResetEndTimer <= uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - Enraged = true; + m_creature->FixateTarget(NULL); + m_uiAggroResetEndTimer = 0; + m_uiAggroResetTimer = urand(35000, 45000); } + else + m_uiAggroResetEndTimer -= uiDiff; } + } + + // If she is 20% enrage + if (!m_bIsEnraged && m_creature->GetHealthPercent() <= 20.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE, m_uiWhirlWindEndTimer ? CAST_TRIGGERED : 0) == CAST_OK) + m_bIsEnraged = true; + } - //After 10 minutes hard enrage - if (!EnragedHard) + // After 10 minutes hard enrage + if (m_uiEnrageHardTimer) + { + if (m_uiEnrageHardTimer <= uiDiff) { - if (EnrageHard_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGEHARD); - EnragedHard = true; - } else EnrageHard_Timer -= diff; + 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_uiWhirlWindEndTimer) DoMeleeAttackIfReady(); - } } }; struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI { - mob_sartura_royal_guardAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 WhirlWind_Timer; - uint32 WhirlWindRandom_Timer; - uint32 WhirlWindEnd_Timer; - uint32 AggroReset_Timer; - uint32 AggroResetEnd_Timer; - uint32 KnockBack_Timer; + mob_sartura_royal_guardAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool WhirlWind; - bool AggroReset; + uint32 m_uiWhirlWindTimer; + uint32 m_uiWhirlWindRandomTimer; + uint32 m_uiWhirlWindEndTimer; + uint32 m_uiAggroResetTimer; + uint32 m_uiAggroResetEndTimer; + uint32 m_uiKnockBackTimer; void Reset() { - WhirlWind_Timer = 30000; - WhirlWindRandom_Timer = urand(3000, 7000); - WhirlWindEnd_Timer = 15000; - AggroReset_Timer = urand(45000, 55000); - AggroResetEnd_Timer = 5000; - KnockBack_Timer = 10000; - - WhirlWind = false; - AggroReset = false; - + m_uiWhirlWindTimer = 30000; + m_uiWhirlWindRandomTimer = urand(3000, 7000); + m_uiWhirlWindEndTimer = 0; + m_uiAggroResetTimer = urand(45000, 55000); + m_uiAggroResetEndTimer = 0; + m_uiKnockBackTimer = 10000; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!WhirlWind && WhirlWind_Timer < diff) + if (m_uiWhirlWindEndTimer) // Is in Whirlwind { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWINDADD); - WhirlWind = true; - WhirlWind_Timer = urand(25000, 40000); - WhirlWindEnd_Timer = 15000; - }else WhirlWind_Timer -= diff; - - if (WhirlWind) - { - if (WhirlWindRandom_Timer < diff) + // While whirlwind, switch to random targets often + if (m_uiWhirlWindRandomTimer < uiDiff) { - //Attack random Gamers - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); - if (target) - m_creature->AddThreat(target); - m_creature->TauntApply(target); - AttackStart(target); - - WhirlWindRandom_Timer = urand(3000, 7000); - }else WhirlWindRandom_Timer -= diff; - - if (WhirlWindEnd_Timer < diff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->FixateTarget(pTarget); + + m_uiWhirlWindRandomTimer = urand(3000, 7000); + } + else + m_uiWhirlWindRandomTimer -= uiDiff; + + // End Whirlwind Phase + if (m_uiWhirlWindEndTimer <= uiDiff) { - WhirlWind = false; - }else WhirlWindEnd_Timer -= diff; + m_creature->FixateTarget(NULL); + m_uiWhirlWindEndTimer = 0; + m_uiWhirlWindTimer = urand(25000, 40000); + } + else + m_uiWhirlWindEndTimer -= uiDiff; } - - if (!WhirlWind) + else // if (!m_uiWhirlWindEndTimer) // Is not in Whirlwind { - if (AggroReset_Timer < diff) + // Enter Whirlwind Phase + if (m_uiWhirlWindTimer < uiDiff) { - //Attack random Gamers - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); - if (target) - m_creature->AddThreat(target); - m_creature->TauntApply(target); - AttackStart(target); - - AggroReset = true; - AggroReset_Timer = urand(2000, 5000); - }else AggroReset_Timer -= diff; - - if (KnockBack_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND_ADD) == CAST_OK) + { + m_uiWhirlWindEndTimer = 8000; + m_uiWhirlWindRandomTimer = 500; + } + } + else + m_uiWhirlWindTimer -= uiDiff; + + // Aquire a new target sometimes + if (!m_uiAggroResetEndTimer) // No random target picket { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWINDADD); - KnockBack_Timer = urand(10000, 20000); - }else KnockBack_Timer -= diff; - } + if (m_uiAggroResetTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + m_creature->FixateTarget(pTarget); - if (AggroReset) - { - if (AggroResetEnd_Timer FixateTarget(NULL); + m_uiAggroResetEndTimer = 0; + m_uiAggroResetTimer = urand(30000, 40000); + } + else + m_uiAggroResetEndTimer -= uiDiff; + } + + // Knockback nearby enemies + if (m_uiKnockBackTimer < uiDiff) { - AggroReset = false; - AggroResetEnd_Timer = 5000; - AggroReset_Timer = urand(30000, 40000); - } else AggroResetEnd_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_KNOCKBACK) == CAST_OK) + m_uiKnockBackTimer = urand(10000, 20000); + } + else + m_uiKnockBackTimer -= uiDiff; } - DoMeleeAttackIfReady(); + // No melee damage while in whirlwind + if (!m_uiWhirlWindEndTimer) + DoMeleeAttackIfReady(); } }; @@ -279,14 +307,15 @@ CreatureAI* GetAI_mob_sartura_royal_guard(Creature* pCreature) void AddSC_boss_sartura() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_sartura"; - newscript->GetAI = &GetAI_boss_sartura; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_sartura_royal_guard"; - newscript->GetAI = &GetAI_mob_sartura_royal_guard; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_sartura"; + pNewScript->GetAI = &GetAI_boss_sartura; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_sartura_royal_guard"; + pNewScript->GetAI = &GetAI_mob_sartura_royal_guard; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp index 53762245ff..ef15bd0947 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,37 +16,33 @@ /* 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 @@ -54,49 +50,40 @@ struct MANGOS_DLL_DECL 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() { - 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,190 +91,149 @@ 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(); } - 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; case 2: DoScriptText(SAY_AGGRO3, m_creature); break; } + + if (m_pInstance) + m_pInstance->SetData(TYPE_SKERAM, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_SKERAM, FAIL); - //ArcaneExplosion_Timer - if (ArcaneExplosion_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - ArcaneExplosion_Timer = urand(8000, 18000); - }else ArcaneExplosion_Timer -= diff; - - //If we are within range melee the target - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - //Make sure our attack is ready and we arn't currently casting - if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - }else - { - //EarthShock_Timer - if (EarthShock_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_EARTH_SHOCK); - EarthShock_Timer = 1000; - }else EarthShock_Timer -= diff; - } - - //Blink_Timer - if (Blink_Timer < diff) - { - //DoCastSpellIfCan(m_creature, SPELL_BLINK); - 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; - } - DoStopAttack(); - - Blink_Timer = urand(20000, 40000); - }else Blink_Timer -= diff; - - float procent = m_creature->GetHealthPercent(); + if (m_bIsImage) + m_creature->ForcedDespawn(); + } - //Summoning 2 Images and teleporting to a random position on 75% health - if (!Images75 && !IsImage && procent <= 75.0f && procent > 70.0f) - DoSplit(75); + void JustSummoned(Creature* pSummoned) override + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); - //Summoning 2 Images and teleporting to a random position on 50% health - if (!Images50 && !IsImage && procent <= 50.0f && procent > 45.0f) - DoSplit(50); + DoCastSpellIfCan(pSummoned, SPELL_INITIALIZE_IMAGE, CAST_TRIGGERED); + } - //Summoning 2 Images and teleporting to a random position on 25% health - if (!Images25 && !IsImage && procent <= 25.0f && procent > 20.0f) - DoSplit(25); + // Wrapper to handle the image version initialize + void DoInitializeImage() + { + if (!m_pInstance) + return; - //Invisible_Timer - if (Invisible) + // Initialize the health of the clone + if (Creature* pProphet = m_pInstance->GetSingleCreatureFromStorage(NPC_SKERAM)) { - if (Invisible_Timer < diff) - { - //Making Skeram visible after telporting - m_creature->SetVisibility(VISIBILITY_ON); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - Invisible_Timer = 2500; - Invisible = false; - }else Invisible_Timer -= diff; + 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); } - - DoMeleeAttackIfReady(); } - void DoSplit(int atPercent /* 75 50 25 */) + void UpdateAI(const uint32 uiDiff) override { - 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; + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - switch(urand(0, 2)) + // ArcaneExplosion_Timer + if (m_uiArcaneExplosionTimer < uiDiff) { - 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_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = urand(8000, 18000); } + else + m_uiArcaneExplosionTimer -= uiDiff; - 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) + // True Fullfilment + if (m_uiFullFillmentTimer < uiDiff) { - case 75: Images75 = true; break; - case 50: Images50 = true; break; - case 25: Images25 = true; break; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_TRUE_FULFILLMENT) == CAST_OK) + m_uiFullFillmentTimer = urand(20000, 30000); + } } + else + m_uiFullFillmentTimer -= uiDiff; - 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) + // Blink_Timer + if (m_uiBlinkTimer < uiDiff) { - Image1->SetMaxHealth(m_creature->GetMaxHealth() / 5); - Image1->SetHealth(m_creature->GetHealth() / 5); + switch (urand(0, 2)) + { + 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; + } - if (target) - Image1->AI()->AttackStart(target); + DoResetThreat(); + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); - if (boss_skeramAI* pImageAI = dynamic_cast(Image1->AI())) - pImageAI->IsImage = true; + m_uiBlinkTimer = urand(10000, 30000); } + else + m_uiBlinkTimer -= uiDiff; - Image2 = m_creature->SummonCreature(15263,i2->x, i2->y, i2->z, i2->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); - if (Image2) + // Summon images at 75%, 50% and 25% + if (!m_bIsImage && m_creature->GetHealthPercent() < m_fHpCheck) { - Image2->SetMaxHealth(m_creature->GetMaxHealth() / 5); - Image2->SetHealth(m_creature->GetHealth() / 5); - - if (target) - Image2->AI()->AttackStart(target); - - if (boss_skeramAI* pImageAI = dynamic_cast(Image2->AI())) - pImageAI->IsImage = true; + 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; + } } - - Invisible = true; - delete place1; - delete place2; - delete place3; + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + else + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_EARTH_SHOCK); + } + } } }; @@ -296,11 +242,35 @@ CreatureAI* GetAI_boss_skeram(Creature* pCreature) return new boss_skeramAI(pCreature); } +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()) + { + if (Creature* pProphet = pInstance->GetSingleCreatureFromStorage(NPC_SKERAM)) + { + if (pProphet == pCreatureTarget) + return false; + } + } + + if (boss_skeramAI* pSkeramAI = dynamic_cast(pCreatureTarget->AI())) + pSkeramAI->DoInitializeImage(); + } + + return false; +} + void AddSC_boss_skeram() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_skeram"; - newscript->GetAI = &GetAI_boss_skeram; - newscript->RegisterSelf(); + Script* pNewScript; + + 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 785ef75d40..1256ef6146 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,613 +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 MANGOS_DLL_DECL 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() { - if (m_pInstance) - { - return m_creature->GetMap()->GetCreature(m_pInstance->GetData64(IAmVeklor() ? DATA_VEKNILASH : DATA_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 KilledUnit(Unit* victim) + void JustDied(Unit* /*pKiller*/) override { - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_KILL : SOUND_VN_KILL); + if (m_pInstance) + m_pInstance->SetData(TYPE_TWINS, DONE); } - void Aggro(Unit* pWho) + void JustReachedHome() override { - m_creature->SetInCombatWithZone(); + if (m_pInstance) + m_pInstance->SetData(TYPE_TWINS, FAIL); + } - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + 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); } } - void SpellHit(Unit *caster, const SpellEntry *entry) + // 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 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); - - uint32 myh = m_creature->GetHealth(); - uint32 hish = pOtherBoss->GetHealth(); - 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; - - 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()); +struct MANGOS_DLL_DECL boss_veknilashAI : public boss_twin_emperorsAI +{ + boss_veknilashAI(Creature* pCreature) : boss_twin_emperorsAI(pCreature) { Reset(); } - if (m_creature->IsWithinDistInMap(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; - } + uint32 m_uiUppercutTimer; + uint32 m_uiUnbalancingStrikeTimer; - Unit *PickNearestPlayer() + void Reset() { - 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()); - - if (!pUnit) - continue; + boss_twin_emperorsAI::Reset(); - 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, 0); - 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 MANGOS_DLL_DECL 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; - - Creature* Summoned; + uint32 m_uiShadowBoltTimer; + uint32 m_uiBlizzardTimer; + uint32 m_uiArcaneBurstTimer; void Reset() { - 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; - - //UnbalancingStrike_Timer - if (UnbalancingStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_UNBALANCING_STRIKE); - UnbalancingStrike_Timer = urand(8000, 20000); - }else UnbalancingStrike_Timer -= diff; + boss_twin_emperorsAI::Aggro(pWho); - if (UpperCut_Timer < diff) + switch (urand(0, 3)) { - Unit* randomMelee = GetAnyoneCloseEnough(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(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; } }; @@ -639,15 +426,15 @@ CreatureAI* GetAI_boss_veklor(Creature* pCreature) void AddSC_boss_twinemperors() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_veknilash"; - newscript->GetAI = &GetAI_boss_veknilash; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_veknilash"; + pNewScript->GetAI = &GetAI_boss_veknilash; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_veklor"; - newscript->GetAI = &GetAI_boss_veklor; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_veklor"; + pNewScript->GetAI = &GetAI_boss_veklor; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp index d2e27e609b..dcc82bb217 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,14 +16,118 @@ /* ScriptData SDName: Boss_Viscidus -SD%Complete: 0 -SDComment: place holder +SD%Complete: 40 +SDComment: Only basic spells - freeze and explode events require more research SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" -#define SPELL_POISON_SHOCK 25993 -#define SPELL_POISONBOLT_VOLLEY 25991 +enum +{ + // Timer spells + SPELL_POISON_SHOCK = 25993, + SPELL_POISONBOLT_VOLLEY = 25991, + SPELL_TOXIN = 26575, // Triggers toxin cloud - 25989 -#define SPELL_TOXIN_CLOUD 25989 + // Debuffs gained by the boss on frost damage + SPELL_VISCIDUS_SLOWED = 26034, + SPELL_VISCIDUS_SLOWED_MORE = 26036, + SPELL_VISCIDUS_FREEZE = 25937, + + // When frost damage exceeds a certain limit, then boss explodes + SPELL_REJOIN_VISCIDUS = 25896, + SPELL_VISCIDUS_EXPLODE = 25938, + SPELL_VISCIDUS_SUICIDE = 26003, // cast when boss explodes and is below 5% Hp - should trigger 26002 + + // 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 +}; + +struct MANGOS_DLL_DECL boss_viscidusAI : public ScriptedAI +{ + boss_viscidusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiPoisonShockTimer; + uint32 m_uiPoisonBoltVolleyTimer; + + void Reset() + { + m_uiPoisonShockTimer = urand(7000, 12000); + m_uiPoisonBoltVolleyTimer = urand(10000, 15000); + } + + 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); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VISCIDUS, DONE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + 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; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_viscidus(Creature* pCreature) +{ + return new boss_viscidusAI(pCreature); +} + +void AddSC_boss_viscidus() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_viscidus"; + pNewScript->GetAI = &GetAI_boss_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 12c43e956e..96c7269b00 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,132 +17,286 @@ /* 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" -struct MANGOS_DLL_DECL instance_temple_of_ahnqiraj : public ScriptedInstance +static const DialogueEntry aIntroDialogue[] = { - instance_temple_of_ahnqiraj(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; + {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} +}; - //Storing Skeram, Vem and Kri. - uint64 m_uiSkeramGUID; - uint64 m_uiVemGUID; - uint64 m_uiKriGUID; - uint64 m_uiVeklorGUID; - uint64 m_uiVeknilashGUID; +instance_temple_of_ahnqiraj::instance_temple_of_ahnqiraj(Map* pMap) : ScriptedInstance(pMap), + m_uiBugTrioDeathCount(0), + m_uiCthunWhisperTimer(90000), + m_bIsEmperorsIntroDone(false), + m_dialogueHelper(aIntroDialogue) +{ + Initialize(); +}; - uint32 m_uiBugTrioDeathCount; +void instance_temple_of_ahnqiraj::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - uint32 m_uiCthunPhase; + m_dialogueHelper.InitializeDialogueHelper(this); +} - void Initialize() +bool instance_temple_of_ahnqiraj::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiSkeramGUID = 0; - m_uiVemGUID = 0; - m_uiKriGUID = 0; - m_uiVeklorGUID = 0; - m_uiVeknilashGUID = 0; + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } - m_uiBugTrioDeathCount = 0; + return false; +} - m_uiCthunPhase = 0; +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; } - - void OnCreatureCreate (Creature* pCreature) + else if (uiTriggerId == AREATRIGGER_SARTURA) { - switch (pCreature->GetEntry()) + if (GetData(TYPE_SARTURA) == NOT_STARTED || GetData(TYPE_SARTURA) == FAIL) { - case 15263: m_uiSkeramGUID = pCreature->GetGUID(); break; - case 15544: m_uiVemGUID = pCreature->GetGUID(); break; - case 15511: m_uiKriGUID = pCreature->GetGUID(); break; - case 15276: m_uiVeklorGUID = pCreature->GetGUID(); break; - case 15275: m_uiVeknilashGUID = pCreature->GetGUID(); break; + if (Creature* pSartura = GetSingleCreatureFromStorage(NPC_SARTURA)) + pSartura->SetInCombatWithZone(); } } +} - bool IsEncounterInProgress() const +void instance_temple_of_ahnqiraj::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - //not active in AQ40 - return false; + 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; } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_temple_of_ahnqiraj::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(uiType) - { - case TYPE_VEM: - m_auiEncounter[0] = uiData; - break; - case TYPE_VEKLOR: - m_auiEncounter[1] = uiData; - break; - case TYPE_VEKNILASH: - m_auiEncounter[2] = uiData; - break; + case GO_SKERAM_GATE: + if (m_auiEncounter[TYPE_SKERAM] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_TWINS_ENTER_DOOR: + break; + case GO_TWINS_EXIT_DOOR: + if (m_auiEncounter[TYPE_TWINS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SANDWORM_BASE: + break; + + default: + return; + } - case DATA_BUG_TRIO_DEATH: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_temple_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_SKERAM: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_SKERAM_GATE); + break; + case TYPE_BUG_TRIO: + if (uiData == SPECIAL) + { ++m_uiBugTrioDeathCount; - break; + if (m_uiBugTrioDeathCount == 2) + SetData(TYPE_BUG_TRIO, DONE); - case TYPE_CTHUN_PHASE: - m_uiCthunPhase = uiData; + // don't store any special data break; - } + } + if (uiData == FAIL) + 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) + return; + + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_TWINS_ENTER_DOOR); + if (uiData == DONE) + DoUseDoorOrButton(GO_TWINS_EXIT_DOOR); + break; + 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; } - uint32 GetData(uint32 uiType) + if (uiData == DONE) { - switch(uiType) - { - case TYPE_VEM: - return m_auiEncounter[0]; + OUT_SAVE_INST_DATA; - case DATA_BUG_TRIO_DEATH: - return m_uiBugTrioDeathCount; + 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]; - case TYPE_CTHUN_PHASE: - return m_uiCthunPhase; - } - return 0; + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +void instance_temple_of_ahnqiraj::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] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } - uint64 GetData64(uint32 uiData) + OUT_LOAD_INST_DATA_COMPLETE; +} + +uint32 instance_temple_of_ahnqiraj::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[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) { - switch(uiData) + if (Player* pPlayer = GetPlayerInMap()) { - case DATA_SKERAM: - return m_uiSkeramGUID; - case DATA_VEM: - return m_uiVemGUID; - case DATA_KRI: - return m_uiKriGUID; - case DATA_VEKLOR: - return m_uiVeklorGUID; - case DATA_VEKNILASH: - return m_uiVeknilashGUID; + 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; + } + } } - return 0; + 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 *newscript; - newscript = new Script; - newscript->Name = "instance_temple_of_ahnqiraj"; - newscript->GetInstanceData = &GetInstanceData_instance_temple_of_ahnqiraj; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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 d10c9bbb2b..4582d13d19 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -53,7 +53,7 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI uint32 m_uiMyAbility; bool m_bEnraged; - std::list m_lAssistList; + GuidList m_lAssistList; void Reset() { @@ -61,11 +61,21 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI m_bEnraged = false; } - void JustReachedHome() + void GetAIInformation(ChatHandler& reader) override { - for(std::list::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->GetGUID()) + if (*itr == m_creature->GetObjectGuid()) continue; if (Creature* pBuddy = m_creature->GetMap()->GetCreature(*itr)) @@ -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,11 +118,11 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI void DoTransferAbility() { - for(std::list::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)) { - if (*itr == m_creature->GetGUID()) + if (*itr == m_creature->GetObjectGuid()) continue; if (!pBuddy->isAlive()) @@ -128,9 +138,9 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI { if (!m_lAssistList.empty()) { - for(std::list::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->GetGUID()) + if (*itr == m_creature->GetObjectGuid()) continue; if (Creature* pBuddy = m_creature->GetMap()->GetCreature(*itr)) @@ -146,24 +156,21 @@ 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)->GetGUID()); + m_lAssistList.push_back((*iter)->GetObjectGuid()); - if ((*iter)->GetGUID() == m_creature->GetGUID()) + if ((*iter)->GetObjectGuid() == m_creature->GetObjectGuid()) continue; (*iter)->AI()->AttackStart(pTarget); } 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; @@ -188,9 +195,10 @@ CreatureAI* GetAI_npc_anubisath_sentinel(Creature* pCreature) void AddSC_mob_anubisath_sentinel() { - Script *newscript; - newscript = new Script; - newscript->Name = "mob_anubisath_sentinel"; - newscript->GetAI = &GetAI_npc_anubisath_sentinel; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_anubisath_sentinel"; + pNewScript->GetAI = &GetAI_npc_anubisath_sentinel; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h b/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h index c9c93e1c93..2cea868f53 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,21 +7,98 @@ enum { - MAX_ENCOUNTER = 3, + MAX_ENCOUNTER = 9, - TYPE_VEM = 1, - TYPE_VEKLOR = 2, - TYPE_VEKNILASH = 3, + TYPE_SKERAM = 0, + TYPE_BUG_TRIO = 1, + TYPE_SARTURA = 2, + TYPE_FANKRISS = 3, + TYPE_VISCIDUS = 4, + TYPE_HUHURAN = 5, + TYPE_TWINS = 6, + TYPE_OURO = 7, + TYPE_CTHUN = 8, - DATA_SKERAM = 5, - DATA_KRI = 6, - DATA_VEM = 7, - DATA_VEKLOR = 8, - DATA_VEKNILASH = 9, + 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, - DATA_BUG_TRIO_DEATH = 10, + GO_SKERAM_GATE = 180636, + GO_TWINS_ENTER_DOOR = 180634, + GO_TWINS_EXIT_DOOR = 180635, + GO_SANDWORM_BASE = 180795, - TYPE_CTHUN_PHASE = 20 + 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, + + // 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 +{ + public: + instance_temple_of_ahnqiraj(Map* pMap); + + void Initialize() override; + + bool IsEncounterInProgress() const 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 DoHandleTempleAreaTrigger(uint32 uiTriggerId); + + 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 2fea2accf9..b2dc258573 100644 --- a/scripts/kalimdor/the_barrens.cpp +++ b/scripts/kalimdor/the_barrens.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,19 +45,19 @@ 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->GetGUID()); + 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->GetGUID()); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(3558, pCreature->GetObjectGuid()); + pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); } return true; } @@ -91,14 +90,14 @@ struct MANGOS_DLL_DECL npc_giltharesAI : public npc_escortAI void Reset() { } - 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,39 +151,13 @@ 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); if (npc_giltharesAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); - } - return true; -} - -/*###### -## npc_sputtervalve -######*/ - -bool GossipHello_npc_sputtervalve(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - 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->GetGUID()); - 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->GetGUID()); - pPlayer->AreaExploredOrEventHappens(6981); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -202,57 +175,57 @@ enum struct MANGOS_DLL_DECL 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() { - 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 { - 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; - uint64 PlayerGUID; - uint64 BigWillGUID; - uint64 AffrayChallenger[6]; + ObjectGuid m_playerGuid; + ObjectGuid m_bigWillGuid; + GuidVector m_vAffrayChallengerGuidsVector; void Reset() { - EventInProgress = false; - - Event_Timer = 2000; - Step = 0; - Challenger_Count = 0; - ChallengerDeath_Timer = 0; + m_bIsEventInProgress = false; - PlayerGUID = 0; - BigWillGUID = 0; + m_uiEventTimer = 1000; + m_uiChallengerCount = 0; + m_uiStep = 0; - for(uint8 i = 0; i < 6; ++i) - AffrayChallenger[i] = 0; + m_playerGuid.Clear(); + m_bigWillGuid.Clear(); + m_vAffrayChallengerGuidsVector.clear(); } bool CanStartEvent(Player* pPlayer) { - if (!EventInProgress) + if (!m_bIsEventInProgress) { - EventInProgress = true; - PlayerGUID = pPlayer->GetGUID(); 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); - AffrayChallenger[i] = pCreature->GetGUID(); - } + 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(Creature* pChallenger) + { + 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 SetChallengerReady(Unit *pUnit) + void JustSummoned(Creature* pSummoned) override { - 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); + 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(AffrayChallenger[i]); - if (challenger && !challenger->isAlive() && challenger->isDead()) - { - DoScriptText(SAY_TWIGGY_DOWN, m_creature); - challenger->RemoveCorpse(); - AffrayChallenger[i] = 0; - continue; - } - } - ChallengerDeath_Timer = 2500; - } else ChallengerDeath_Timer -= diff; + DoScriptText(SAY_BIG_WILL_READY, pSummoned, pPlayer); + pSummoned->SetFacingToObject(pPlayer); } + } - if (Event_Timer < diff) + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_BIG_WILL) + { + DoScriptText(SAY_TWIGGY_OVER, m_creature); + EnterEvadeMode(); + } + else { - Player* pPlayer = m_creature->GetMap()->GetPlayer(PlayerGUID); + DoScriptText(SAY_TWIGGY_DOWN, m_creature); + m_uiEventTimer = 15000; + } + } - if (!pPlayer || pPlayer->isDead()) - Reset(); + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsEventInProgress) + return; - switch(Step) + if (m_uiEventTimer < uiDiff) + { + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); + + if (!pPlayer || !pPlayer->isAlive()) + EnterEvadeMode(); + + 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(AffrayChallenger[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) { - BigWillGUID = temp->GetGUID(); - 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(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(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,26 +445,23 @@ 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->GetQuestStatus(QUEST_AFFRAY) == QUEST_STATUS_FAILED) + { + //we don't want player to start event if failed already. + return true; + } + else if (pPlayer->isAlive() && !pPlayer->isGameMaster() && pPlayer->GetQuestStatus(QUEST_AFFRAY) == QUEST_STATUS_INCOMPLETE) { - if (uint16 slot = pPlayer->FindQuestSlot(QUEST_AFFRAY)) - { - //we don't want player to start event if failed already. - if (pPlayer->GetQuestSlotState(slot) == QUEST_STATE_FAIL) - return true; - } - 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; @@ -540,9 +517,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()) @@ -552,10 +529,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: @@ -564,9 +541,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()) @@ -580,7 +557,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); @@ -589,7 +566,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()) { @@ -597,7 +574,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); @@ -636,10 +613,10 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(true, pPlayer, pQuest); } return true; } @@ -651,44 +628,38 @@ CreatureAI* GetAI_npc_wizzlecranks_shredder(Creature* pCreature) void AddSC_the_barrens() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_beaten_corpse"; - newscript->pGossipHello = &GossipHello_npc_beaten_corpse; - newscript->pGossipSelect = &GossipSelect_npc_beaten_corpse; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_gilthares"; - newscript->GetAI = &GetAI_npc_gilthares; - newscript->pQuestAccept = &QuestAccept_npc_gilthares; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_sputtervalve"; - newscript->pGossipHello = &GossipHello_npc_sputtervalve; - newscript->pGossipSelect = &GossipSelect_npc_sputtervalve; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_taskmaster_fizzule"; - newscript->GetAI = &GetAI_npc_taskmaster_fizzule; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_twiggy_flathead"; - newscript->GetAI = &GetAI_npc_twiggy_flathead; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "at_twiggy_flathead"; - newscript->pAreaTrigger = &AreaTrigger_at_twiggy_flathead; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_wizzlecranks_shredder"; - newscript->GetAI = &GetAI_npc_wizzlecranks_shredder; - newscript->pQuestAccept = &QuestAccept_npc_wizzlecranks_shredder; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_beaten_corpse"; + pNewScript->pGossipHello = &GossipHello_npc_beaten_corpse; + pNewScript->pGossipSelect = &GossipSelect_npc_beaten_corpse; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_gilthares"; + pNewScript->GetAI = &GetAI_npc_gilthares; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_gilthares; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_taskmaster_fizzule"; + pNewScript->GetAI = &GetAI_npc_taskmaster_fizzule; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_twiggy_flathead"; + pNewScript->GetAI = &GetAI_npc_twiggy_flathead; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_twiggy_flathead"; + pNewScript->pAreaTrigger = &AreaTrigger_at_twiggy_flathead; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_wizzlecranks_shredder"; + pNewScript->GetAI = &GetAI_npc_wizzlecranks_shredder; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_wizzlecranks_shredder; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/thousand_needles.cpp b/scripts/kalimdor/thousand_needles.cpp index 648b9a3d0a..7775bd13f9 100644 --- a/scripts/kalimdor/thousand_needles.cpp +++ b/scripts/kalimdor/thousand_needles.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -44,7 +44,7 @@ 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 { @@ -52,9 +52,9 @@ struct MANGOS_DLL_DECL npc_kanatiAI : public npc_escortAI void Reset() { } - 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); } @@ -91,7 +91,7 @@ bool QuestAccept_npc_kanati(Player* pPlayer, Creature* pCreature, const Quest* p if (pQuest->GetQuestId() == QUEST_PROTECT_KANATI) { if (npc_kanatiAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest, true); + pEscortAI->Start(false, pPlayer, pQuest, true); } return true; } @@ -116,14 +116,14 @@ 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 @@ -132,9 +132,9 @@ struct MANGOS_DLL_DECL npc_lakota_windsongAI : public npc_escortAI void Reset() { } - 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,10 +174,10 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -196,11 +196,11 @@ 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 @@ -209,9 +209,9 @@ struct MANGOS_DLL_DECL npc_paoka_swiftmountainAI : public npc_escortAI void Reset() { } - 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,10 +246,10 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -272,33 +272,28 @@ struct MANGOS_DLL_DECL 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() { 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)) { @@ -352,15 +347,15 @@ bool GossipHello_npc_plucky_johnson(Player* pPlayer, Creature* pCreature) if (pPlayer->GetQuestStatus(QUEST_SCOOP) == QUEST_STATUS_INCOMPLETE) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_QUEST, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(720, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(720, pCreature->GetObjectGuid()); 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) { - pPlayer->SEND_GOSSIP_MENU(738, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(738, pCreature->GetObjectGuid()); pPlayer->AreaExploredOrEventHappens(QUEST_SCOOP); } @@ -369,30 +364,30 @@ bool GossipSelect_npc_plucky_johnson(Player* pPlayer, Creature* pCreature, uint3 void AddSC_thousand_needles() { - Script* newscript; - - newscript = new Script; - newscript->Name = "npc_kanati"; - newscript->GetAI = &GetAI_npc_kanati; - newscript->pQuestAccept = &QuestAccept_npc_kanati; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_lakota_windsong"; - newscript->GetAI = &GetAI_npc_lakota_windsong; - newscript->pQuestAccept = &QuestAccept_npc_lakota_windsong; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_paoka_swiftmountain"; - newscript->GetAI = &GetAI_npc_paoka_swiftmountain; - newscript->pQuestAccept = &QuestAccept_npc_paoka_swiftmountain; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_plucky_johnson"; - newscript->GetAI = &GetAI_npc_plucky_johnson; - newscript->pGossipHello = &GossipHello_npc_plucky_johnson; - newscript->pGossipSelect = &GossipSelect_npc_plucky_johnson; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_kanati"; + pNewScript->GetAI = &GetAI_npc_kanati; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kanati; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_lakota_windsong"; + pNewScript->GetAI = &GetAI_npc_lakota_windsong; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_lakota_windsong; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_paoka_swiftmountain"; + pNewScript->GetAI = &GetAI_npc_paoka_swiftmountain; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_paoka_swiftmountain; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_plucky_johnson"; + pNewScript->GetAI = &GetAI_npc_plucky_johnson; + pNewScript->pGossipHello = &GossipHello_npc_plucky_johnson; + pNewScript->pGossipSelect = &GossipSelect_npc_plucky_johnson; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/throne_of_the_four_winds/boss_alakir.cpp b/scripts/kalimdor/throne_of_the_four_winds/boss_alakir.cpp new file mode 100644 index 0000000000..e5de99d972 --- /dev/null +++ b/scripts/kalimdor/throne_of_the_four_winds/boss_alakir.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_alakir +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Four Winds +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_alakir() +{ +} diff --git a/scripts/kalimdor/throne_of_the_four_winds/conclave_of_the_wind.cpp b/scripts/kalimdor/throne_of_the_four_winds/conclave_of_the_wind.cpp new file mode 100644 index 0000000000..6f8862f938 --- /dev/null +++ b/scripts/kalimdor/throne_of_the_four_winds/conclave_of_the_wind.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: conclave_of_the_wind +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Four Winds +EndScriptData */ + +#include "precompiled.h" + +void AddSC_conclave_of_the_wind() +{ +} diff --git a/scripts/kalimdor/throne_of_the_four_winds/instance_throne_of_the_four_winds.cpp b/scripts/kalimdor/throne_of_the_four_winds/instance_throne_of_the_four_winds.cpp new file mode 100644 index 0000000000..7a9fb68e7d --- /dev/null +++ b/scripts/kalimdor/throne_of_the_four_winds/instance_throne_of_the_four_winds.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_throne_of_the_four_winds +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of the Four Winds +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_throne_of_the_four_winds() +{ +} diff --git a/scripts/kalimdor/throne_of_the_four_winds/throne_of_the_four_winds.h b/scripts/kalimdor/throne_of_the_four_winds/throne_of_the_four_winds.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/throne_of_the_four_winds/throne_of_the_four_winds.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/thunder_bluff.cpp b/scripts/kalimdor/thunder_bluff.cpp index 5f51682216..97b8afea6a 100644 --- a/scripts/kalimdor/thunder_bluff.cpp +++ b/scripts/kalimdor/thunder_bluff.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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 +17,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->GetGUID()); - - 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->GetGUID()); - - 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->GetGUID()); - } - return true; -} - void AddSC_thunder_bluff() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_cairne_bloodhoof"; - newscript->GetAI = &GetAI_npc_cairne_bloodhoof; - newscript->pGossipHello = &GossipHello_npc_cairne_bloodhoof; - newscript->pGossipSelect = &GossipSelect_npc_cairne_bloodhoof; - newscript->RegisterSelf(); } diff --git a/scripts/kalimdor/uldum.cpp b/scripts/kalimdor/uldum.cpp new file mode 100644 index 0000000000..2da318b720 --- /dev/null +++ b/scripts/kalimdor/uldum.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Uldum +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Uldum +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_uldum() +{ +} diff --git a/scripts/kalimdor/ungoro_crater.cpp b/scripts/kalimdor/ungoro_crater.cpp index 3f3c86a2d6..c04c614b39 100644 --- a/scripts/kalimdor/ungoro_crater.cpp +++ b/scripts/kalimdor/ungoro_crater.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,6 +22,7 @@ SDCategory: Un'Goro Crater EndScriptData */ /* ContentData +npc_ame01 npc_ringo EndContentData */ @@ -51,9 +52,9 @@ struct MANGOS_DLL_DECL npc_ame01AI : public npc_escortAI void Reset() {} - 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,11 +99,11 @@ 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->GetGUID(), pQuest); + pAmeAI->Start(false, pPlayer, pQuest); } } return true; @@ -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); @@ -334,12 +335,12 @@ void AddSC_ungoro_crater() pNewScript = new Script; pNewScript->Name = "npc_ame01"; pNewScript->GetAI = &GetAI_npc_ame01; - pNewScript->pQuestAccept = &QuestAccept_npc_ame01; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_ame01; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_ringo"; pNewScript->GetAI = &GetAI_npc_ringo; - pNewScript->pQuestAccept = &QuestAccept_npc_ringo; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_ringo; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/vortex_pinnacle/boss_altairus.cpp b/scripts/kalimdor/vortex_pinnacle/boss_altairus.cpp new file mode 100644 index 0000000000..56dcf9e446 --- /dev/null +++ b/scripts/kalimdor/vortex_pinnacle/boss_altairus.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_altairus +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Vortex Pinnacle +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_altairus() +{ +} diff --git a/scripts/kalimdor/vortex_pinnacle/boss_asaad.cpp b/scripts/kalimdor/vortex_pinnacle/boss_asaad.cpp new file mode 100644 index 0000000000..7d1e3c3fcf --- /dev/null +++ b/scripts/kalimdor/vortex_pinnacle/boss_asaad.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_asaad +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Vortex Pinnacle +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_asaad() +{ +} diff --git a/scripts/kalimdor/vortex_pinnacle/boss_grand_vizier_ertan.cpp b/scripts/kalimdor/vortex_pinnacle/boss_grand_vizier_ertan.cpp new file mode 100644 index 0000000000..e1854c173a --- /dev/null +++ b/scripts/kalimdor/vortex_pinnacle/boss_grand_vizier_ertan.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_grand_vizier_etan +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Vortex Pinnacle +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_grand_vizier_etan() +{ +} diff --git a/scripts/kalimdor/vortex_pinnacle/instance_vortex_pinnacle.cpp b/scripts/kalimdor/vortex_pinnacle/instance_vortex_pinnacle.cpp new file mode 100644 index 0000000000..ff64481773 --- /dev/null +++ b/scripts/kalimdor/vortex_pinnacle/instance_vortex_pinnacle.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_vortex_pinnacle +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Vortex Pinnacle +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_vortex_pinnacle() +{ +} diff --git a/scripts/kalimdor/vortex_pinnacle/vortex_pinnacle.h b/scripts/kalimdor/vortex_pinnacle/vortex_pinnacle.h new file mode 100644 index 0000000000..6b5f9ef476 --- /dev/null +++ b/scripts/kalimdor/vortex_pinnacle/vortex_pinnacle.h @@ -0,0 +1,3 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp b/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp index 41e16de766..15d019efd6 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,15 +17,14 @@ /* ScriptData SDName: Instance_Wailing_Caverns SD%Complete: 90 -SDComment: +SDComment: SDCategory: Wailing Caverns EndScriptData */ #include "precompiled.h" #include "wailing_caverns.h" -instance_wailing_caverns::instance_wailing_caverns(Map* pMap) : ScriptedInstance(pMap), - m_uiNaralexGUID(0) +instance_wailing_caverns::instance_wailing_caverns(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } @@ -35,17 +34,34 @@ void instance_wailing_caverns::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +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)) + DoRespawnGameObject(GO_MYSTERIOUS_CHEST, HOUR); +} + void instance_wailing_caverns::OnCreatureCreate(Creature* pCreature) { switch (pCreature->GetEntry()) { - case NPC_NARLEX: m_uiNaralexGUID = pCreature->GetGUID(); break; + case NPC_NARALEX: + case NPC_DISCIPLE: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } } +void instance_wailing_caverns::OnObjectCreate(GameObject* pGo) +{ + if (pGo->GetEntry() == GO_MYSTERIOUS_CHEST) + m_mGoEntryGuidStore[GO_MYSTERIOUS_CHEST] = pGo->GetObjectGuid(); +} + void instance_wailing_caverns::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ANACONDRA: m_auiEncounter[0] = uiData; @@ -62,13 +78,23 @@ void instance_wailing_caverns::SetData(uint32 uiType, uint32 uiData) case TYPE_DISCIPLE: m_auiEncounter[4] = uiData; break; - case TYPE_MUTANOUS: + case TYPE_MUTANUS: m_auiEncounter[5] = uiData; break; } - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE && m_auiEncounter[2] == DONE && m_auiEncounter[3] == DONE && m_auiEncounter[4] == NOT_STARTED) + // Set to special in order to start the escort event; only if all four bosses are done + if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE && m_auiEncounter[2] == DONE && m_auiEncounter[3] == DONE && (m_auiEncounter[4] == NOT_STARTED || m_auiEncounter[4] == FAIL)) + { + // Yell intro text; only the first time + if (m_auiEncounter[4] == NOT_STARTED) + { + if (Creature* pDisciple = GetSingleCreatureFromStorage(NPC_DISCIPLE)) + DoScriptText(SAY_INTRO, pDisciple); + } + m_auiEncounter[4] = SPECIAL; + } if (uiData == DONE) { @@ -77,9 +103,9 @@ 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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; } @@ -97,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; @@ -108,26 +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_MUTANOUS: return m_auiEncounter[5]; break; - } - return 0; -} + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; -uint64 instance_wailing_caverns::GetData64(uint32 uiData) -{ - switch (uiData) - { - case DATA_NARALEX: return m_uiNaralexGUID; - } return 0; } @@ -138,9 +149,10 @@ InstanceData* GetInstanceData_instance_wailing_caverns(Map* pMap) void AddSC_instance_wailing_caverns() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_wailing_caverns"; - newscript->GetInstanceData = &GetInstanceData_instance_wailing_caverns; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_wailing_caverns"; + pNewScript->GetInstanceData = &GetInstanceData_instance_wailing_caverns; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp b/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp new file mode 100644 index 0000000000..eb34f1de16 --- /dev/null +++ b/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp @@ -0,0 +1,498 @@ +/* Copyright (C) 2006 - 2013 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: wailing_caverns +SD%Complete: 90 +SDComment: Missing vipers emerge effect, Naralex doesn't fly at exit(Core issue) +SDCategory: Wailing Caverns +EndScriptData */ + +#include "precompiled.h" +#include "wailing_caverns.h" +#include "escort_ai.h" + +enum +{ + SAY_PREPARE = -1043001, + SAY_FIRST_CORNER = -1043002, + SAY_CONTINUE = -1043003, + SAY_CIRCLE_BANISH = -1043004, + SAY_PURIFIED = -1043005, + SAY_NARALEX_CHAMBER = -1043006, + SAY_BEGIN_RITUAL = -1043007, + SAY_MUTANUS = -1043012, + SAY_NARALEX_AWAKE = -1043013, + SAY_AWAKE = -1043014, + SAY_NARALEX_THANKYOU = -1043015, + SAY_FAREWELL = -1043016, + SAY_AGGRO_1 = -1043017, // Random between the first 2 + SAY_AGGRO_2 = -1043018, + SAY_AGGRO_3 = -1043019, // During the awakening ritual + + EMOTE_RITUAL_BEGIN = -1043008, + EMOTE_NARALEX_AWAKE = -1043009, + EMOTE_BREAK_THROUGH = -1043010, + EMOTE_VISION = -1043011, + + GOSSIP_ITEM_BEGIN = -3043000, + TEXT_ID_DISCIPLE = 698, + + SPELL_MARK = 5232, // Buff before the fight. To be removed after 4.0.3 + SPELL_SLEEP = 1090, + SPELL_POTION = 8141, + SPELL_CLEANSING = 6270, + SPELL_AWAKENING = 6271, + SPELL_SHAPESHIFT = 8153, + + NPC_DEVIATE_RAPTOR = 3636, // 2 of them at the first stop + NPC_DEVIATE_VIPER = 5755, // 3 of them at the circle + NPC_DEVIATE_MOCCASIN = 5762, // 6 of them at Naralex chamber + NPC_NIGHTMARE_ECTOPLASM = 5763, // 10 of them at Naralex chamber + NPC_MUTANUS = 3654 +}; + +// Distance, Angle or Offset +static const float aSummonPositions[5][2] = +{ + {50.0f, -0.507f}, // First Raptors + {53.0f, -0.603f}, + { 7.0f, 1.73f}, // Vipers + {45.0f, 5.16f}, // Chamber + {47.0f, 0.5901f} // Mutanus +}; + +struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI +{ + npc_disciple_of_naralexAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (instance_wailing_caverns*)pCreature->GetInstanceData(); + Reset(); + } + + instance_wailing_caverns* m_pInstance; + + uint32 m_uiEventTimer; + uint32 m_uiSleepTimer; + uint32 m_uiPotionTimer; + uint32 m_uiCleansingTimer; + uint8 m_uiSummonedAlive; + bool m_bIsFirstHit; + + uint32 m_uiPoint; + uint8 m_uiSubeventPhase; + + void Reset() + { + m_uiSleepTimer = 5000; + m_uiPotionTimer = 5000; + m_uiCleansingTimer = 0; + m_bIsFirstHit = false; // Used to trigger the combat yell; reset at every evade + + // Don't reset mob counter during the event + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiEventTimer = 0; + + m_uiPoint = 0; + m_uiSubeventPhase = 0; + + m_uiSummonedAlive = 0; + } + } + + void JustRespawned() override + { + npc_escortAI::JustRespawned(); + + // Reset event if can + if (m_pInstance && m_pInstance->GetData(TYPE_DISCIPLE) != DONE) + m_pInstance->SetData(TYPE_DISCIPLE, FAIL); + } + + void AttackedBy(Unit* pAttacker) override + { + if (!m_bIsFirstHit) + { + if (pAttacker->GetEntry() == NPC_MUTANUS) + DoScriptText(SAY_MUTANUS, m_creature, pAttacker); + // Check if already in ritual + else if (m_uiPoint >= 30) + DoScriptText(SAY_AGGRO_3, m_creature, pAttacker); + else + // Aggro 1 should be in 90% of the cases + DoScriptText(roll_chance_i(90) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature, pAttacker); + + m_bIsFirstHit = true; + } + } + + // Overwrite the evade function, to change the combat stop function (keep casting some spells) + void EnterEvadeMode() override + { + // Do not stop casting at these points + if (m_uiPoint == 15 || m_uiPoint == 32) + { + m_creature->SetLootRecipient(NULL); + m_creature->DeleteThreatList(); + m_creature->CombatStop(false); + Reset(); + + // Remove running + m_creature->SetWalk(true); + } + else + npc_escortAI::EnterEvadeMode(); + } + + void JustStartedEscort() override + { + DoScriptText(SAY_PREPARE, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DISCIPLE, IN_PROGRESS); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 7: + DoScriptText(SAY_FIRST_CORNER, m_creature); + m_uiSubeventPhase = 0; + m_uiEventTimer = 2000; + m_uiPoint = uiPointId; + SetEscortPaused(true); + break; + case 15: + m_uiSubeventPhase = 0; + m_uiEventTimer = 2000; + m_uiPoint = uiPointId; + SetEscortPaused(true); + break; + case 26: + DoScriptText(SAY_NARALEX_CHAMBER, m_creature); + break; + case 32: + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + m_creature->SetFacingToObject(pNaralex); + + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiEventTimer = 2000; + m_uiSubeventPhase = 0; + m_uiPoint = uiPointId; + SetEscortPaused(true); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + // Attack the disciple + pSummoned->AI()->AttackStart(m_creature); + + ++m_uiSummonedAlive; + } + + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override + { + if (m_uiSummonedAlive == 0) + return; // Actually if this happens, something went wrong before + + --m_uiSummonedAlive; + + // Continue Event if all are dead and we are in a stopped subevent + if (m_uiSummonedAlive == 0 && m_uiEventTimer == 0) + m_uiEventTimer = 1000; + } + + // Summon mobs at calculated points + void DoSpawnMob(uint32 uiEntry, float fDistance, float fAngle) + { + 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_OOC_DESPAWN, 20000); + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiPoint) + { + // Corner stop -> raptors + case 7: + switch (m_uiSubeventPhase) + { + case 0: + // Summon raptors at first stop + DoSpawnMob(NPC_DEVIATE_RAPTOR, aSummonPositions[0][0], aSummonPositions[0][1]); + DoSpawnMob(NPC_DEVIATE_RAPTOR, aSummonPositions[1][0], aSummonPositions[1][1]); + m_uiEventTimer = 0; + ++m_uiSubeventPhase; + break; + case 1: + // After the summoned mobs are killed continue + DoScriptText(SAY_CONTINUE, m_creature); + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + } + break; + // Circle stop -> vipers + case 15: + switch (m_uiSubeventPhase) + { + case 0: + DoScriptText(SAY_CIRCLE_BANISH, m_creature); + m_uiEventTimer = 2000; + ++m_uiSubeventPhase; + break; + case 1: + DoCastSpellIfCan(m_creature, SPELL_CLEANSING); + m_uiEventTimer = 20000; + ++m_uiSubeventPhase; + break; + 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); + m_uiEventTimer = 0; + ++m_uiSubeventPhase; + break; + case 3: + // Wait for casting to be complete - TODO, this might have to be done better + ++m_uiSubeventPhase; + m_uiEventTimer = 10000; + break; + case 4: + DoScriptText(SAY_PURIFIED, m_creature); + m_uiEventTimer = 0; + ++m_uiPoint; // Increment this in order to avoid the special case evade + SetEscortPaused(false); + break; + } + break; + // Chamber stop -> ritual and final boss + case 32: + switch (m_uiSubeventPhase) + { + case 0: + DoScriptText(SAY_BEGIN_RITUAL, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiEventTimer = 2000; + ++m_uiSubeventPhase; + break; + case 1: + DoCastSpellIfCan(m_creature, SPELL_AWAKENING); + DoScriptText(EMOTE_RITUAL_BEGIN, m_creature); + m_uiEventTimer = 4000; + ++m_uiSubeventPhase; + break; + case 2: + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + DoScriptText(EMOTE_NARALEX_AWAKE, pNaralex); + m_uiEventTimer = 5000; + ++m_uiSubeventPhase; + break; + 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); + 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); + 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); + ++m_uiSubeventPhase; + m_uiEventTimer = 10000; + break; + case 6: + // Mutanus + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + DoScriptText(EMOTE_VISION, pNaralex); + DoSpawnMob(NPC_MUTANUS, aSummonPositions[4][0], aSummonPositions[4][1]); + m_uiEventTimer = 0; + ++m_uiSubeventPhase; + break; + case 7: + // Awaken Naralex after mutanus is defeated + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + { + pNaralex->SetStandState(UNIT_STAND_STATE_SIT); + DoScriptText(SAY_NARALEX_AWAKE, pNaralex); + } + m_creature->InterruptNonMeleeSpells(false, SPELL_AWAKENING); + m_creature->RemoveAurasDueToSpell(SPELL_AWAKENING); + m_pInstance->SetData(TYPE_DISCIPLE, DONE); + ++m_uiSubeventPhase; + m_uiEventTimer = 2000; + break; + case 8: + DoScriptText(SAY_AWAKE, m_creature); + m_uiEventTimer = 5000; + ++m_uiSubeventPhase; + break; + case 9: + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + { + DoScriptText(SAY_NARALEX_THANKYOU, pNaralex); + pNaralex->SetStandState(UNIT_STAND_STATE_STAND); + } + m_uiEventTimer = 10000; + ++m_uiSubeventPhase; + break; + case 10: + // Shapeshift into a bird + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + { + DoScriptText(SAY_FAREWELL, pNaralex); + pNaralex->CastSpell(pNaralex, SPELL_SHAPESHIFT, false); + } + DoCastSpellIfCan(m_creature, SPELL_SHAPESHIFT); + m_uiEventTimer = 10000; + ++m_uiSubeventPhase; + break; + case 11: + SetEscortPaused(false); + m_creature->SetLevitate(true); + SetRun(); + // Send them flying somewhere outside of the room + if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) + { + // 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_HOVER); + + // Set to flying + pNaralex->SetLevitate(true); + pNaralex->SetWalk(false); + + // Set following + pNaralex->GetMotionMaster()->MoveFollow(m_creature, 5.0f, 0); + // Despawn after some time + pNaralex->ForcedDespawn(30000); + } + m_uiEventTimer = 0; + break; + } + break; + } + } + else + m_uiEventTimer -= uiDiff; + } + + if (m_uiPotionTimer < uiDiff) + { + // if health lower than 80%, cast heal + if (m_creature->GetHealthPercent() < 80.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_POTION) == CAST_OK) + m_uiPotionTimer = 45000; + } + else + m_uiPotionTimer = 5000; + } + else + m_uiPotionTimer -= uiDiff; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSleepTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SLEEP) == CAST_OK) + m_uiSleepTimer = 30000; + } + } + else + m_uiSleepTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +bool GossipHello_npc_disciple_of_naralex(Player* pPlayer, Creature* pCreature) +{ + ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + // Buff the players + pCreature->CastSpell(pPlayer, SPELL_MARK, false); + + 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()); + } + else + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +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 (npc_disciple_of_naralexAI* pEscortAI = dynamic_cast(pCreature->AI())) + { + pEscortAI->Start(false, pPlayer); // Note: after 4.0.3 set him run = true + pCreature->SetFactionTemporary(FACTION_ESCORT_N_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + } + pPlayer->CLOSE_GOSSIP_MENU(); + } + return true; +} + +CreatureAI* GetAI_npc_disciple_of_naralex(Creature* pCreature) +{ + return new npc_disciple_of_naralexAI(pCreature); +} + +void AddSC_wailing_caverns() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_disciple_of_naralex"; + pNewScript->GetAI = &GetAI_npc_disciple_of_naralex; + pNewScript->pGossipHello = &GossipHello_npc_disciple_of_naralex; + pNewScript->pGossipSelect = &GossipSelect_npc_disciple_of_naralex; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/wailing_caverns/wailing_caverns.h b/scripts/kalimdor/wailing_caverns/wailing_caverns.h index 04093f7d83..8b28067626 100644 --- a/scripts/kalimdor/wailing_caverns/wailing_caverns.h +++ b/scripts/kalimdor/wailing_caverns/wailing_caverns.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,18 +7,23 @@ enum { - MAX_ENCOUNTER = 6, + MAX_ENCOUNTER = 6, - TYPE_ANACONDRA = 0, - TYPE_COBRAHN = 1, - TYPE_PYTHAS = 2, - TYPE_SERPENTIS = 3, - TYPE_DISCIPLE = 4, - TYPE_MUTANOUS = 5, + TYPE_ANACONDRA = 0, + TYPE_COBRAHN = 1, + TYPE_PYTHAS = 2, + TYPE_SERPENTIS = 3, + TYPE_DISCIPLE = 4, + TYPE_MUTANUS = 5, - DATA_NARALEX = 6, + NPC_NARALEX = 3679, + NPC_DISCIPLE = 3678, - NPC_NARLEX = 3679 + SAY_INTRO = -1043000, // Say when the first 4 encounter are DONE + + GO_MYSTERIOUS_CHEST = 180055, // used for quest 7944; spawns in the instance only if one of the players has the quest + + QUEST_FORTUNE_AWAITS = 7944, }; class MANGOS_DLL_DECL instance_wailing_caverns : public ScriptedInstance @@ -27,21 +32,20 @@ class MANGOS_DLL_DECL instance_wailing_caverns : public ScriptedInstance instance_wailing_caverns(Map* pMap); ~instance_wailing_caverns() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(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); - uint64 GetData64(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return 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]; - std::string strInstData; - - uint64 m_uiNaralexGUID; + std::string m_strInstData; }; #endif diff --git a/scripts/kalimdor/winterspring.cpp b/scripts/kalimdor/winterspring.cpp index 56cf8c4b15..dcef88b622 100644 --- a/scripts/kalimdor/winterspring.cpp +++ b/scripts/kalimdor/winterspring.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,141 +17,452 @@ /* ScriptData SDName: Winterspring SD%Complete: 90 -SDComment: Quest support: 5126 (Loraxs' tale missing proper gossip items text). Vendor Rivern Frostwind. Obtain Cache of Mau'ari +SDComment: Quest support: 4901. SDCategory: Winterspring EndScriptData */ /* ContentData -npc_lorax -npc_rivern_frostwind -npc_witch_doctor_mauari +npc_ranshalla EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### -## npc_lorax -######*/ +# npc_ranshalla +####*/ -bool GossipHello_npc_lorax(Player* pPlayer, Creature* pCreature) +enum { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + // Escort texts + SAY_QUEST_START = -1000739, + SAY_ENTER_OWL_THICKET = -1000707, + SAY_REACH_TORCH_1 = -1000708, + SAY_REACH_TORCH_2 = -1000709, + SAY_REACH_TORCH_3 = -1000710, + SAY_AFTER_TORCH_1 = -1000711, + SAY_AFTER_TORCH_2 = -1000712, + SAY_REACH_ALTAR_1 = -1000713, + SAY_REACH_ALTAR_2 = -1000714, - if (pPlayer->GetQuestStatus(5126) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Talk to me", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + // After lighting the altar cinematic + SAY_RANSHALLA_ALTAR_1 = -1000715, + SAY_RANSHALLA_ALTAR_2 = -1000716, + SAY_PRIESTESS_ALTAR_3 = -1000717, + SAY_PRIESTESS_ALTAR_4 = -1000718, + SAY_RANSHALLA_ALTAR_5 = -1000719, + SAY_RANSHALLA_ALTAR_6 = -1000720, + SAY_PRIESTESS_ALTAR_7 = -1000721, + SAY_PRIESTESS_ALTAR_8 = -1000722, + SAY_PRIESTESS_ALTAR_9 = -1000723, + SAY_PRIESTESS_ALTAR_10 = -1000724, + SAY_PRIESTESS_ALTAR_11 = -1000725, + SAY_PRIESTESS_ALTAR_12 = -1000726, + SAY_PRIESTESS_ALTAR_13 = -1000727, + SAY_PRIESTESS_ALTAR_14 = -1000728, + SAY_VOICE_ALTAR_15 = -1000729, + SAY_PRIESTESS_ALTAR_16 = -1000730, + SAY_PRIESTESS_ALTAR_17 = -1000731, + SAY_PRIESTESS_ALTAR_18 = -1000732, + SAY_PRIESTESS_ALTAR_19 = -1000733, + SAY_PRIESTESS_ALTAR_20 = -1000734, + SAY_PRIESTESS_ALTAR_21 = -1000735, + SAY_QUEST_END_1 = -1000736, + SAY_QUEST_END_2 = -1000737, - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + EMOTE_CHANT_SPELL = -1000738, - return true; -} + SPELL_LIGHT_TORCH = 18953, // channeled spell by Ranshalla while waiting for the torches / altar + + NPC_RANSHALLA = 10300, + NPC_PRIESTESS_ELUNE = 12116, + NPC_VOICE_ELUNE = 12152, + NPC_GUARDIAN_ELUNE = 12140, + + NPC_PRIESTESS_DATA_1 = 1, // dummy member for the first priestess (right) + NPC_PRIESTESS_DATA_2 = 2, // dummy member for the second priestess (left) + DATA_MOVE_PRIESTESS = 3, // dummy member to check the priestess movement + DATA_EVENT_END = 4, // dummy member to indicate the event end + + GO_ELUNE_ALTAR = 177404, + GO_ELUNE_FIRE = 177417, + GO_ELUNE_GEM = 177414, // is respawned in script + GO_ELUNE_LIGHT = 177415, // are respawned in script -bool GossipSelect_npc_lorax(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) + QUEST_GUARDIANS_ALTAR = 4901, +}; + +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 + {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_PRIESTESS_ALTAR_7, NPC_PRIESTESS_DATA_2, 4000}, + {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 + {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 + {NPC_VOICE_ELUNE, 0, 12000}, + {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 + {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_QUEST_END_2, NPC_RANSHALLA, 0}, + {0, 0, 0}, +}; + +static EVENTLOCATION aWingThicketLocations[] = { - switch(uiAction) + {5515.98f, -4903.43f, 846.30f, 4.58f}, // 0 right priestess summon loc + {5501.94f, -4920.20f, 848.69f, 6.15f}, // 1 left priestess summon loc + {5497.35f, -4906.49f, 850.83f, 2.76f}, // 2 guard of elune summon loc + {5518.38f, -4913.47f, 845.57f}, // 3 right priestess move loc + {5510.36f, -4921.17f, 846.33f}, // 4 left priestess move loc + {5511.31f, -4913.82f, 847.17f}, // 5 guard of elune move loc + {5518.51f, -4917.56f, 845.23f}, // 6 right priestess second move loc + {5514.40f, -4921.16f, 845.49f} // 7 left priestess second move loc +}; + +struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHelper +{ + npc_ranshallaAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aIntroDialogue) { - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(5126); - break; + Reset(); } - return true; -} -/*###### -## npc_rivern_frostwind -######*/ + uint32 m_uiDelayTimer; -bool GossipHello_npc_rivern_frostwind(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + ObjectGuid m_firstPriestessGuid; + ObjectGuid m_secondPriestessGuid; + ObjectGuid m_guardEluneGuid; + ObjectGuid m_voiceEluneGuid; + ObjectGuid m_altarGuid; - if (pCreature->isVendor() && pPlayer->GetReputationRank(589) == REP_EXALTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + void Reset() + { + m_uiDelayTimer = 0; + } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // Called when the player activates the torch / altar + void DoContinueEscort(bool bIsAltarWaypoint = false) + { + if (bIsAltarWaypoint) + DoScriptText(SAY_RANSHALLA_ALTAR_1, m_creature); + else + { + switch (urand(0, 1)) + { + case 0: DoScriptText(SAY_AFTER_TORCH_1, m_creature); break; + case 1: DoScriptText(SAY_AFTER_TORCH_2, m_creature); break; + } + } - return true; -} + m_uiDelayTimer = 2000; + } -bool GossipSelect_npc_rivern_frostwind(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); + // Called when Ranshalla starts to channel on a torch / altar + void DoChannelTorchSpell(bool bIsAltarWaypoint = false) + { + // Check if we are using the fire or the altar and remove the no_interact flag + if (bIsAltarWaypoint) + { + if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_ELUNE_ALTAR, 10.0f)) + { + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + m_creature->SetFacingToObject(pGo); + m_altarGuid = pGo->GetObjectGuid(); + } + } + else + { + if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_ELUNE_FIRE, 10.0f)) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + } - return true; -} + // Yell and set escort to pause + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_REACH_TORCH_1, m_creature); break; + case 1: DoScriptText(SAY_REACH_TORCH_2, m_creature); break; + case 2: DoScriptText(SAY_REACH_TORCH_3, m_creature); break; + } -/*###### -## npc_witch_doctor_mauari -######*/ + DoScriptText(EMOTE_CHANT_SPELL, m_creature); + DoCastSpellIfCan(m_creature, SPELL_LIGHT_TORCH); + SetEscortPaused(true); + } + + void DoSummonPriestess() + { + // Summon 2 Elune priestess and make each of them move to a different spot + if (Creature* pPriestess = m_creature->SummonCreature(NPC_PRIESTESS_ELUNE, aWingThicketLocations[0].m_fX, aWingThicketLocations[0].m_fY, aWingThicketLocations[0].m_fZ, aWingThicketLocations[0].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + pPriestess->GetMotionMaster()->MovePoint(0, aWingThicketLocations[3].m_fX, aWingThicketLocations[3].m_fY, aWingThicketLocations[3].m_fZ); + m_firstPriestessGuid = pPriestess->GetObjectGuid(); + } + if (Creature* pPriestess = m_creature->SummonCreature(NPC_PRIESTESS_ELUNE, aWingThicketLocations[1].m_fX, aWingThicketLocations[1].m_fY, aWingThicketLocations[1].m_fZ, aWingThicketLocations[1].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + // Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach + pPriestess->GetMotionMaster()->MovePoint(1, aWingThicketLocations[4].m_fX, aWingThicketLocations[4].m_fY, aWingThicketLocations[4].m_fZ); + m_secondPriestessGuid = pPriestess->GetObjectGuid(); + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_PRIESTESS_ELUNE || uiPointId != 1) + return; + + // Start the dialogue when the priestess reach the altar (they should both reach the point in the same time) + StartNextDialogueText(SAY_PRIESTESS_ALTAR_3); + } -bool GossipHello_npc_witch_doctor_mauari(Player* pPlayer, Creature* pCreature) + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 3: + DoScriptText(SAY_ENTER_OWL_THICKET, m_creature); + break; + case 10: // Cavern 1 + case 15: // Cavern 2 + case 20: // Cavern 3 + case 25: // Cavern 4 + case 36: // Cavern 5 + DoChannelTorchSpell(); + break; + case 39: + StartNextDialogueText(SAY_REACH_ALTAR_1); + 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) + { + 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); + DoSummonPriestess(); + DoScriptText(SAY_RANSHALLA_ALTAR_2, m_creature); + break; + case 44: + // Stop the escort and turn towards the altar + SetEscortPaused(true); + if (GameObject* pAltar = m_creature->GetMap()->GetGameObject(m_altarGuid)) + m_creature->SetFacingToObject(pAltar); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case NPC_RANSHALLA: + // Start the altar channeling + DoChannelTorchSpell(true); + break; + case SAY_RANSHALLA_ALTAR_6: + SetEscortPaused(false); + break; + case SAY_PRIESTESS_ALTAR_8: + // make the gem respawn + if (GameObject* pGem = GetClosestGameObjectWithEntry(m_creature, GO_ELUNE_GEM, 10.0f)) + { + if (pGem->isSpawned()) + break; + + pGem->SetRespawnTime(90); + pGem->Refresh(); + } + break; + case SAY_PRIESTESS_ALTAR_9: + // move near the escort npc + if (Creature* pPriestess = m_creature->GetMap()->GetCreature(m_firstPriestessGuid)) + pPriestess->GetMotionMaster()->MovePoint(0, aWingThicketLocations[6].m_fX, aWingThicketLocations[6].m_fY, aWingThicketLocations[6].m_fZ); + break; + case SAY_PRIESTESS_ALTAR_13: + // summon the Guardian of Elune + if (Creature* pGuard = m_creature->SummonCreature(NPC_GUARDIAN_ELUNE, aWingThicketLocations[2].m_fX, aWingThicketLocations[2].m_fY, aWingThicketLocations[2].m_fZ, aWingThicketLocations[2].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + pGuard->GetMotionMaster()->MovePoint(0, aWingThicketLocations[5].m_fX, aWingThicketLocations[5].m_fY, aWingThicketLocations[5].m_fZ); + m_guardEluneGuid = pGuard->GetObjectGuid(); + } + // summon the Voice of Elune + if (GameObject* pAltar = m_creature->GetMap()->GetGameObject(m_altarGuid)) + { + if (Creature* pVoice = m_creature->SummonCreature(NPC_VOICE_ELUNE, pAltar->GetPositionX(), pAltar->GetPositionY(), pAltar->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + m_voiceEluneGuid = pVoice->GetObjectGuid(); + } + break; + case SAY_VOICE_ALTAR_15: + // move near the escort npc and continue dialogue + if (Creature* pPriestess = m_creature->GetMap()->GetCreature(m_secondPriestessGuid)) + { + DoScriptText(SAY_PRIESTESS_ALTAR_14, pPriestess); + pPriestess->GetMotionMaster()->MovePoint(0, aWingThicketLocations[7].m_fX, aWingThicketLocations[7].m_fY, aWingThicketLocations[7].m_fZ); + } + break; + case SAY_PRIESTESS_ALTAR_19: + // make the voice of elune leave + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardEluneGuid)) + { + pGuard->GetMotionMaster()->MovePoint(0, aWingThicketLocations[2].m_fX, aWingThicketLocations[2].m_fY, aWingThicketLocations[2].m_fZ); + pGuard->ForcedDespawn(4000); + } + break; + case SAY_PRIESTESS_ALTAR_20: + // make the first priestess leave + if (Creature* pPriestess = m_creature->GetMap()->GetCreature(m_firstPriestessGuid)) + { + pPriestess->GetMotionMaster()->MovePoint(0, aWingThicketLocations[0].m_fX, aWingThicketLocations[0].m_fY, aWingThicketLocations[0].m_fZ); + pPriestess->ForcedDespawn(4000); + } + break; + case SAY_PRIESTESS_ALTAR_21: + // make the second priestess leave + if (Creature* pPriestess = m_creature->GetMap()->GetCreature(m_secondPriestessGuid)) + { + pPriestess->GetMotionMaster()->MovePoint(0, aWingThicketLocations[1].m_fX, aWingThicketLocations[1].m_fY, aWingThicketLocations[1].m_fZ); + pPriestess->ForcedDespawn(4000); + } + break; + case DATA_EVENT_END: + // Turn towards the player + if (Player* pPlayer = GetPlayerForEscort()) + { + m_creature->SetFacingToObject(pPlayer); + DoScriptText(SAY_QUEST_END_1, m_creature, pPlayer); + } + break; + case SAY_QUEST_END_2: + // Turn towards the altar and kneel - quest complete + if (GameObject* pAltar = m_creature->GetMap()->GetGameObject(m_altarGuid)) + m_creature->SetFacingToObject(pAltar); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_GUARDIANS_ALTAR, m_creature); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_RANSHALLA: return m_creature; + case NPC_VOICE_ELUNE: return m_creature->GetMap()->GetCreature(m_voiceEluneGuid); + case NPC_PRIESTESS_DATA_1: return m_creature->GetMap()->GetCreature(m_firstPriestessGuid); + case NPC_PRIESTESS_DATA_2: return m_creature->GetMap()->GetCreature(m_secondPriestessGuid); + + default: + return NULL; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (m_uiDelayTimer) + { + if (m_uiDelayTimer <= uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + SetEscortPaused(false); + m_uiDelayTimer = 0; + } + else + m_uiDelayTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_ranshalla(Creature* pCreature) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + return new npc_ranshallaAI(pCreature); +} - if (pPlayer->GetQuestRewardStatus(975)) +bool QuestAccept_npc_ranshalla(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_GUARDIANS_ALTAR) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I'd like you to make me a new Cache of Mau'ari please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(3377, pCreature->GetGUID()); - }else - pPlayer->SEND_GOSSIP_MENU(3375, pCreature->GetGUID()); + DoScriptText(SAY_QUEST_START, pCreature); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); - return true; + if (npc_ranshallaAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest, true); + + return true; + } + + return false; } -bool GossipSelect_npc_witch_doctor_mauari(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GOUse_go_elune_fire(Player* /*pPlayer*/, GameObject* pGo) { - if (uiAction==GOSSIP_ACTION_INFO_DEF+1) + // Check if we are using the torches or the altar + bool bIsAltar = false; + + if (pGo->GetEntry() == GO_ELUNE_ALTAR) + bIsAltar = true; + + if (Creature* pRanshalla = GetClosestCreatureWithEntry(pGo, NPC_RANSHALLA, 10.0f)) { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, 16351, false); + if (npc_ranshallaAI* pEscortAI = dynamic_cast(pRanshalla->AI())) + pEscortAI->DoContinueEscort(bIsAltar); } - return true; + return false; } void AddSC_winterspring() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_lorax"; - newscript->pGossipHello = &GossipHello_npc_lorax; - newscript->pGossipSelect = &GossipSelect_npc_lorax; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_rivern_frostwind"; - newscript->pGossipHello = &GossipHello_npc_rivern_frostwind; - newscript->pGossipSelect = &GossipSelect_npc_rivern_frostwind; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_witch_doctor_mauari"; - newscript->pGossipHello = &GossipHello_npc_witch_doctor_mauari; - newscript->pGossipSelect = &GossipSelect_npc_witch_doctor_mauari; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_ranshalla"; + pNewScript->GetAI = &GetAI_npc_ranshalla; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_ranshalla; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_elune_fire"; + pNewScript->pGOUse = &GOUse_go_elune_fire; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/zulfarrak/boss_zumrah.cpp b/scripts/kalimdor/zulfarrak/boss_zumrah.cpp index bef247fd45..e7abee631f 100644 --- a/scripts/kalimdor/zulfarrak/boss_zumrah.cpp +++ b/scripts/kalimdor/zulfarrak/boss_zumrah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +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 MANGOS_DLL_DECL 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() + { + 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 11902defa9..7e282e1394 100644 --- a/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp +++ b/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,7 +16,7 @@ /* ScriptData SDName: instance_zulfarrak -SD%Complete: 50% +SD%Complete: 80% SDComment: SDCategory: Zul'Farrak EndScriptData */ @@ -25,12 +25,12 @@ EndScriptData */ #include "zulfarrak.h" instance_zulfarrak::instance_zulfarrak(Map* pMap) : ScriptedInstance(pMap), - m_uiAntuSulGUID(0) + m_uiPyramidEventTimer(0) { Initialize(); } - void instance_zulfarrak::Initialize() +void instance_zulfarrak::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } @@ -39,23 +39,59 @@ void instance_zulfarrak::OnCreatureCreate(Creature* pCreature) { switch (pCreature->GetEntry()) { - case NPC_ANTUSUL: m_uiAntuSulGUID = pCreature->GetGUID(); break; + case NPC_ANTUSUL: + 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; @@ -67,9 +103,10 @@ 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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -88,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; @@ -99,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]; @@ -107,16 +145,6 @@ uint32 instance_zulfarrak::GetData(uint32 uiType) return 0; } -uint64 instance_zulfarrak::GetData64(uint32 uiData) -{ - switch (uiData) - { - case NPC_ANTUSUL: return m_uiAntuSulGUID; - default: - return 0; - } -} - void instance_zulfarrak::OnCreatureEnterCombat(Creature* pCreature) { switch (pCreature->GetEntry()) @@ -162,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 fea9cb1d3d..8040c7e9d0 100644 --- a/scripts/kalimdor/zulfarrak/zulfarrak.cpp +++ b/scripts/kalimdor/zulfarrak/zulfarrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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->GetGUID()); - /*} - else if (m_pInstance->GetData(0) == IN_PROGRESS) - pPlayer->SEND_GOSSIP_MENU(1516, pCreature->GetGUID()); - else - pPlayer->SEND_GOSSIP_MENU(1515, pCreature->GetGUID());*/ - - 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->GetGUID());//if event can proceed to end - } - else if (m_pInstance->GetData(0) == IN_PROGRESS) - pPlayer->SEND_GOSSIP_MENU(1513, pCreature->GetGUID());//if event are in progress - else*/ - pPlayer->SEND_GOSSIP_MENU(1511, pCreature->GetGUID()); //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) @@ -250,7 +92,7 @@ bool AreaTrigger_at_zulfarrak(Player* pPlayer, AreaTriggerEntry const* pAt) if (pInstance->GetData(TYPE_ANTUSUL) == NOT_STARTED || pInstance->GetData(TYPE_ANTUSUL) == FAIL) { - if (Creature* pAntuSul = pInstance->instance->GetCreature(pInstance->GetData64(NPC_ANTUSUL))) + if (Creature* pAntuSul = pInstance->GetSingleCreatureFromStorage(NPC_ANTUSUL)) { if (pAntuSul->isAlive()) pAntuSul->AI()->AttackStart(pPlayer); @@ -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 653a326f1e..556269eb54 100644 --- a/scripts/kalimdor/zulfarrak/zulfarrak.h +++ b/scripts/kalimdor/zulfarrak/zulfarrak.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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,6 +28,19 @@ 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, }; @@ -36,26 +50,33 @@ class MANGOS_DLL_DECL instance_zulfarrak : public ScriptedInstance instance_zulfarrak(Map* pMap); ~instance_zulfarrak() {} - void Initialize(); + void Initialize() override; - void OnCreatureEnterCombat(Creature* pCreature); - void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) 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); - uint64 GetData64(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); + void GetShallowGravesGuidList(GuidList& lList) { lList = m_lShallowGravesGuidList; } + + 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 strInstData; + std::string m_strInstData; + + GuidList m_lShallowGravesGuidList; + GuidList m_lPyramidTrollsGuidList; - uint64 m_uiAntuSulGUID; + uint32 m_uiPyramidEventTimer; }; #endif diff --git a/scripts/maelstrom/baradin_hold/baradin_hold.h b/scripts/maelstrom/baradin_hold/baradin_hold.h new file mode 100644 index 0000000000..cca726e5ed --- /dev/null +++ b/scripts/maelstrom/baradin_hold/baradin_hold.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_BARADINHOLD_H +#define DEF_BARADINHOLD_H + +#endif diff --git a/scripts/maelstrom/baradin_hold/boss_alizabal.cpp b/scripts/maelstrom/baradin_hold/boss_alizabal.cpp new file mode 100644 index 0000000000..81df56eae1 --- /dev/null +++ b/scripts/maelstrom/baradin_hold/boss_alizabal.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_alizabal +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Baradin Hold +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_alizabal() +{ +} diff --git a/scripts/maelstrom/baradin_hold/boss_argaloth.cpp b/scripts/maelstrom/baradin_hold/boss_argaloth.cpp new file mode 100644 index 0000000000..ddcfd039db --- /dev/null +++ b/scripts/maelstrom/baradin_hold/boss_argaloth.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_argaloth +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Baradin Hold +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_argaloth() +{ +} diff --git a/scripts/maelstrom/baradin_hold/boss_occu_thar.cpp b/scripts/maelstrom/baradin_hold/boss_occu_thar.cpp new file mode 100644 index 0000000000..cbe99431e0 --- /dev/null +++ b/scripts/maelstrom/baradin_hold/boss_occu_thar.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_occu_thar +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Baradin Hold +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_occu_thar() +{ +} diff --git a/scripts/maelstrom/baradin_hold/instance_baradin_hold.cpp b/scripts/maelstrom/baradin_hold/instance_baradin_hold.cpp new file mode 100644 index 0000000000..dd9842c51a --- /dev/null +++ b/scripts/maelstrom/baradin_hold/instance_baradin_hold.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_baradin_hold +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Baradin Hold +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_baradin_hold() +{ +} diff --git a/scripts/maelstrom/darkmoon_island.cpp b/scripts/maelstrom/darkmoon_island.cpp new file mode 100644 index 0000000000..aafa99e61c --- /dev/null +++ b/scripts/maelstrom/darkmoon_island.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Darkmoon Island +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Darkmoon Island +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_darkmoon_island() +{ +} diff --git a/scripts/maelstrom/deepholm.cpp b/scripts/maelstrom/deepholm.cpp new file mode 100644 index 0000000000..769bae2bdc --- /dev/null +++ b/scripts/maelstrom/deepholm.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Deepholm +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Deepholm +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_deepholm() +{ +} diff --git a/scripts/maelstrom/kezan.cpp b/scripts/maelstrom/kezan.cpp new file mode 100644 index 0000000000..ecc6ff41a2 --- /dev/null +++ b/scripts/maelstrom/kezan.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Kezan +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Kezan +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_kezan() +{ +} diff --git a/scripts/maelstrom/lost_isles.cpp b/scripts/maelstrom/lost_isles.cpp new file mode 100644 index 0000000000..f6ec9c8958 --- /dev/null +++ b/scripts/maelstrom/lost_isles.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Lost Isles +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Lost Isles +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_lost_isles() +{ +} diff --git a/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp b/scripts/maelstrom/stonecore/boss_corborus.cpp similarity index 50% rename from scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp rename to scripts/maelstrom/stonecore/boss_corborus.cpp index a898d2797c..868d2e625b 100644 --- a/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp +++ b/scripts/maelstrom/stonecore/boss_corborus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,23 +15,38 @@ */ /* ScriptData -SDName: Boss_Gatewatcher_Gyrokill +SDName: boss_corborus SD%Complete: 0 -SDComment: Place Holder -SDCategory: Tempest Keep, The Mechanar +SDComment: Placeholder +SDCategory: Stonecore EndScriptData */ #include "precompiled.h" +#include "stonecore.h" -#define SAY_AGGRO -1554000 -#define SAY_SAW_ATTACK1 -1554001 -#define SAY_SAW_ATTACK2 -1554002 -#define SAY_SLAY1 -1554003 -#define SAY_SLAY2 -1554004 -#define SAY_DEATH -1554005 +struct MANGOS_DLL_DECL boss_corborusAI : public ScriptedAI +{ + boss_corborusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + //m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + }; -#define SPELL_STREAM_OF_MACHINE_FLUID 35311 -#define SPELL_SAW_BLADE 35318 -#define H_SPELL_SAW_BLADE 39192 -#define SPELL_SHADOW_POWER 35322 -#define H_SPELL_SHADOW_POWER 39193 + void Reset() {}; +}; + +CreatureAI* GetAI_boss_corborus(Creature* pCreature) +{ + return new boss_corborusAI(pCreature); +}; + +void AddSC_boss_corborus() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_corborus"; + pNewScript->GetAI = &GetAI_boss_corborus; + pNewScript->RegisterSelf(); +}; diff --git a/scripts/maelstrom/stonecore/boss_ozruk.cpp b/scripts/maelstrom/stonecore/boss_ozruk.cpp new file mode 100644 index 0000000000..26acc0fd30 --- /dev/null +++ b/scripts/maelstrom/stonecore/boss_ozruk.cpp @@ -0,0 +1,72 @@ +/* Copyright (C) 2006 - 2013 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_ozruk +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stonecore +EndScriptData */ + +#include "precompiled.h" +#include "stonecore.h" + +struct MANGOS_DLL_DECL boss_ozrukAI : public ScriptedAI +{ + boss_ozrukAI(Creature* pCreature) : ScriptedAI(pCreature) + { + //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + //m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + }; + + void Reset() {}; +}; + +CreatureAI* GetAI_boss_ozruk(Creature* pCreature) +{ + return new boss_ozrukAI(pCreature); +}; + +struct MANGOS_DLL_DECL npc_ruptureAI : public ScriptedAI // 51422 +{ + npc_ruptureAI(Creature* creature) : ScriptedAI(creature) + { + //m_pInstance = (ScriptedInstance*)creature->GetInstanceData(); + //timerAura = 100; + }; + void Reset() {}; +}; + +CreatureAI* GetAI_npc_rupture(Creature* pCreature) +{ + return new npc_ruptureAI(pCreature); +}; + +void AddSC_boss_ozruk() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ozruk"; + pNewScript->GetAI = &GetAI_boss_ozruk; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_rupture"; + pNewScript->GetAI = &GetAI_npc_rupture; + pNewScript->RegisterSelf(); +} diff --git a/scripts/maelstrom/stonecore/boss_priestess_azil.cpp b/scripts/maelstrom/stonecore/boss_priestess_azil.cpp new file mode 100644 index 0000000000..0fa8c0b865 --- /dev/null +++ b/scripts/maelstrom/stonecore/boss_priestess_azil.cpp @@ -0,0 +1,52 @@ +/* Copyright (C) 2006 - 2013 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_priestess_azil +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stonecore +EndScriptData */ + +#include "precompiled.h" +#include "stonecore.h" + +struct MANGOS_DLL_DECL boss_princeless_azilAI : public ScriptedAI +{ + boss_princeless_azilAI(Creature* pCreature) : ScriptedAI(pCreature) + { + //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + //m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + }; + + void Reset() {}; +}; + +CreatureAI* GetAI_boss_priestess_azil(Creature* pCreature) +{ + return new boss_princeless_azilAI(pCreature); +}; + +void AddSC_boss_priestess_azil() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_princeless_azil"; + pNewScript->GetAI = &GetAI_boss_priestess_azil; + pNewScript->RegisterSelf(); +} diff --git a/scripts/maelstrom/stonecore/boss_slabhide.cpp b/scripts/maelstrom/stonecore/boss_slabhide.cpp new file mode 100644 index 0000000000..78c242add7 --- /dev/null +++ b/scripts/maelstrom/stonecore/boss_slabhide.cpp @@ -0,0 +1,69 @@ +/* Copyright (C) 2006 - 2013 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_slabhide +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stonecore +EndScriptData */ + +#include "precompiled.h" +#include "stonecore.h" + +struct MANGOS_DLL_DECL boss_slabhideAI : public ScriptedAI +{ + boss_slabhideAI(Creature* creature) : ScriptedAI(creature) + { + //m_pInstance = (ScriptedInstance*)creature->GetInstanceData(); + //m_bIsRegularMode = creature->GetMap()->IsRegularDifficulty(); + }; + + void Reset() {}; +}; + +CreatureAI* GetAI_boss_slabhide(Creature* pCreature) +{ + return new boss_slabhideAI(pCreature); +}; + +struct MANGOS_DLL_DECL npc_stalactiteAI : public ScriptedAI +{ + npc_stalactiteAI(Creature* creature) : ScriptedAI(creature) + { + }; + void Reset() {}; +}; + +CreatureAI* GetAI_npc_stalactite(Creature* pCreature) +{ + return new npc_stalactiteAI(pCreature); +}; + +void AddSC_boss_slabhide() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_slabhide"; + pNewScript->GetAI = &GetAI_boss_slabhide; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_stalactite"; + pNewScript->GetAI = &GetAI_npc_stalactite; + pNewScript->RegisterSelf(); +} diff --git a/scripts/maelstrom/stonecore/instance_stonecore.cpp b/scripts/maelstrom/stonecore/instance_stonecore.cpp new file mode 100644 index 0000000000..5443e75989 --- /dev/null +++ b/scripts/maelstrom/stonecore/instance_stonecore.cpp @@ -0,0 +1,46 @@ +/* Copyright (C) 2006 - 2013 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: instance_stonecore +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stonecore +EndScriptData */ + +#include "precompiled.h" +#include "stonecore.h" + +class MANGOS_DLL_DECL instance_stonecore : public ScriptedInstance +{ +public: + instance_stonecore(Map* map) : ScriptedInstance(map) { Initialize(); } +}; + +InstanceData* GetInstanceData_instance_stonecore(Map* pMap) +{ + return new instance_stonecore(pMap); +} + +void AddSC_instance_stonecore() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_stonecore"; + pNewScript->GetInstanceData = &GetInstanceData_instance_stonecore; + pNewScript->RegisterSelf(); +} diff --git a/scripts/maelstrom/stonecore/stonecore.cpp b/scripts/maelstrom/stonecore/stonecore.cpp new file mode 100644 index 0000000000..16f5311010 --- /dev/null +++ b/scripts/maelstrom/stonecore/stonecore.cpp @@ -0,0 +1,186 @@ +/* Copyright (C) 2006 - 2013 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 + */ + +#include "precompiled.h" +#include "stonecore.h" + +/***************************************TRASH SPELLS*************************************/ +// Crystalspawn Giant (42810) Health: 536, 810 - 1, 202, 925 +// update creature_template set +enum Spells +{ + SPELL_QUAKE = 81008, + H_SPELL_QUAKE = 92631, + + // IMP (43014) Health: 4, 468 - 7, 749, Mana: 16, 676 - 17, 816 + SPELL_FELL_FIREBALL = 80344, + H_SPELL_FELL_FIREBALL = 92638, + + // Millhouse Manastorm (43391) Health: 386, 505 - 513, 248, Mana: 186, 560 - 197, 380 + SPELL_BLUR = 81216, + SPELL_MILL_FEAR = 81442, + SPELL_FROSTBOLT_VOLLEY = 81440, + H_SPELL_FROSTBOLT_VOLLEY = 92642, + SPELL_IMPENDING_DOOM = 86830, + SPELL_SHADOW_BOLT = 81439, + H_SPELL_SHADOW_BOLT = 92641, + SPELL_SHADOWFURY = 81441, + H_SPELL_SHADOWFURY = 92644, + SPELL_TIGULE = 81220, + + // Rock Borer (43917, 42845) Health: 6, 702 - 11, 624 + SPELL_ROCK_BORE = 80028, + H_SPELL_ROCK_BORE = 92630, + + // Stonecore Berserker (43430) Health: 312, 753 - 387, 450 + SPELL_SCHARGE = 81574, + SPELL_SPINNING_SLASH = 81568, + + // Stonecore Bruiser (42692) Health: 590, 491 - 1, 202, 925 + SPELL_BODY_SLAM = 80180, + SPELL_SHOCKWAVE = 80195, + H_SPELL_SHOCKWAVE = 92640, + + // Stonecore Earthshaper (43537) Health: 250, 201 - 309, 960, Mana: 19, 394 + SPELL_DUST_STORM = 81463, + SPELL_FORCE_OF_EARTH = 81459, + SPELL_GROUND_SHOCK = 81530, + H_SPELL_GROUND_SHOCK = 92628, + SPELL_LAVA_BURST = 81576, + H_SPELL_LAVA_BURST = 92626, + + // Stonecore Flayer (42808) Health: 312, 753 - 387, 450 + SPELL_FLAY = 79922, + + // Stonecore Magmalord (42789) Health: 312, 753 - 387, 450, Mana: 25, 014 - 26, 724 + SPELL_IGNITE = 80151, + H_SPELL_IGNITE = 92636, + SPELL_MAGMA_ERUPTION = 80038, + + // Stonecore Rift Conjurer (42691) Health: 312, 753 - 387, 450, Mana: 16, 676 - 17, 816 + SPELL_DEMON_PORTAL = 80308, + SPELL_SHADOWBOLT = 80279, + H_SPELL_SHADOWBOLT = 92637, + + //Stonecore Sentry (42695) Health: 6, 702 - 11, 624 + + // Stonecore Warbringer (42696) Health: 312, 753 - 387, 450 + SPELL_CLEAVE = 15496, + SPELL_RAGE = 80158, +}; + +enum eEvents +{ + EVENT_NONE, + EVENT_QUAKE, + EVENT_FELL_FIREBALL, + EVENT_BLUR, + EVENT_MILL_FEAR, + EVENT_FROSTBOLT_VOLLEY, + EVENT_IMPENDING_DOOM, + EVENT_SHADOW_BOLT, + EVENT_SHADOWFURY, + EVENT_TIGULE, + EVENT_ROCK_BORE, + EVENT_SCHARGE, + EVENT_SPINNING_SLASH, + EVENT_BODY_SLAM, + EVENT_SHOCKWAVE, + EVENT_DUST_STORM, + EVENT_FORCE_OF_EARTH, + EVENT_GROUND_SHOCK, + EVENT_LAVA_BURST, + EVENT_FLAY, + EVENT_IGNITE, + EVENT_MAGMA_ERUPTION, + EVENT_DEMON_PORTAL, + EVENT_SHADOWBOLT, + EVENT_CLEAVE, + EVENT_RAGE, +}; + +// Crystalspawn Giant AI +struct MANGOS_DLL_DECL mob_crystalspawn_giantAI : public ScriptedAI +{ + mob_crystalspawn_giantAI(Creature* creature) : ScriptedAI(creature) { } + void Reset() {}; +}; + +// Imp AI +struct MANGOS_DLL_DECL mob_imppAI : public ScriptedAI +{ + mob_imppAI(Creature* creature) : ScriptedAI(creature) {} + void Reset() {}; +}; + +// Rock Borer AI +struct MANGOS_DLL_DECL mob_rock_borerAI : public ScriptedAI +{ + mob_rock_borerAI(Creature* creature) : ScriptedAI(creature) {} + void Reset() {}; +}; + +// Millhouse Manastorm AI +struct MANGOS_DLL_DECL mob_millhouse_manastormAI : public ScriptedAI +{ + mob_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature) {} + void Reset() {}; +}; + +CreatureAI* GetAI_mob_crystalspawn_giant(Creature* pCreature) +{ + return new mob_crystalspawn_giantAI(pCreature); +} + +CreatureAI* GetAI_mob_impp(Creature* pCreature) +{ + return new mob_imppAI(pCreature); +} + +CreatureAI* GetAI_mob_millhouse_manastorm(Creature* pCreature) +{ + return new mob_millhouse_manastormAI(pCreature); +} + +CreatureAI* GetAI_mob_rock_borer(Creature* pCreature) +{ + return new mob_rock_borerAI(pCreature); +} + +void AddSC_stonecore() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_crystalspawn_giant"; + pNewScript->GetAI = &GetAI_mob_crystalspawn_giant; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_impp"; + pNewScript->GetAI = &GetAI_mob_impp; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_millhouse_manastorm"; + pNewScript->GetAI = &GetAI_mob_millhouse_manastorm; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_rock_borer"; + pNewScript->GetAI = &GetAI_mob_rock_borer; + pNewScript->RegisterSelf(); +} diff --git a/scripts/maelstrom/stonecore/stonecore.h b/scripts/maelstrom/stonecore/stonecore.h new file mode 100644 index 0000000000..558290e17b --- /dev/null +++ b/scripts/maelstrom/stonecore/stonecore.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_STONECORE_H +#define DEF_STONECORE_H + +enum +{ + TYPE_CORBORUS = 0, + TYPE_SLABHIDE = 1, + TYPE_OZRUK = 2, + TYPE_AZIL = 3, + + MAX_ENCOUNTER = 4, +}; + +enum CreatureIds +{ + // Dungeon Bosses + + BOSS_CORBORUS = 43438, + BOSS_SLABHIDE = 43214, + BOSS_OZRUK = 42188, + BOSS_HIGH_PRIESTESS_AZIL = 42333, + + // Trash mobs + + NPC_CRYSTALSPAWN_GIANT = 42810, + NPC_IMP = 43014, + NPC_MILLHOUSE_MANASTORM = 43391, + NPC_ROCK_BORER = 43917, + NPC_ROCK_BORER2 = 42845, + NPC_STONECORE_BERSERKER = 43430, + NPC_STONECORE_BRUISER = 42692, + NPC_STONECORE_EARTHSHAPER = 43537, + NPC_STONECORE_FLAYER = 42808, + NPC_MAGMALORD = 42789, + NPC_RIFT_CONJURER = 42691, + NPC_STONECORE_SENTRY = 42695, + NPC_STONECORE_WARBRINGER = 42696, + + // Various NPCs + + NPC_EARTHWARDEN_YRSA = 50048, + NPC_STONECORE_TELEPORTER1 = 51396, + NPC_STONECORE_TELEPORTER2 = 51397, +}; + +enum GameObjectIds +{ + GO_BROKEN_PILLAR = 207407, + GO_TWILIGHT_DOCUMENTS = 207415, +}; + +#endif \ No newline at end of file diff --git a/scripts/maelstrom/the_maelstrom.cpp b/scripts/maelstrom/the_maelstrom.cpp new file mode 100644 index 0000000000..13bd247575 --- /dev/null +++ b/scripts/maelstrom/the_maelstrom.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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 Maelstrom +SD%Complete: 0 +SDComment: Placeholder +SDCategory: The Maelstrom +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_the_maelstrom() +{ +} diff --git a/scripts/maelstrom/tol_barad.cpp b/scripts/maelstrom/tol_barad.cpp new file mode 100644 index 0000000000..ef06780890 --- /dev/null +++ b/scripts/maelstrom/tol_barad.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Tol Barad +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Tol Barad +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_tol_barad() +{ +} diff --git a/scripts/maelstrom/tol_barad_peninsula.cpp b/scripts/maelstrom/tol_barad_peninsula.cpp new file mode 100644 index 0000000000..ca16e74a09 --- /dev/null +++ b/scripts/maelstrom/tol_barad_peninsula.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2006 - 2013 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: Tol Barad Peninsula +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Tol Barad Peninsula +EndScriptData */ + +/* ContentData +EndContentData */ + +#include "precompiled.h" + +/*###### +# +######*/ + +void AddSC_tol_barad_peninsula() +{ +} diff --git a/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h b/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h index 23f326c9c8..79c0c98393 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h +++ b/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -13,21 +13,107 @@ */ enum { - MAX_ENCOUNTER = 5, + MAX_ENCOUNTER = 5, + MAX_INITIATES = 15, - TYPE_NADOX = 0, - TYPE_TALDARAM = 1, - TYPE_JEDOGA = 2, - TYPE_VOLAZJ = 3, - TYPE_AMANITAR = 4, + TYPE_NADOX = 0, + TYPE_TALDARAM = 1, + TYPE_JEDOGA = 2, + TYPE_VOLAZJ = 3, + TYPE_AMANITAR = 4, - GO_DOOR_TALDARAM = 192236, - GO_ANCIENT_DEVICE_L = 193093, - GO_ANCIENT_DEVICE_R = 193094, - GO_VORTEX = 193564, + DATA_INSANITY_PLAYER = 1, - NPC_ELDER_NADOX = 29309, - NPC_JEDOGA_SHADOWSEEKER = 29310 + 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_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 +}; + +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 MANGOS_DLL_DECL instance_ahnkahet : public ScriptedInstance +{ + public: + instance_ahnkahet(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureEvade(Creature* pCreature) override; + 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; + + ObjectGuid SelectRandomGuardianEggGuid(); + ObjectGuid SelectRandomSwarmerEggGuid(); + ObjectGuid SelectJedogaSacrificeControllerGuid() { return m_jedogaSacrificeController; } + + void GetJedogaControllersList(GuidList& lList) { lList = m_lJedogaControllersGuidList; } + void GetJedogaEventControllersList(GuidList& lList) {lList = m_lJedogaEventControllersGuidList; } + + 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_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 0000000000..76e27b26eb --- /dev/null +++ b/scripts/northrend/azjol-nerub/ahnkahet/boss_amanitar.cpp @@ -0,0 +1,227 @@ +/* Copyright (C) 2006 - 2013 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_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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 1692b06df4..ef189548fe 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 - 2009 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,20 +46,37 @@ 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}, }; /*###### @@ -70,50 +87,64 @@ struct MANGOS_DLL_DECL 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 UpdateAI(const uint32 uiDiff) + 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 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,12 +403,70 @@ CreatureAI* GetAI_boss_jedoga(Creature* pCreature) return new boss_jedogaAI(pCreature); } +/*###### +## npc_twilight_volunteer +######*/ + +struct MANGOS_DLL_DECL 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* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_jedoga"; + pNewScript->GetAI = &GetAI_boss_jedoga; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_jedoga"; - newscript->GetAI = &GetAI_boss_jedoga; - newscript->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 017b089895..789cd66cba 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Nadox SD%Complete: 90% -SDComment: TODO: some more research on guardian aura needed, BroodRage needs core and db support +SDComment: Some adjustment may be required SDCategory: Ahn'kahet EndScriptData */ @@ -41,14 +41,11 @@ enum SPELL_BROOD_RAGE = 59465, SPELL_GUARDIAN_AURA = 56151, - SPELL_GUARDIAN_AURA_TRIGGERED = 56153, // JustSummoned is not called for spell summoned creatures SPELL_SUMMON_SWARM_GUARDIAN = 56120, SPELL_SUMMON_SWARMERS = 56119, - NPC_AHNKAHAR_GUARDIAN_EGG = 30173, - NPC_AHNKAHAR_SWARM_EGG = 30172, NPC_AHNKAHAR_GUARDIAN = 30176, NPC_AHNKAHAR_SWARMER = 30178 }; @@ -66,25 +63,39 @@ 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) + { + pSummoned->CastSpell(pSummoned, SPELL_GUARDIAN_AURA, true); DoScriptText(EMOTE_HATCH, m_creature); + } if (m_pInstance) { - if (Creature* pElderNadox = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(NPC_ELDER_NADOX))) + if (Creature* pElderNadox = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_NADOX)) { float fPosX, fPosY, fPosZ; pElderNadox->GetPosition(fPosX, fPosY, fPosZ); + pSummoned->SetWalk(false); pSummoned->GetMotionMaster()->MovePoint(0, fPosX, fPosY, fPosZ); } } } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // If the Guardian is killed set the achiev criteria to false + if (pSummoned->GetEntry() == NPC_AHNKAHAR_GUARDIAN) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NADOX, SPECIAL); + } + } }; CreatureAI* GetAI_mob_ahnkahar_egg(Creature* pCreature) @@ -100,12 +111,12 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI { boss_nadoxAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_ahnkahet*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_ahnkahet* m_pInstance; bool m_bIsRegularMode; bool m_bBerserk; @@ -114,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; @@ -123,28 +134,23 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI m_uiBroodRageTimer = 20000; } - Creature* SelectRandomCreatureOfEntryInRange(uint32 uiEntry, float fRange) + void Aggro(Unit* /*pWho*/) override { - std::list lCreatureList; - GetCreatureListWithEntryInGrid(lCreatureList, m_creature, uiEntry, fRange); - - if (lCreatureList.empty()) - return NULL; - - std::list::iterator iter = lCreatureList.begin(); - advance(iter, urand(0, lCreatureList.size()-1)); + DoScriptText(SAY_AGGRO, m_creature); - return *iter; + if (m_pInstance) + m_pInstance->SetData(TYPE_NADOX, IN_PROGRESS); } - void Aggro(Unit* pWho) + void JustReachedHome() override { - DoScriptText(SAY_AGGRO, m_creature); + 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; @@ -152,12 +158,15 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + 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; @@ -165,20 +174,31 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI if (!m_bGuardianSummoned && m_creature->GetHealthPercent() < 50.0f) { // guardian is summoned at 50% of boss HP - if (Creature* pGuardianEgg = SelectRandomCreatureOfEntryInRange(NPC_AHNKAHAR_GUARDIAN_EGG, 75.0f)) - pGuardianEgg->CastSpell(pGuardianEgg, SPELL_SUMMON_SWARM_GUARDIAN, false); + if (m_pInstance) + { + if (Creature* pGuardianEgg = m_creature->GetMap()->GetCreature(m_pInstance->SelectRandomGuardianEggGuid())) + pGuardianEgg->CastSpell(pGuardianEgg, SPELL_SUMMON_SWARM_GUARDIAN, false); - m_bGuardianSummoned = true; + m_bGuardianSummoned = true; + } } if (m_uiSummonTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_SUMMON_EGG_1 : SAY_SUMMON_EGG_2, m_creature); + if (roll_chance_i(50)) + DoScriptText(urand(0, 1) ? SAY_SUMMON_EGG_1 : SAY_SUMMON_EGG_2, m_creature); - if (Creature* pSwarmerEgg = SelectRandomCreatureOfEntryInRange(NPC_AHNKAHAR_SWARM_EGG, 75.0)) - pSwarmerEgg->CastSpell(pSwarmerEgg, SPELL_SUMMON_SWARMERS, false); + if (m_pInstance) + { + // There are 2 Swarmers summoned at a timer + if (Creature* pSwarmerEgg = m_creature->GetMap()->GetCreature(m_pInstance->SelectRandomSwarmerEggGuid())) + { + for (uint8 i = 0; i < 2; ++i) + pSwarmerEgg->CastSpell(pSwarmerEgg, SPELL_SUMMON_SWARMERS, false); + } + } - m_uiSummonTimer = 10000; + m_uiSummonTimer = urand(5000, 10000); } else m_uiSummonTimer -= uiDiff; @@ -197,10 +217,8 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI { if (m_uiBroodRageTimer < uiDiff) { - if (Creature* pRageTarget = SelectRandomCreatureOfEntryInRange(NPC_AHNKAHAR_SWARMER, 50.0)) - DoCastSpellIfCan(pRageTarget, SPELL_BROOD_RAGE); - - m_uiBroodRageTimer = 20000; + if (DoCastSpellIfCan(m_creature, SPELL_BROOD_RAGE) == CAST_OK) + m_uiBroodRageTimer = 20000; } else m_uiBroodRageTimer -= uiDiff; @@ -208,8 +226,8 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI if (!m_bBerserk && m_creature->GetPositionZ() < 24.0) { - m_bBerserk = true; - DoCastSpellIfCan(m_creature, SPELL_BERSERK); + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_bBerserk = true; } DoMeleeAttackIfReady(); @@ -223,15 +241,15 @@ CreatureAI* GetAI_boss_nadox(Creature* pCreature) void AddSC_boss_nadox() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_nadox"; - newscript->GetAI = &GetAI_boss_nadox; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_nadox"; + pNewScript->GetAI = &GetAI_boss_nadox; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_ahnkahar_egg"; - newscript->GetAI = &GetAI_mob_ahnkahar_egg; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_ahnkahar_egg"; + pNewScript->GetAI = &GetAI_mob_ahnkahar_egg; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp index 2b2c6b58b4..1dc4013ec5 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Taldaram -SD%Complete: 20% -SDComment: +SD%Complete: 90% +SDComment: Timers; SDCategory: Ahn'kahet EndScriptData */ @@ -34,7 +34,24 @@ 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, }; /*###### @@ -45,26 +62,51 @@ struct MANGOS_DLL_DECL 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,33 +292,52 @@ 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 GOHello_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_UNK1); return false; } void AddSC_boss_taldaram() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_taldaram"; - newscript->GetAI = &GetAI_boss_taldaram; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_taldaram"; + pNewScript->GetAI = &GetAI_boss_taldaram; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_conjure_flame_orbs; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "go_nerubian_device"; - newscript->pGOHello = &GOHello_go_nerubian_device; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_nerubian_device"; + pNewScript->pGOUse = &GOUse_go_nerubian_device; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp index 9d934720c4..63277c9f26 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,14 +16,15 @@ /* ScriptData SDName: Boss_Volazj -SD%Complete: 20% -SDComment: +SD%Complete: 50% +SDComment: Insanity NYI; Timers need adjustments SDCategory: Ahn'kahet EndScriptData */ #include "precompiled.h" +#include "ahnkahet.h" +#include "TemporarySummon.h" -//TODO: fill in texts in database. Also need to add text for whisper. enum { SAY_AGGRO = -1619033, @@ -31,10 +32,44 @@ enum SAY_SLAY_1 = -1619035, SAY_SLAY_2 = -1619036, SAY_SLAY_3 = -1619037, - SAY_DEATH_1 = -1619038, - SAY_DEATH_2 = -1619039 + SAY_DEATH_1 = -1619038, // missing text + SAY_DEATH_2 = -1619039, + + SPELL_MIND_FLAY = 57941, + SPELL_MIND_FLAY_H = 59974, + SPELL_SHADOW_BOLT = 57942, + SPELL_SHADOW_BOLT_H = 59975, + 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_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 ######*/ @@ -51,35 +86,197 @@ struct MANGOS_DLL_DECL boss_volazjAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint8 m_uiCombatPhase; + uint32 m_uiMindFlayTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiShiverTimer; + + uint8 m_uiInsanityIndex; + bool m_bIsInsanityInProgress; + + void Reset() override { + 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; + // 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) + m_uiMindFlayTimer = urand(10000, 20000); + } + else + m_uiMindFlayTimer -= uiDiff; + + if (m_uiShadowBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT_H) == CAST_OK) + m_uiShadowBoltTimer = urand(8000, 13000); + } + else + m_uiShadowBoltTimer -= uiDiff; + + if (m_uiShiverTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHIVER : SPELL_SHIVER_H) == CAST_OK) + m_uiShiverTimer = 30000; + } + } + else + m_uiShiverTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -91,10 +288,10 @@ CreatureAI* GetAI_boss_volazj(Creature* pCreature) void AddSC_boss_volazj() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_volazj"; - newscript->GetAI = &GetAI_boss_volazj; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_volazj"; + pNewScript->GetAI = &GetAI_boss_volazj; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp b/scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp index 5dee80b572..e9bb1baa16 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,179 +16,406 @@ /* ScriptData SDName: instance_ahnkahet -SD%Complete: 0 +SD%Complete: 75 SDComment: SDCategory: Ahn'kahet EndScriptData */ #include "precompiled.h" #include "ahnkahet.h" +#include "TemporarySummon.h" -struct MANGOS_DLL_DECL instance_ahnkahet : public ScriptedInstance +instance_ahnkahet::instance_ahnkahet(Map* pMap) : ScriptedInstance(pMap), + m_bRespectElders(false), + m_bVolunteerWork(false), + m_uiDevicesActivated(0), + m_uiInitiatesKilled(0), + m_uiTwistedVisageCount(0) { - instance_ahnkahet(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; +void instance_ahnkahet::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - uint64 m_uiElderNadoxGUID; - uint64 m_uiJedogaShadowseekerGUID; - uint64 m_uiTaldaramDoorGUID; - uint64 m_uiTaldaramVortexGUID; - uint8 m_uiDevicesActivated; +void instance_ahnkahet::OnCreatureCreate(Creature* pCreature) +{ + 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: + m_GuardianEggList.push_back(pCreature->GetObjectGuid()); + break; + 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 Initialize() +void instance_ahnkahet::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + case GO_DOOR_TALDARAM: + if (m_auiEncounter[TYPE_TALDARAM] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_VORTEX: + if (m_auiEncounter[TYPE_TALDARAM] == SPECIAL) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + + case GO_ANCIENT_DEVICE_L: + case GO_ANCIENT_DEVICE_R: + if (m_auiEncounter[TYPE_NADOX] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; - m_uiElderNadoxGUID = 0; - m_uiJedogaShadowseekerGUID = 0; - m_uiTaldaramDoorGUID = 0; - m_uiTaldaramVortexGUID = 0; - m_uiDevicesActivated = 0; + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_ahnkahet::SetData(uint32 uiType, uint32 uiData) +{ + debug_log("SD2: Instance Ahn'Kahet: SetData received for type %u with data %u", uiType, uiData); - void OnCreatureCreate(Creature* pCreature) + switch (uiType) { - switch(pCreature->GetEntry()) - { - case NPC_ELDER_NADOX: m_uiElderNadoxGUID = pCreature->GetGUID(); break; - case NPC_JEDOGA_SHADOWSEEKER: m_uiJedogaShadowseekerGUID = pCreature->GetGUID(); break; - } + case TYPE_NADOX: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + m_bRespectElders = true; + 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) + { + ++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); + } + } + } + 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) + { + m_uiTwistedVisageCount = 0; + m_lInsanityPlayersGuidList.clear(); + } + break; + + default: + script_error_log("Instance Ahn'Kahet: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + break; } - void OnObjectCreate(GameObject* pGo) + // For some encounters Special data needs to be saved + if (uiData == DONE || (uiData == SPECIAL && uiType == TYPE_TALDARAM)) { - switch(pGo->GetEntry()) - { - case GO_DOOR_TALDARAM: - m_uiTaldaramDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - DoUseDoorOrButton(m_uiTaldaramDoorGUID); - break; - case GO_ANCIENT_DEVICE_L: - if (m_auiEncounter[1] == NOT_STARTED) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - case GO_ANCIENT_DEVICE_R: - if (m_auiEncounter[1] == NOT_STARTED) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - case GO_VORTEX: - m_uiTaldaramVortexGUID = pGo->GetGUID(); - if (m_auiEncounter[1] != NOT_STARTED) - DoUseDoorOrButton(m_uiTaldaramVortexGUID); - break; - } + 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; } - - void SetData(uint32 uiType, uint32 uiData) +} + +void instance_ahnkahet::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - debug_log("SD2: Instance Ahn'Kahet: SetData received for type %u with data %u",uiType,uiData); + case NPC_TWILIGHT_INITIATE: + ++m_uiInitiatesKilled; - switch(uiType) - { - case TYPE_NADOX: - m_auiEncounter[0] = uiData; - break; - case TYPE_TALDARAM: - if (uiData == SPECIAL) + // 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 (m_uiDevicesActivated < 2) - ++m_uiDevicesActivated; + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->InterruptNonMeleeSpells(false); + } + } - if (m_uiDevicesActivated == 2) - { - m_auiEncounter[1] = uiData; - DoUseDoorOrButton(m_uiTaldaramVortexGUID); - } + 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(); } - if (uiData == DONE) + + // 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()) { - m_auiEncounter[1] = uiData; - DoUseDoorOrButton(m_uiTaldaramDoorGUID); + TemporarySummon* pTemporary = (TemporarySummon*)pCreature; + + // Switch insanity phase for the master player + if (Player* pPlayer = instance->GetPlayer(pTemporary->GetSummonerGuid())) + HandleInsanitySwitch(pPlayer); } - break; - case TYPE_JEDOGA: - m_auiEncounter[2] = uiData; - break; - case TYPE_VOLAZJ: - m_auiEncounter[3] = uiData; - break; - case TYPE_AMANITAR: - m_auiEncounter[4] = uiData; - break; - default: - error_log("SD2: Instance Ahn'Kahet: ERROR SetData = %u for type %u does not exist/not implemented.",uiType,uiData); - break; - } + } + break; + } +} - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; +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; - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] - << " " << m_auiEncounter[4]; + // 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(); + } - strInstData = saveStream.str(); + // Clear insanity manually for now, because the spell won't hit phased players + HandleInsanityClear(); - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + SetData(TYPE_VOLAZJ, IN_PROGRESS); + } + + pCreature->ForcedDespawn(); + break; } +} - const char* Save() +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) { - return strInstData.c_str(); + if (Player* pPlayer = instance->GetPlayer(ObjectGuid(uiGuid))) + m_lInsanityPlayersGuidList.push_back(pPlayer->GetObjectGuid()); } +} + +ObjectGuid instance_ahnkahet::SelectRandomGuardianEggGuid() +{ + if (m_GuardianEggList.empty()) + return ObjectGuid(); + + GuidList::iterator iter = m_GuardianEggList.begin(); + advance(iter, urand(0, m_GuardianEggList.size() - 1)); + + return *iter; +} + +ObjectGuid instance_ahnkahet::SelectRandomSwarmerEggGuid() +{ + if (m_SwarmerEggList.empty()) + return ObjectGuid(); - void Load(const char* chrIn) + GuidList::iterator iter = m_SwarmerEggList.begin(); + advance(iter, urand(0, m_SwarmerEggList.size() - 1)); + + return *iter; +} + +void instance_ahnkahet::HandleInsanityClear() +{ + for (GuidList::const_iterator itr = m_lInsanityPlayersGuidList.begin(); itr != m_lInsanityPlayersGuidList.end(); ++itr) { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + if (Player* pPlayer = instance->GetPlayer(*itr)) + pPlayer->RemoveSpellsCausingAura(SPELL_AURA_PHASE); + } +} - OUT_LOAD_INST_DATA(chrIn); +void instance_ahnkahet::HandleInsanitySwitch(Player* pPhasedPlayer) +{ + // Get the phase aura id + Unit::AuraList lAuraList = pPhasedPlayer->GetAurasByType(SPELL_AURA_PHASE); + if (lAuraList.empty()) + return; + + uint32 uiPhaseAura = (*lAuraList.begin())->GetId(); - std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; + std::list lSamePhasePlayers; + std::vector vOtherPhasePlayers; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + // 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 (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; + 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 + Unit::AuraList 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; - OUT_LOAD_INST_DATA_COMPLETE; + default: + return false; } +} - uint32 GetData(uint32 uiType) +void instance_ahnkahet::Load(const char* chrIn) +{ + if (!chrIn) { - switch(uiType) - { - case TYPE_TALDARAM: - return m_auiEncounter[0]; - case TYPE_JEDOGA: - return m_auiEncounter[1]; - } - return 0; + OUT_LOAD_INST_DATA_FAIL; + return; } - uint64 GetData64(uint32 uiData) + 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) { - switch(uiData) - { - case NPC_ELDER_NADOX: - return m_uiElderNadoxGUID; - case NPC_JEDOGA_SHADOWSEEKER: - return m_uiJedogaShadowseekerGUID; - } - return 0; + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } -}; + + OUT_LOAD_INST_DATA_COMPLETE; +} + +uint32 instance_ahnkahet::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} InstanceData* GetInstanceData_instance_ahnkahet(Map* pMap) { @@ -197,10 +424,10 @@ InstanceData* GetInstanceData_instance_ahnkahet(Map* pMap) void AddSC_instance_ahnkahet() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "instance_ahnkahet"; - newscript->GetInstanceData = &GetInstanceData_instance_ahnkahet; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "instance_ahnkahet"; + pNewScript->GetInstanceData = &GetInstanceData_instance_ahnkahet; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h b/scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h index 29f8258a07..e391c81c1b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,64 +7,105 @@ enum { - MAX_ENCOUNTER = 3, - MAX_WATCHERS = 3, + MAX_ENCOUNTER = 3, - TYPE_KRIKTHIR = 0, - TYPE_HADRONOX = 1, - TYPE_ANUBARAK = 2, + TYPE_KRIKTHIR = 0, + TYPE_HADRONOX = 1, + TYPE_ANUBARAK = 2, - NPC_KRIKTHIR = 28684, + NPC_KRIKTHIR = 28684, + NPC_HADRONOX = 28921, + NPC_ANUBARAK = 29120, - SAY_SEND_GROUP_1 = -1601004, - SAY_SEND_GROUP_2 = -1601005, - SAY_SEND_GROUP_3 = -1601006, + SAY_SEND_GROUP_1 = -1601004, + SAY_SEND_GROUP_2 = -1601005, + SAY_SEND_GROUP_3 = -1601006, - NPC_GASHRA = 28730, - NPC_NARJIL = 28729, - NPC_SILTHIK = 28731, + NPC_GASHRA = 28730, + NPC_NARJIL = 28729, + NPC_SILTHIK = 28731, + NPC_ANUBAR_CRUSHER = 28922, - GO_DOOR_KRIKTHIR = 192395, - GO_DOOR_ANUBARAK_1 = 192396, - GO_DOOR_ANUBARAK_2 = 192397, - GO_DOOR_ANUBARAK_3 = 192398 + 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 }; -struct MANGOS_DLL_DECL instance_azjol_nerub : public ScriptedInstance +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}; + +class MANGOS_DLL_DECL instance_azjol_nerub : public ScriptedInstance { public: instance_azjol_nerub(Map* pMap); - ~instance_azjol_nerub() {}; - - void Initialize(); - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); - void OnCreatureEvade(Creature* pCreature); - void OnCreatureEnterCombat(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); - void SetData(uint32 uiType, uint32 uiData); - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); - void Update(uint32 uiDiff); + + void Initialize() override; + + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + + 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*/) const override; + + ObjectGuid GetRandomAssassinTrigger(); + ObjectGuid GetGuardianTrigger() { return m_guardianSummonTarget; } + ObjectGuid GetDarterTrigger() { return m_darterSummonTarget; } + ObjectGuid GetAnubTrigger() { return m_anubSummonTarget; } + + 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) override; + + private: void DoSendWatcherOrKrikthir(); + void DoSortWorldTriggers(); - protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; + std::string m_strInstData; - uint64 m_uiDoorKrikthirGUID; - uint64 m_uiDoorAnubarak1GUID; - uint64 m_uiDoorAnubarak2GUID; - uint64 m_uiDoorAnubarak3GUID; + ObjectGuid m_playerGuid; - uint64 m_uiKrikthirGUID; - uint64 m_uiGashraGUID; - uint64 m_uiNarjilGUID; - uint64 m_uiSilthikGUID; + // Hadronox triggers + GuidList m_lSpiderTriggersGuids; - uint64 m_uiPlayerGUID; + // Anub triggers + ObjectGuid m_darterSummonTarget; + ObjectGuid m_guardianSummonTarget; + ObjectGuid m_anubSummonTarget; + GuidVector m_vAssassinSummonTargetsVect; + GuidList m_lTriggerGuids; - uint64 m_auiWatcherGUIDS[3]; 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 461e7f5e2d..cb51344998 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,9 @@ /* ScriptData SDName: Boss_Anubarak -SD%Complete: 20% -SDComment: -SDCategory: Azjol'NerubstrInstData +SD%Complete: 80% +SDComment: Summoned creatures movement may need some adjustments - may be solved with movement maps +SDCategory: Azjol'Nerub EndScriptData */ #include "precompiled.h" @@ -36,9 +36,41 @@ enum SAY_LOCUST_1 = -1601021, SAY_LOCUST_2 = -1601022, SAY_LOCUST_3 = -1601023, - SAY_DEATH = -1601024 + SAY_DEATH = -1601024, + + SPELL_CARRION_BEETLES = 53520, + SPELL_LEECHING_SWARM = 53467, + SPELL_LEECHING_SWARM_H = 59430, + SPELL_IMPALE_AURA = 53456, // ticks at each 10 secs - summons 29184 + SPELL_POUND = 53472, + SPELL_POUND_H = 59433, + SPELL_SUBMERGE = 53421, + SPELL_EMERGE = 53500, + + // NOTES: + // The Assassin and Guardian summon spell should be 53609 and 53613 + // They are currently not used because of the ignore LoS issue in core + SPELL_SUMMON_ASSASSIN = 53610, // summons 29214 + SPELL_SUMMON_GUARDIAN = 53614, // summons 29216 + 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, + NPC_ANUBAR_VENOMANCER = 29217, + NPC_IMPALE_TARGET = 29184, + + PHASE_GROUND = 1, + PHASE_SUBMERGED = 2 }; + /*###### ## boss_anubarak ######*/ @@ -49,17 +81,39 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI { m_pInstance = (instance_azjol_nerub*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bDoneIntro = false; Reset(); } instance_azjol_nerub* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint8 m_uiPhase; + uint8 m_uiSubmergePhase; + + uint32 m_uiCarrionBeetlesTimer; + uint32 m_uiLeechingSwarmTimer; + uint32 m_uiPoundTimer; + uint32 m_uiEmergeTimer; + uint32 m_uiSummonTimer; + uint32 m_uiDarterTimer; + bool m_bIsFirstWave; + bool m_bDoneIntro; + + void Reset() override { + m_uiPhase = PHASE_GROUND; + m_uiSubmergePhase = 1; + + m_uiCarrionBeetlesTimer = 8000; + m_uiLeechingSwarmTimer = 20000; + m_uiPoundTimer = 15000; + m_uiDarterTimer = 5000; + + 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); @@ -67,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; @@ -77,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); @@ -85,18 +139,180 @@ 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 UpdateAI(const uint32 uiDiff) + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bDoneIntro && m_creature->IsWithinDistInMap(pWho, 60.0f)) + { + DoScriptText(SAY_INTRO, m_creature); + m_bDoneIntro = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustSummoned(Creature* pSummoned) override + { + if (!m_pInstance) + return; + + switch (pSummoned->GetEntry()) + { + case NPC_ANUBAR_GUARDIAN: + case NPC_ANUBAR_VENOMANCER: + pSummoned->SetWalk(false); + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetAnubTrigger())) + pSummoned->GetMotionMaster()->MovePoint(0, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ()); + break; + case NPC_ANUBAR_DARTER: + case NPC_ANUBAR_ASSASSIN: + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetAnubTrigger())) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 15.0f, fX, fY, fZ); + + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + break; + case NPC_IMPALE_TARGET: + pSummoned->CastSpell(pSummoned, SPELL_IMPALE_VISUAL, true); + break; + default: + break; + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); + if (m_uiPhase == PHASE_GROUND) + { + if (m_uiLeechingSwarmTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LEECHING_SWARM : SPELL_LEECHING_SWARM_H) == CAST_OK) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_LOCUST_1, m_creature); break; + case 1: DoScriptText(SAY_LOCUST_2, m_creature); break; + case 2: DoScriptText(SAY_LOCUST_3, m_creature); break; + } + + m_uiLeechingSwarmTimer = 19000; + } + } + else + m_uiLeechingSwarmTimer -= uiDiff; + + if (m_uiCarrionBeetlesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CARRION_BEETLES) == CAST_OK) + m_uiCarrionBeetlesTimer = 25000; + } + else + m_uiCarrionBeetlesTimer -= uiDiff; + + if (m_uiPoundTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_POUND : SPELL_POUND_H) == CAST_OK) + m_uiPoundTimer = 16000; + } + else + m_uiPoundTimer -= uiDiff; + + 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_uiPhase = PHASE_SUBMERGED; + m_bIsFirstWave = true; + m_uiSummonTimer = 5000; + + // Emerge timers aren't the same. They depend on the submerge phase + switch (m_uiSubmergePhase) + { + case 1: + m_uiEmergeTimer = 20000; + break; + case 2: + m_uiEmergeTimer = 45000; + break; + case 3: + m_uiEmergeTimer = 50000; + break; + } + ++m_uiSubmergePhase; + } + + DoMeleeAttackIfReady(); + } + else if (m_uiPhase == PHASE_SUBMERGED) + { + if (m_uiSummonTimer < uiDiff) + { + if (!m_pInstance) + return; + + // Summon 2 Assassins + for (uint8 i = 0; i < 2; ++i) + { + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetRandomAssassinTrigger())) + pTrigger->CastSpell(pTrigger, SPELL_SUMMON_ASSASSIN, true, NULL, NULL, m_creature->GetObjectGuid()); + } + + // on the first wave summon a guardian; on the second wave summon a venonmancer + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetGuardianTrigger())) + { + pTrigger->CastSpell(pTrigger, m_bIsFirstWave ? SPELL_SUMMON_GUARDIAN : SPELL_SUMMON_VENOMANCER, true, NULL, NULL, m_creature->GetObjectGuid()); + m_bIsFirstWave = false; + } + + m_uiSummonTimer = 26000; + } + else + m_uiSummonTimer -= uiDiff; + + // only on the last submerge phase + if (m_uiSubmergePhase == 4) + { + if (m_uiDarterTimer < uiDiff) + { + if (!m_pInstance) + return; + + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetDarterTrigger())) + { + pTrigger->CastSpell(pTrigger, SPELL_SUMMON_DARTER, true, NULL, NULL, m_creature->GetObjectGuid()); + m_uiDarterTimer = urand(10000, 15000); + } + } + else + m_uiDarterTimer -= uiDiff; + } + + if (m_uiEmergeTimer < uiDiff) + { + 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_uiPhase = PHASE_GROUND; + } + else + m_uiEmergeTimer -= uiDiff; + } + + EnterEvadeIfOutOfCombatArea(uiDiff); } }; @@ -105,6 +321,61 @@ CreatureAI* GetAI_boss_anubarak(Creature* pCreature) return new boss_anubarakAI(pCreature); } +/*###### +## npc_impale_target +######*/ + +struct MANGOS_DLL_DECL 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; @@ -113,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 0189f7348e..5b7a1412b1 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Hadronox -SD%Complete: 20% -SDComment: +SD%Complete: 90% +SDComment: Some details and timers can be improved. SDCategory: Azjol'Nerub EndScriptData */ @@ -26,9 +26,35 @@ EndScriptData */ enum { + EMOTE_MOVE_TUNNEL = -1601013, + SPELL_TAUNT = 53799, + SPELL_PIERCE_ARMOR = 53418, + SPELL_ACID_CLOUD = 53400, + SPELL_ACID_CLOUD_H = 59419, + SPELL_LEECH_POISON = 53030, + SPELL_LEECH_POISON_H = 59417, + SPELL_WEB_GRAB = 57731, + SPELL_WEB_GRAB_H = 59421, + + // 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, }; +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 ######*/ @@ -39,26 +65,220 @@ struct MANGOS_DLL_DECL boss_hadronoxAI : public ScriptedAI { m_pInstance = (instance_azjol_nerub*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_uiGauntletStartTimer = 1000; Reset(); } instance_azjol_nerub* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiGauntletStartTimer; + + uint32 m_uiAcidTimer; + uint32 m_uiLeechTimer; + uint32 m_uiPierceTimer; + uint32 m_uiGrabTimer; + uint32 m_uiTauntTimer; + + 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 = urand(8000, 15000); + } + else + m_uiPierceTimer -= uiDiff; + + if (m_uiAcidTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ACID_CLOUD : SPELL_ACID_CLOUD_H) == CAST_OK) + m_uiAcidTimer = urand(10000, 15000); + } + } + else + m_uiAcidTimer -= uiDiff; + + if (m_uiLeechTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_LEECH_POISON : SPELL_LEECH_POISON_H) == CAST_OK) + m_uiLeechTimer = urand(10000, 15000); + } + } + else + m_uiLeechTimer -= uiDiff; + + if (m_uiGrabTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WEB_GRAB : SPELL_WEB_GRAB_H) == CAST_OK) + m_uiGrabTimer = urand(25000, 30000); + } + 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 e122b40693..7256fded66 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 4920327e0d..cf01029a2f 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -25,19 +25,11 @@ EndScriptData */ #include "azjol-nerub.h" instance_azjol_nerub::instance_azjol_nerub(Map* pMap) : ScriptedInstance(pMap), - m_uiDoorKrikthirGUID(0), - m_uiDoorAnubarak1GUID(0), - m_uiDoorAnubarak2GUID(0), - m_uiDoorAnubarak3GUID(0), - - m_uiKrikthirGUID(0), - m_uiGashraGUID(0), - m_uiNarjilGUID(0), - m_uiSilthikGUID(0), - - m_uiPlayerGUID(0), - - m_uiWatcherTimer(0) + m_uiWatcherTimer(0), + m_uiGauntletEndTimer(0), + m_bWatchHimDie(true), + m_bHadronoxDenied(true), + m_bGauntletStarted(false) { Initialize(); } @@ -45,44 +37,45 @@ instance_azjol_nerub::instance_azjol_nerub(Map* pMap) : ScriptedInstance(pMap), void instance_azjol_nerub::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_auiWatcherGUIDS, 0, sizeof(m_auiWatcherGUIDS)); } void instance_azjol_nerub::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_DOOR_KRIKTHIR: - m_uiDoorKrikthirGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) + if (m_auiEncounter[TYPE_KRIKTHIR] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_DOOR_ANUBARAK_1: - m_uiDoorAnubarak1GUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE || m_auiEncounter[2] == NOT_STARTED) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_DOOR_ANUBARAK_2: - m_uiDoorAnubarak2GUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE || m_auiEncounter[2] == NOT_STARTED) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_DOOR_ANUBARAK_3: - m_uiDoorAnubarak3GUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE || m_auiEncounter[2] == NOT_STARTED) - pGo->SetGoState(GO_STATE_ACTIVE); break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } void instance_azjol_nerub::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - case NPC_KRIKTHIR: m_uiKrikthirGUID = pCreature->GetGUID(); break; - case NPC_GASHRA: m_auiWatcherGUIDS[0] = pCreature->GetGUID(); break; - case NPC_NARJIL: m_auiWatcherGUIDS[1] = pCreature->GetGUID(); break; - case NPC_SILTHIK: m_auiWatcherGUIDS[2] = pCreature->GetGUID(); break; + 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; } } @@ -91,8 +84,11 @@ void instance_azjol_nerub::OnCreatureDeath(Creature* pCreature) uint32 uiEntry = pCreature->GetEntry(); if (uiEntry == NPC_GASHRA || uiEntry == NPC_NARJIL || uiEntry == NPC_SILTHIK) { - if (m_auiEncounter[0] == NOT_STARTED) + if (m_auiEncounter[TYPE_KRIKTHIR] == NOT_STARTED) m_uiWatcherTimer = 5000; + + // Set achiev criteriat to false if one of the watchers dies + m_bWatchHimDie = false; } } @@ -103,8 +99,34 @@ void instance_azjol_nerub::OnCreatureEnterCombat(Creature* pCreature) if (uiEntry == NPC_GASHRA || uiEntry == NPC_NARJIL || uiEntry == NPC_SILTHIK) { // Creature enter combat is not equal to having a victim yet. - if (!m_uiPlayerGUID && pCreature->getVictim()) - m_uiPlayerGUID = pCreature->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->GetGUID(); + 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; } } @@ -112,7 +134,7 @@ void instance_azjol_nerub::OnCreatureEvade(Creature* pCreature) { uint32 uiEntry = pCreature->GetEntry(); if (uiEntry == NPC_GASHRA || uiEntry == NPC_NARJIL || uiEntry == NPC_SILTHIK) - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); } void instance_azjol_nerub::Update(uint32 uiDiff) @@ -127,19 +149,41 @@ 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() { Creature* pAttacker = NULL; - Creature* pKrikthir = instance->GetCreature(m_uiKrikthirGUID); + Creature* pKrikthir = GetSingleCreatureFromStorage(NPC_KRIKTHIR); if (!pKrikthir) return; - for (uint8 i = 0; i < MAX_WATCHERS; ++i) + for (uint8 i = 0; i < countof(aWatchers); ++i) { - if (Creature* pTemp = instance->GetCreature(m_auiWatcherGUIDS[i])) + if (Creature* pTemp = GetSingleCreatureFromStorage(aWatchers[i])) { if (pTemp->isAlive()) { @@ -153,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; @@ -163,30 +207,90 @@ void instance_azjol_nerub::DoSendWatcherOrKrikthir() else pAttacker = pKrikthir; - if (Unit* pTarget = instance->GetUnit(m_uiPlayerGUID)) + if (Player* pTarget = instance->GetPlayer(m_playerGuid)) { if (pTarget->isAlive()) pAttacker->AI()->AttackStart(pTarget); } } +void instance_azjol_nerub::DoSortWorldTriggers() +{ + if (Creature* pAnub = GetSingleCreatureFromStorage(NPC_ANUBARAK)) + { + float fZ = pAnub->GetPositionZ(); + float fTriggZ = 0; + + for (GuidList::const_iterator itr = m_lTriggerGuids.begin(); itr != m_lTriggerGuids.end(); ++itr) + { + if (Creature* pTrigg = instance->GetCreature(*itr)) + { + // Sort only triggers in a range of 100 + if (pTrigg->GetPositionY() < pAnub->GetPositionY() + 110) + { + fTriggZ = pTrigg->GetPositionZ(); + + // One npc below the platform + if (fTriggZ < fZ + aSortDistance[0]) + m_darterSummonTarget = pTrigg->GetObjectGuid(); + // One npc on the boss platform - used to handle the summoned movement + else if (fTriggZ < fZ + aSortDistance[1]) + m_anubSummonTarget = pTrigg->GetObjectGuid(); + // One npc on the upper pathway + else if (fTriggZ < fZ + aSortDistance[2]) + m_guardianSummonTarget = pTrigg->GetObjectGuid(); + // Eight npcs on the upper ledges + else if (fTriggZ < fZ + aSortDistance[3]) + m_vAssassinSummonTargetsVect.push_back(pTrigg->GetObjectGuid()); + } + } + } + } +} + +ObjectGuid instance_azjol_nerub::GetRandomAssassinTrigger() +{ + // Get a random summon target + if (m_vAssassinSummonTargetsVect.size() > 0) + 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[0] = uiData; + m_auiEncounter[uiType] = uiData; if (uiData == DONE) - DoUseDoorOrButton(m_uiDoorKrikthirGUID); + DoUseDoorOrButton(GO_DOOR_KRIKTHIR); break; case TYPE_HADRONOX: - m_auiEncounter[1] = uiData; + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + ResetHadronoxTriggers(); break; case TYPE_ANUBARAK: - m_auiEncounter[2] = uiData; - DoUseDoorOrButton(m_uiDoorAnubarak1GUID); - DoUseDoorOrButton(m_uiDoorAnubarak2GUID); - DoUseDoorOrButton(m_uiDoorAnubarak3GUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_DOOR_ANUBARAK_1); + DoUseDoorOrButton(GO_DOOR_ANUBARAK_2); + DoUseDoorOrButton(GO_DOOR_ANUBARAK_3); + if (uiData == IN_PROGRESS) + { + DoSortWorldTriggers(); + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_ANUB_ID); + } break; } @@ -197,13 +301,35 @@ void instance_azjol_nerub::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; } } +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 +{ + switch (uiCriteriaId) + { + case ACHIEV_CRITERIA_WATCH_DIE: + return m_bWatchHimDie; + case ACHIEV_CRITERIA_DENIED: + return m_bHadronoxDenied; + + default: + return false; + } +} + void instance_azjol_nerub::Load(const char* chrIn) { if (!chrIn) @@ -217,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; @@ -234,6 +360,7 @@ InstanceData* GetInstanceData_instance_azjol_nerub(Map* pMap) void AddSC_instance_azjol_nerub() { Script* pNewScript; + pNewScript = new Script; pNewScript->Name = "instance_azjol-nerub"; pNewScript->GetInstanceData = &GetInstanceData_instance_azjol_nerub; diff --git a/scripts/northrend/borean_tundra.cpp b/scripts/northrend/borean_tundra.cpp index d6eb0c01a3..7a28c0d0c2 100644 --- a/scripts/northrend/borean_tundra.cpp +++ b/scripts/northrend/borean_tundra.cpp @@ -1,4 +1,5 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 * This program is free software; you can redistribute it and/or modify * 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,174 +18,32 @@ /* ScriptData SDName: Borean_Tundra SD%Complete: 100 -SDComment: Quest support: 11708, 11692, 11961, 11865. Taxi vendors. 11570 +SDComment: Quest support: 11570, 11590, 11673, 11728, 11865, 11889, 11897, 11919, 11940. SDCategory: Borean Tundra EndScriptData */ /* ContentData -npc_fizzcrank_fullthrottle -npc_iruk -npc_kara_thricestar npc_nesingwary_trapper -go_caribou_trap -npc_surristrasz -npc_tiare +npc_sinkhole_kill_credit npc_lurgglbr +npc_nexus_drake +go_scourge_cage +npc_beryl_sorcerer +npc_seaforium_depth_charge +npc_tad_pole +Go_tadpole_cage +npc_captured_beryl_sorcerer +npc_nexus_drake_hatchling +npc_scourged_flamespitter +npc_bonker_togglevolt EndContentData */ #include "precompiled.h" #include "escort_ai.h" - -/*###### -## npc_fizzcrank_fullthrottle -######*/ - -#define GOSSIP_ITEM_GO_ON "Go on." -#define GOSSIP_ITEM_TELL_ME "Tell me what's going on out here, Fizzcrank." - -enum -{ - GOSSIP_TEXTID_FIZZCRANK1 = 12456, - GOSSIP_TEXTID_FIZZCRANK2 = 12457, - GOSSIP_TEXTID_FIZZCRANK3 = 12458, - GOSSIP_TEXTID_FIZZCRANK4 = 12459, - GOSSIP_TEXTID_FIZZCRANK5 = 12460, - GOSSIP_TEXTID_FIZZCRANK6 = 12461, - GOSSIP_TEXTID_FIZZCRANK7 = 12462, - GOSSIP_TEXTID_FIZZCRANK8 = 12463, - GOSSIP_TEXTID_FIZZCRANK9 = 12464, - - QUEST_THE_MECHAGNOMES = 11708 -}; - -bool GossipHello_npc_fizzcrank_fullthrottle(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(QUEST_THE_MECHAGNOMES) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELL_ME, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_fizzcrank_fullthrottle(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_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK1, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK4, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK5, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK6, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK7, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GO_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK8, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FIZZCRANK9, pCreature->GetGUID()); - pPlayer->AreaExploredOrEventHappens(QUEST_THE_MECHAGNOMES); - break; - } - return true; -} - -/*###### -## npc_iruk -######*/ - -#define GOSSIP_ITEM_IRUK "" - -enum -{ - QUEST_SPIRITS_WATCH_OVER_US = 11961, - SPELL_CREATE_TOTEM = 46816 -}; - -bool GossipHello_npc_iruk(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(QUEST_SPIRITS_WATCH_OVER_US) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_IRUK, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_iruk(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer,SPELL_CREATE_TOTEM,true); - } - - return true; -} - -/*###### -## npc_kara_thricestar -######*/ - -#define GOSSIP_ITEM_THRICESTAR1 "Do you think I could take a ride on one of those flying machines?" -#define GOSSIP_ITEM_THRICESTAR2 "Kara, I need to be flown out the Dens of Dying to find Bixie." - -enum -{ - QUEST_CHECK_IN_WITH_BIXIE = 11692, - SPELL_FIZZCRANK_AIRSTRIP = 51446 -}; - -bool GossipHello_npc_kara_thricestar(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isTaxi()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TAXI, GOSSIP_ITEM_THRICESTAR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if (pPlayer->GetQuestStatus(QUEST_CHECK_IN_WITH_BIXIE) == QUEST_STATUS_COMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THRICESTAR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_kara_thricestar(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->GetSession()->SendTaxiMenu(pCreature); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_FIZZCRANK_AIRSTRIP, false); - break; - } - - return true; -} +#include "ObjectMgr.h" +#include "follower_ai.h" +#include "TemporarySummon.h" +#include "follower_ai.h" /*###### ## npc_nesingwary_trapper @@ -207,78 +66,107 @@ struct MANGOS_DLL_DECL npc_nesingwary_trapperAI : public ScriptedAI uint8 m_uiPhase; uint32 m_uiPhaseTimer; - uint64 m_uiPlayerGUID; - uint64 m_uiGobjectTrapGUID; + ObjectGuid m_playerGuid; + ObjectGuid m_trapGuid; - void Reset() + void Reset() override { m_uiPhase = 0; m_uiPhaseTimer = 0; - m_uiPlayerGUID = 0; - m_uiGobjectTrapGUID = 0; + m_playerGuid.Clear(); + m_trapGuid.Clear(); } - void StartAction(uint64 uiPlayerGUID, uint64 uiGoTrapGUID) + void MoveInLineOfSight(Unit* pWho) override { - m_uiPhase = 1; - m_uiPhaseTimer = 3000; - m_uiPlayerGUID = uiPlayerGUID; - m_uiGobjectTrapGUID = uiGoTrapGUID; + 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_uiGobjectTrapGUID)) + 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: - if (GameObject* pTrap = m_creature->GetMap()->GetGameObject(m_uiGobjectTrapGUID)) + switch (urand(0, 3)) { - if (pTrap->isSpawned()) - { - pTrap->Use(m_creature); + 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)) + { + pTrap->Use(m_creature); - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) - { - 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) @@ -286,104 +174,221 @@ CreatureAI* GetAI_npc_nesingwary_trapper(Creature* pCreature) return new npc_nesingwary_trapperAI(pCreature); } -/*###### -## go_caribou_trap -######*/ +/*##### +# npc_oil_stained_wolf +#####*/ + +enum +{ + SPELL_THROW_WOLF_BAIT = 53326, + SPELL_PLACE_WOLF_BAIT = 46072, // doesn't appear to be used for anything + SPELL_HAS_EATEN = 46073, + SPELL_SUMMON_DROPPINGS = 46075, -bool GOHello_go_caribou_trap(Player* pPlayer, GameObject* pGo) + FACTION_MONSTER = 634, + + POINT_DEST = 1 +}; + +struct MANGOS_DLL_DECL npc_oil_stained_wolfAI : public ScriptedAI { - float fX, fY, fZ; - pGo->GetClosePoint(fX, fY, fZ, pGo->GetObjectBoundingRadius(), 2*INTERACTION_DISTANCE, frand(0, M_PI_F*2)); + npc_oil_stained_wolfAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bCanCrapInPublic; + uint32 m_uiPooTimer; - if (Creature* pCreature = pGo->SummonCreature(NPC_NESINGWARY_TRAPPER, fX, fY, fZ, pGo->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 10000)) + void Reset() override { - if (npc_nesingwary_trapperAI* pTrapperAI = dynamic_cast(pCreature->AI())) - pTrapperAI->StartAction(pPlayer->GetGUID(), pGo->GetGUID()); + m_bCanCrapInPublic = false; + m_uiPooTimer = 0; + } - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; - if (GameObject* pGoFur = GetClosestGameObjectWithEntry(pGo, GO_QUALITY_FUR, INTERACTION_DISTANCE)) + if (uiPointId == POINT_DEST) { - if (!pGoFur->isSpawned()) - { - pGoFur->SetRespawnTime(10); - pGoFur->Refresh(); - } + DoCastSpellIfCan(m_creature, SPELL_HAS_EATEN); + m_uiPooTimer = 4000; } } - return true; -} - -/*###### -## npc_surristrasz -######*/ + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + if (m_uiPooTimer) + { + if (m_uiPooTimer <= uiDiff) + { + if (m_bCanCrapInPublic) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DROPPINGS); + m_creature->GetMotionMaster()->Clear(); + Reset(); + } + else + { + m_creature->HandleEmote(EMOTE_ONESHOT_BATTLEROAR); + m_bCanCrapInPublic = true; + m_uiPooTimer = 3000; + } + } + else + m_uiPooTimer -= uiDiff; + } -#define GOSSIP_ITEM_FREE_FLIGHT "I'd like passage to the Transitus Shield." -#define GOSSIP_ITEM_FLIGHT "May I use a drake to fly elsewhere?" + return; + } -enum -{ - SPELL_ABMER_TO_COLDARRA = 46064 + DoMeleeAttackIfReady(); + } }; -bool GossipHello_npc_surristrasz(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_oil_stained_wolf(Creature* pCreature) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + return new npc_oil_stained_wolfAI(pCreature); +} - if (pCreature->isTaxi()) +bool EffectDummyCreature_npc_oil_stained_wolf(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_THROW_WOLF_BAIT) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FREE_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_GOSSIP); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TAXI, GOSSIP_ITEM_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_TAXIVENDOR); + if (uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->getFaction() != FACTION_MONSTER && !pCreatureTarget->HasAura(SPELL_HAS_EATEN)) + { + pCreatureTarget->SetFactionTemporary(FACTION_MONSTER); + pCreatureTarget->SetWalk(false); + + pCreatureTarget->GetMotionMaster()->MoveIdle(); + + float fX, fY, fZ; + pCaster->GetContactPoint(pCreatureTarget, fX, fY, fZ, CONTACT_DISTANCE); + pCreatureTarget->GetMotionMaster()->MovePoint(POINT_DEST, fX, fY, fZ); + return true; + } } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; + return false; } -bool GossipSelect_npc_surristrasz(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool EffectAuraDummy_npc_oil_stained_wolf(const Aura* pAura, bool bApply) { - if (uiAction == GOSSIP_OPTION_GOSSIP) + if (pAura->GetId() == SPELL_HAS_EATEN) { - pPlayer->CLOSE_GOSSIP_MENU(); + if (pAura->GetEffIndex() != EFFECT_INDEX_0) + return false; - //TaxiPath 795 (amber to coldarra) - pPlayer->CastSpell(pPlayer, SPELL_ABMER_TO_COLDARRA, true); - } + if (bApply) + { + pAura->GetTarget()->HandleEmote(EMOTE_ONESHOT_CUSTOMSPELL01); + } + else + { + Creature* pCreature = (Creature*)pAura->GetTarget(); + pCreature->setFaction(pCreature->GetCreatureInfo()->FactionAlliance); + } - if (uiAction == GOSSIP_OPTION_TAXIVENDOR) - pPlayer->GetSession()->SendTaxiMenu(pCreature); + return true; + } - return true; + return false; } -/*###### -## npc_tiare -######*/ - -#define GOSSIP_ITEM_TELEPORT "Teleport me to Amber Ledge, please." +/*##### +# npc_sinkhole_kill_credit +#####*/ enum { - SPELL_TELEPORT_COLDARRA = 50135 + SPELL_SUMMON_EXPLOSIVES_CART_FIRE = 46799, + SPELL_SUMMON_SCOURGE_BURROWER = 46800, + SPELL_COSMETIC_HUGE_EXPLOSION = 46225, + SPELL_CANNON_FIRE = 42445, }; -bool GossipHello_npc_tiare(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_OPTION_GOSSIP); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + npc_sinkhole_kill_creditAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } -bool GossipSelect_npc_tiare(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_OPTION_GOSSIP) + ObjectGuid m_cartGuid; + ObjectGuid m_wormGuid; + uint32 m_uiCartTimer; + uint32 m_uiCartPhase; + + void Reset() override { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_COLDARRA, true); + m_cartGuid.Clear(); + m_wormGuid.Clear(); + m_uiCartTimer = 2000; + m_uiCartPhase = 0; } - return true; + + void JustSummoned(Creature* pSummoned) override + { + m_wormGuid = pSummoned->GetObjectGuid(); + } + + 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) + return; + + // Expecting summoned from mangos dummy effect 46797 + m_cartGuid = pGo->GetObjectGuid(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_cartGuid) + { + if (m_uiCartTimer <= uiDiff) + { + switch (m_uiCartPhase) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_SUMMON_EXPLOSIVES_CART_FIRE); + m_uiCartTimer = 4000; + break; + case 1: + // Unclear if these should be in a dummy effect or not. + // The order of spells are correct though. + DoCastSpellIfCan(m_creature, SPELL_COSMETIC_HUGE_EXPLOSION, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CANNON_FIRE, CAST_TRIGGERED); + break; + case 2: + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SCOURGE_BURROWER); + m_uiCartTimer = 2000; + break; + case 3: + if (Creature* pWorm = m_creature->GetMap()->GetCreature(m_wormGuid)) + { + pWorm->SetDeathState(JUST_DIED); + pWorm->SetHealth(0); + } + m_uiCartTimer = 10000; + break; + case 4: + if (Creature* pWorm = m_creature->GetMap()->GetCreature(m_wormGuid)) + pWorm->RemoveCorpse(); + + Reset(); + return; + } + + ++m_uiCartPhase; + } + else + m_uiCartTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_sinkhole_kill_credit(Creature* pCreature) +{ + return new npc_sinkhole_kill_creditAI(pCreature); } /*###### @@ -413,7 +418,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)) { @@ -422,7 +427,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)) { @@ -431,9 +436,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()) @@ -445,9 +450,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()) @@ -466,7 +471,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()) { @@ -484,7 +489,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); @@ -515,8 +520,8 @@ 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); - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + pEscortAI->Start(false, pPlayer, pQuest); } } return true; @@ -527,53 +532,815 @@ CreatureAI* GetAI_npc_lurgglbr(Creature* pCreature) return new npc_lurgglbrAI(pCreature); } +/*##### +## go_scourge_cage +#####*/ + +enum +{ + QUEST_MERCIFUL_FREEDOM = 11676, + NPC_SCOURGE_PRISONER = 25610, +}; + +bool GOHello_go_scourge_cage(Player* pPlayer, GameObject* pGo) +{ + if (pPlayer->GetQuestStatus(QUEST_MERCIFUL_FREEDOM) == QUEST_STATUS_INCOMPLETE) + { + Creature *pCreature = GetClosestCreatureWithEntry(pGo, NPC_SCOURGE_PRISONER, INTERACTION_DISTANCE); + if(pCreature) + { + pPlayer->KilledMonsterCredit(NPC_SCOURGE_PRISONER, pCreature->GetObjectGuid()); + pCreature->CastSpell(pCreature, 43014, false); + } + } + return false; +}; + +/*###### +## npc_beryl_sorcerer +######*/ + +enum eBerylSorcerer +{ + NPC_LIBRARIAN_DONATHAN = 25262, + + SPELL_FROST_BOLT = 9672, + SPELL_BLINK = 50648, + + SPELL_COSMETIC_CHAINS = 54324, + SPELL_COSMETIC_ENSLAVE_CHAINS_SELF = 45631 +}; + +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, +}; + +struct MANGOS_DLL_DECL npc_beryl_sorcererAI : public FollowerAI +{ + npc_beryl_sorcererAI(Creature* pCreature) : FollowerAI(pCreature) { + m_uiNormalFaction = pCreature->getFaction(); + Reset(); + } + + bool bEnslaved; + ObjectGuid uiChainerGUID; + uint32 m_uiNormalFaction; + + uint32 SPELL_FROST_BOLT_Timer; + uint32 SPELL_BLINK_Timer; + + void Reset() override + { + m_creature->setFaction(m_uiNormalFaction); + bEnslaved = false; + SPELL_FROST_BOLT_Timer = 5400; + SPELL_BLINK_Timer = 15000; + } + void EnterCombat(Unit* pWho) override + { + AttackStart(pWho); + } + + void SpellHit(Unit* pCaster, SpellEntry const* pSpell) override + { + if (pSpell->Id == SPELL_ARCANE_CHAINS && pCaster->GetTypeId() == TYPEID_PLAYER && !bEnslaved) + { + EnterEvadeMode(); //We make sure that the npc is not attacking the player! + m_creature->setFaction(35); + uiChainerGUID = pCaster->GetObjectGuid(); + if(Player *pChainer = m_creature->GetMap()->GetPlayer(uiChainerGUID)) + { + StartFollow(pChainer, 35, NULL); + m_creature->UpdateEntry(NPC_CAPTURED_BERYL_SORCERER); + DoCast(m_creature, SPELL_COSMETIC_ENSLAVE_CHAINS_SELF, true); + bEnslaved = true; + } + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + FollowerAI::MoveInLineOfSight(pWho); + + if (pWho->GetEntry() == NPC_LIBRARIAN_DONATHAN && m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) + { + if(Player *pChainer = m_creature->GetMap()->GetPlayer(uiChainerGUID)) + { + pChainer->KilledMonsterCredit(NPC_CAPTURED_BERYL_SORCERER,m_creature->GetObjectGuid()); + SetFollowComplete(); + m_creature->ForcedDespawn(1000); + } + } + } + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + /// Frost_bolt needs to be casted more after blink + if (SPELL_FROST_BOLT_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_BOLT); + SPELL_FROST_BOLT_Timer = 5400 + rand()%1400; + }else SPELL_FROST_BOLT_Timer -= uiDiff; + + if (SPELL_BLINK_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_BLINK); + SPELL_BLINK_Timer = 15000 + rand()%3000; + }else SPELL_BLINK_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + +}; + +CreatureAI* GetAI_npc_beryl_sorcerer(Creature* pCreature) +{ + return new npc_beryl_sorcererAI(pCreature); +} + +/*##### +# 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; +} + +/*###### +##Bury Those Cockroaches! +######*/ +enum +{ + QUEST_BURY_THOSE_COCKROACHES = 11608, + SPELL_SEAFORIUM_DEPTH_CHARGE_EXPLOSION = 45502 + + +}; +struct npc_seaforium_depth_chargeAI : public ScriptedAI +{ + npc_seaforium_depth_chargeAI(Creature *pCreature) : ScriptedAI(pCreature) {} + + uint32 uiExplosionTimer; + void Reset() override + { + uiExplosionTimer = urand(5000,10000); + } + void UpdateAI(const uint32 uiDiff) override + { + if (uiExplosionTimer < uiDiff) + { + DoCast(m_creature, SPELL_SEAFORIUM_DEPTH_CHARGE_EXPLOSION); + for(uint8 i = 0; i < 4; ++i) + { + if(Creature* cCredit = GetClosestCreatureWithEntry(m_creature, 25402 + i, 10.0f))//25402-25405 credit markers + { + if(Player *pPlayer = m_creature->GetMap()->GetPlayer(m_creature->GetCreatorGuid())) + { + if(pPlayer->GetQuestStatus(QUEST_BURY_THOSE_COCKROACHES) == QUEST_STATUS_INCOMPLETE) + pPlayer->KilledMonsterCredit(cCredit->GetEntry(),cCredit->GetObjectGuid()); + } + } + } + m_creature->ForcedDespawn(1000); + } else uiExplosionTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_seaforium_depth_charge(Creature* pCreature) +{ + return new npc_seaforium_depth_chargeAI(pCreature); +} + +/*##### +## go_tadpole_cage +#####*/ + +enum +{ + NPC_TADPOLE = 25201, + QUEST_TADPOLES = 11560 +}; + +const int32 textNotOnQuest[3] = +{ + -1999825, + -1999826, + -1999827 +}; + +const int32 textOnQuest[4] = +{ + -1999828, + -1999829, + -1999830, + -1999831 +}; + +bool ProcessEventId_go_tadpole_cage(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +{ + if (Player* pPlayer = (Player*) pSource) + { + if (GameObject* pGo = (GameObject*) pTarget) + { + if (Creature* pTadpole = GetClosestCreatureWithEntry(pGo,NPC_TADPOLE,0.5)) + { + if (pPlayer->GetQuestStatus(QUEST_TADPOLES) == QUEST_STATUS_INCOMPLETE) + { + DoScriptText(textOnQuest[urand(0,3)],pTadpole,pPlayer); + ((FollowerAI*)pTadpole->AI())->StartFollow(pPlayer); + pPlayer->KilledMonsterCredit(NPC_TADPOLE); + } + else + DoScriptText(textNotOnQuest[urand(0,2)],pTadpole,pPlayer); + } + } + } + return true; +} + +/*##### +## npc_tadpole +#####*/ + +struct MANGOS_DLL_DECL npc_tadpoleAI : public FollowerAI +{ + npc_tadpoleAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } + + uint32 m_uiDespawnTimer; + + void Reset() override { m_uiDespawnTimer = 60000; } + + void UpdateFollowerAI(const uint32 uiDiff) + { + // despawn after following 1 minute + if (HasFollowState(STATE_FOLLOW_INPROGRESS)) + if (m_uiDespawnTimer < uiDiff) + { + SetFollowComplete(false); + m_creature->ForcedDespawn(); + } + + FollowerAI::UpdateFollowerAI(uiDiff); + } +}; + +CreatureAI* GetAI_npc_tadpole(Creature* pCreature) +{ + return new npc_tadpoleAI(pCreature); +} + +/*###### +## 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 *newscript; - - newscript = new Script; - newscript->Name = "npc_fizzcrank_fullthrottle"; - newscript->pGossipHello = &GossipHello_npc_fizzcrank_fullthrottle; - newscript->pGossipSelect = &GossipSelect_npc_fizzcrank_fullthrottle; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_iruk"; - newscript->pGossipHello = &GossipHello_npc_iruk; - newscript->pGossipSelect = &GossipSelect_npc_iruk; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_kara_thricestar"; - newscript->pGossipHello = &GossipHello_npc_kara_thricestar; - newscript->pGossipSelect = &GossipSelect_npc_kara_thricestar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_nesingwary_trapper"; - newscript->GetAI = &GetAI_npc_nesingwary_trapper; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_caribou_trap"; - newscript->pGOHello = &GOHello_go_caribou_trap; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_surristrasz"; - newscript->pGossipHello = &GossipHello_npc_surristrasz; - newscript->pGossipSelect = &GossipSelect_npc_surristrasz; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tiare"; - newscript->pGossipHello = &GossipHello_npc_tiare; - newscript->pGossipSelect = &GossipSelect_npc_tiare; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_lurgglbr"; - newscript->GetAI = &GetAI_npc_lurgglbr; - newscript->pQuestAccept = &QuestAccept_npc_lurgglbr; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_nesingwary_trapper"; + pNewScript->GetAI = &GetAI_npc_nesingwary_trapper; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_oil_stained_wolf"; + pNewScript->GetAI = &GetAI_npc_oil_stained_wolf; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_oil_stained_wolf; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_oil_stained_wolf; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_sinkhole_kill_credit"; + pNewScript->GetAI = &GetAI_npc_sinkhole_kill_credit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_lurgglbr"; + pNewScript->GetAI = &GetAI_npc_lurgglbr; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_lurgglbr; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_scourge_cage"; + pNewScript->pGOUse = &GOHello_go_scourge_cage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_beryl_sorcerer"; + pNewScript->GetAI = &GetAI_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_seaforium_depth_charge"; + pNewScript->GetAI = &GetAI_npc_seaforium_depth_charge; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_tadpole_cage"; + pNewScript->pProcessEventId = &ProcessEventId_go_tadpole_cage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tadpole"; + pNewScript->GetAI = &GetAI_npc_tadpole; + 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 0000000000..4fc43d75a9 --- /dev/null +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp @@ -0,0 +1,502 @@ +/* Copyright (C) 2006 - 2013 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_argent_challenge +SD%Complete: 50% +SDComment: missing yells. radiance is "wrong". modified by /dev/rsa +SDCategory: Trial Of the Champion +EndScriptData */ + +#include "precompiled.h" +#include "trial_of_the_champion.h" + +enum +{ + SPELL_BERSERK = 47008, + // Yells + + // Eadric + SPELL_VENGEANCE = 66889, + SPELL_RADIANCE = 66862, + SPELL_RADIANCE_H = 67681, + SPELL_HAMMER_OF_JUSTICE = 66940, + SPELL_HAMMER = 67680, + // Paletress + SPELL_SMITE = 66536, + SPELL_SMITE_H = 67674, + SPELL_HOLY_FIRE = 66538, + SPELL_HOLY_FIRE_H = 67676, + SPELL_RENEW = 66537, + SPELL_RENEW_H = 67675, + SPELL_HOLY_NOVA = 66546, + SPELL_SHIELD = 66515, + SPELL_CONFESS = 66547, + // Memory + SPELL_FEAR = 66552, + SPELL_FEAR_H = 67677, + SPELL_SHADOWS = 66619, + SPELL_SHADOWS_H = 67678, + SPELL_OLD_WOUNDS = 66620, + SPELL_OLD_WOUNDS_H = 67679, +}; + +// Eadric The Pure +struct MANGOS_DLL_DECL boss_eadricAI : public ScriptedAI +{ + boss_eadricAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Vengeance_Timer; + uint32 Radiance_Timer; + uint32 Hammer_Timer; + uint32 Hammer_Dmg_Timer; + uint32 m_uiBerserk_Timer; + ObjectGuid HammerTarget; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + Vengeance_Timer = 1000; + Radiance_Timer = m_bIsRegularMode ? 15000 : 8000; + Hammer_Timer = m_bIsRegularMode ? 40000 : 10000; + Hammer_Dmg_Timer = m_bIsRegularMode ? 45000 : 20000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + HammerTarget.Clear(); + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_ARGENT_CHALLENGE) != DONE) + m_pInstance->SetData(TYPE_ARGENT_CHALLENGE, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_ARGENT_CHALLENGE, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Vengeance_Timer < diff) + { + DoCast(m_creature, SPELL_VENGEANCE); + Vengeance_Timer = m_bIsRegularMode ? 12000 : 8000; + } + else + Vengeance_Timer -= diff; + + if (Radiance_Timer < diff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_RADIANCE : SPELL_RADIANCE_H); + Radiance_Timer = m_bIsRegularMode ? 20000 : 12000; + } + else + Radiance_Timer -= diff; + + if (Hammer_Timer < diff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + { + DoCast(target, SPELL_HAMMER_OF_JUSTICE); + HammerTarget = target->GetObjectGuid(); + } + Hammer_Timer = m_bIsRegularMode ? 40000 : 15000; + } + else + Hammer_Timer -= diff; + + if (Hammer_Dmg_Timer < diff) + { + if (Unit* pHammerTarget = m_creature->GetMap()->GetUnit(HammerTarget)) + DoCast(pHammerTarget, SPELL_HAMMER); + + Hammer_Dmg_Timer = m_bIsRegularMode ? 50000 : 15000; + } + else + Hammer_Dmg_Timer -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_eadric(Creature* pCreature) +{ + return new boss_eadricAI(pCreature); +} + +// Argent Confessor Paletress +struct MANGOS_DLL_DECL boss_paletressAI : public ScriptedAI +{ + boss_paletressAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Smite_Timer; + uint32 Holy_Fire_Timer; + uint32 Renew_Timer; + uint32 Shield_Delay; + uint32 Shield_Check; + uint32 m_uiBerserk_Timer; + uint32 summonEntry; + bool summoned; + bool shielded; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->RemoveAurasDueToSpell(SPELL_SHIELD); + Smite_Timer = 5000; + Holy_Fire_Timer = m_bIsRegularMode ? 10000 : 8000; + Renew_Timer = m_bIsRegularMode ? 7000 : 5000; + Shield_Delay = 0; + Shield_Check = 1000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + summoned = false; + summonEntry = 0; + shielded = false; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void JustSummoned(Creature* _summoned) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + _summoned->AddThreat(target); + + summonEntry = _summoned->GetEntry(); + summoned = true; + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_ARGENT_CHALLENGE) != DONE) + m_pInstance->SetData(TYPE_ARGENT_CHALLENGE, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_ARGENT_CHALLENGE, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Smite_Timer < diff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsRegularMode ? SPELL_SMITE : SPELL_SMITE_H); + + Smite_Timer = 2000; + } + else + Smite_Timer -= diff; + + if (Holy_Fire_Timer < diff) + { + m_creature->CastStop(m_bIsRegularMode ? SPELL_SMITE : SPELL_SMITE_H); + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsRegularMode ? SPELL_HOLY_FIRE : SPELL_HOLY_FIRE_H); + + Holy_Fire_Timer = m_bIsRegularMode ? 10000 : 7000; + } + else + Holy_Fire_Timer -= diff; + + if (Renew_Timer < diff) + { + m_creature->CastStop(m_bIsRegularMode ? SPELL_SMITE : SPELL_SMITE_H); + m_creature->CastStop(m_bIsRegularMode ? SPELL_HOLY_FIRE : SPELL_HOLY_FIRE_H); + switch(urand(0, 1)) + { + case 0: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(summonEntry)) + { + if (pTemp->isAlive()) + DoCast(pTemp, m_bIsRegularMode ? SPELL_RENEW : SPELL_RENEW_H); + else + DoCast(m_creature, m_bIsRegularMode ? SPELL_RENEW : SPELL_RENEW_H); + } + break; + case 1: + DoCast(m_creature, m_bIsRegularMode ? SPELL_RENEW : SPELL_RENEW_H); + break; + } + Renew_Timer = 25000; + } + else + Renew_Timer -= diff; + + if (((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 35 ) && !summoned) + { + m_creature->CastStop(m_bIsRegularMode ? SPELL_SMITE : SPELL_SMITE_H); + m_creature->CastStop(m_bIsRegularMode ? SPELL_HOLY_FIRE : SPELL_HOLY_FIRE_H); + DoCast(m_creature, SPELL_HOLY_NOVA); + switch(urand(0, 24)) + { + case 0: + m_creature->SummonCreature(MEMORY_ALGALON, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 1: + m_creature->SummonCreature(MEMORY_CHROMAGGUS, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 2: + m_creature->SummonCreature(MEMORY_CYANIGOSA, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 3: + m_creature->SummonCreature(MEMORY_DELRISSA, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 4: + m_creature->SummonCreature(MEMORY_ECK, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 5: + m_creature->SummonCreature(MEMORY_ENTROPIUS, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 6: + m_creature->SummonCreature(MEMORY_GRUUL, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 7: + m_creature->SummonCreature(MEMORY_HAKKAR, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 8: + m_creature->SummonCreature(MEMORY_HEIGAN, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 9: + m_creature->SummonCreature(MEMORY_HEROD, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 10: + m_creature->SummonCreature(MEMORY_HOGGER, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 11: + m_creature->SummonCreature(MEMORY_IGNIS, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 12: + m_creature->SummonCreature(MEMORY_ILLIDAN, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 13: + m_creature->SummonCreature(MEMORY_INGVAR, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 14: + m_creature->SummonCreature(MEMORY_KALITHRESH, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 15: + m_creature->SummonCreature(MEMORY_LUCIFRON, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 16: + m_creature->SummonCreature(MEMORY_MALCHEZAAR, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 17: + m_creature->SummonCreature(MEMORY_MUTANUS, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 18: + m_creature->SummonCreature(MEMORY_ONYXIA, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 19: + m_creature->SummonCreature(MEMORY_THUNDERAAN, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 20: + m_creature->SummonCreature(MEMORY_VANCLEEF, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 21: + m_creature->SummonCreature(MEMORY_VASHJ, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 22: + m_creature->SummonCreature(MEMORY_VEKNILASH, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 23: + m_creature->SummonCreature(MEMORY_VEZAX, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 24: + m_creature->SummonCreature(MEMORY_ARCHIMONDE, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + } + Shield_Delay = 1000; + } + if (Shield_Delay < diff && !shielded && summoned) + { + m_creature->CastStop(m_bIsRegularMode ? SPELL_SMITE : SPELL_SMITE_H); + m_creature->CastStop(m_bIsRegularMode ? SPELL_HOLY_FIRE : SPELL_HOLY_FIRE_H); + DoCast(m_creature, SPELL_SHIELD); + shielded = true; + Shield_Check = m_bIsRegularMode ? 3000 : 5000; + } + else + Shield_Delay -= diff; + + if (Shield_Check < diff && shielded) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(summonEntry)) + { + if (!pTemp->isAlive()) + { + m_creature->RemoveAurasDueToSpell(SPELL_SHIELD); + shielded = false; + } + else + Shield_Check = 1000; + } + } + else + Shield_Check -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_paletress(Creature* pCreature) +{ + return new boss_paletressAI(pCreature); +} + +// Summoned Memory +struct MANGOS_DLL_DECL mob_toc5_memoryAI : public ScriptedAI +{ + mob_toc5_memoryAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Old_Wounds_Timer; + uint32 Shadows_Timer; + uint32 Fear_Timer; + + void Reset() + { + Old_Wounds_Timer = 5000; + Shadows_Timer = 8000; + Fear_Timer = 13000; + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Old_Wounds_Timer < diff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsRegularMode ? SPELL_OLD_WOUNDS : SPELL_OLD_WOUNDS_H); + + Old_Wounds_Timer = 10000; + } + else + Old_Wounds_Timer -= diff; + + if (Fear_Timer < diff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_FEAR : SPELL_FEAR_H); + Fear_Timer = 40000; + } + else + Fear_Timer -= diff; + + if (Shadows_Timer < diff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) + DoCast(target, m_bIsRegularMode ? SPELL_SHADOWS : SPELL_SHADOWS_H); + + Shadows_Timer = 10000; + } + else + Shadows_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_memory(Creature* pCreature) +{ + return new mob_toc5_memoryAI(pCreature); +} + +void AddSC_boss_argent_challenge() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "boss_eadric"; + NewScript->GetAI = &GetAI_boss_eadric; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "boss_paletress"; + NewScript->GetAI = &GetAI_boss_paletress; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_memory"; + NewScript->GetAI = &GetAI_mob_toc5_memory; + NewScript->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 0000000000..6970dab295 --- /dev/null +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp @@ -0,0 +1,335 @@ +/* Copyright (C) 2006 - 2013 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_black_knight +SD%Complete: 70% +SDComment: missing yells. not sure about timers. modified by /dev/rsa +SDCategory: Trial Of the Champion +EndScriptData */ + +#include "precompiled.h" +#include "trial_of_the_champion.h" + +enum +{ + SPELL_BERSERK = 47008, + // Yells + + // Undead + SPELL_PLAGUE_STRIKE = 67724, + SPELL_PLAGUE_STRIKE_H = 67884, + SPELL_ICY_TOUCH = 67718, + SPELL_ICY_TOUCH_H = 67881, + SPELL_OBLITERATE = 67725, + SPELL_OBLITERATE_H = 67883, + SPELL_CHOKE = 68306, + // Skeleton + SPELL_ARMY = 42650, //replacing original one, since that one spawns millions of ghouls!! + // Ghost + SPELL_DEATH = 67808, + SPELL_DEATH_H = 67875, + SPELL_MARK = 67823, + + // Risen ghoul + SPELL_CLAW = 67879, + SPELL_EXPLODE = 67729, + SPELL_EXPLODE_H = 67886, + SPELL_LEAP = 67749, + SPELL_LEAP_H = 67880, + + // Sword ID + EQUIP_SWORD = 40343 +}; + +// Risen Ghoul +struct MANGOS_DLL_DECL mob_toc5_risen_ghoulAI : public ScriptedAI +{ + mob_toc5_risen_ghoulAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Attack; + + void Reset() + { + Attack = 2500; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Attack < diff) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_BLACK_KNIGHT)) + { + if (pTemp->isAlive()) + if ((pTemp->GetHealth()*100 / pTemp->GetMaxHealth()) < 25) + DoCast(m_creature, m_bIsRegularMode ? SPELL_EXPLODE : SPELL_EXPLODE_H); + } + + if (m_creature->IsWithinDistInMap(m_creature->getVictim(), 4)) + { + DoCast(m_creature->getVictim(), SPELL_CLAW); + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) + m_creature->AI()->AttackStart(target); + + Attack = 2500; + } + else if (m_creature->IsWithinDistInMap(m_creature->getVictim(), 30)) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_LEAP : SPELL_LEAP_H); + Attack = 2500; + } + } + else + Attack -= diff; + + if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) + DoCast(m_creature, m_bIsRegularMode ? SPELL_EXPLODE : SPELL_EXPLODE_H); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_risen_ghoul(Creature* pCreature) +{ + return new mob_toc5_risen_ghoulAI(pCreature); +} + +// The Black Knight +struct MANGOS_DLL_DECL boss_black_knightAI : public ScriptedAI +{ + boss_black_knightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Plague_Strike_Timer; + uint32 Icy_Touch_Timer; + uint32 Obliterate_Timer; + uint32 Choke_Timer; + uint32 Death_Timer; + uint32 Mark_Timer; + uint32 Phase_Delay; + uint32 Summon_Ghoul; + uint32 m_uiBerserk_Timer; + bool phase1; + bool phase2; + bool phase3; + bool ghoul; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->SetDisplayId(29837); + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + Plague_Strike_Timer = m_bIsRegularMode ? 5000 : 4000; + Icy_Touch_Timer = m_bIsRegularMode ? 10000 : 7000; + Obliterate_Timer = m_bIsRegularMode ? 16000 : 10000; + Choke_Timer = 15000; + Summon_Ghoul = 4000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + phase1 = true; + phase2 = false; + phase3 = false; + ghoul = false; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_BLACK_KNIGHT) != DONE) + m_pInstance->SetData(TYPE_BLACK_KNIGHT, IN_PROGRESS); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if ((uiDamage > m_creature->GetHealth() || m_creature->GetHealth()/m_creature->GetHealth() <= 0.1 ) && !phase3) + { + uiDamage = 0; + + if (phase2) + StartPhase3(); + + if (phase1) + StartPhase2(); + } + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + if (phase3 && !phase1 && !phase2) + { + m_pInstance->SetData(TYPE_BLACK_KNIGHT, DONE); + } +/* if (phase2 && !phase1 && !phase3) + if (!m_creature->isAlive()) + { + m_creature->Respawn(); + StartPhase3(); + } + if (phase1 && !phase2 && !phase3) + if (!m_creature->isAlive()) + { + m_creature->Respawn(); + StartPhase2(); + }*/ + } + + void StartPhase2() + { + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->SetDisplayId(27550); + phase1 = false; + phase2 = true; + phase3 = false; + DoCast(m_creature, SPELL_ARMY); + Plague_Strike_Timer = m_bIsRegularMode ? 14000 : 8000; + Icy_Touch_Timer = m_bIsRegularMode ? 12000 : 7000; + Obliterate_Timer = m_bIsRegularMode ? 18000 : 10000; + } + + void StartPhase3() + { + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->SetDisplayId(14560); + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + phase1 = false; + phase2 = false; + phase3 = true; + Death_Timer = m_bIsRegularMode ? 5000 : 3000; + Mark_Timer = m_bIsRegularMode ? 9000 : 7000; + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Plague_Strike_Timer < diff && !phase3) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_PLAGUE_STRIKE : SPELL_PLAGUE_STRIKE_H); + Plague_Strike_Timer = m_bIsRegularMode ? 10500 : 7000; + } + else + Plague_Strike_Timer -= diff; + + if (Icy_Touch_Timer < diff && !phase3) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ICY_TOUCH : SPELL_ICY_TOUCH_H); + Icy_Touch_Timer = m_bIsRegularMode ? 10000 : 8000; + } + else + Icy_Touch_Timer -= diff; + + if (Obliterate_Timer < diff && !phase3) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_OBLITERATE : SPELL_OBLITERATE_H); + Obliterate_Timer = m_bIsRegularMode ? 11000 : 8000; + } + else + Obliterate_Timer -= diff; + + if (Choke_Timer < diff && phase1) + { + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) + DoCast(m_creature->getVictim(), SPELL_CHOKE); + Choke_Timer = m_bIsRegularMode ? 15000 : 10000; + } + else + Choke_Timer -= diff; + + if (Summon_Ghoul < diff && phase1 && !ghoul) + { + if (m_pInstance->GetData(DATA_TOC5_ANNOUNCER) == m_pInstance->GetData(DATA_JAEREN)) + m_creature->SummonCreature(NPC_RISEN_JAEREN, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + else + m_creature->SummonCreature(NPC_RISEN_ARELAS, 0.0f, 0.0f, 0.0f, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + + ghoul = true; + } + else + Summon_Ghoul -= diff; + + if (Mark_Timer < diff && phase3) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) + DoCast(target, SPELL_MARK); + Mark_Timer = m_bIsRegularMode ? 15000 : 10000; + } + else + Mark_Timer -= diff; + + if (Death_Timer < diff && phase3) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_DEATH : SPELL_DEATH_H); + Death_Timer = 3500; + } + else + Death_Timer -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_black_knight(Creature* pCreature) +{ + return new boss_black_knightAI(pCreature); +} + +void AddSC_boss_black_knight() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "mob_toc5_risen_ghoul"; + NewScript->GetAI = &GetAI_mob_toc5_risen_ghoul; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "boss_black_knight"; + NewScript->GetAI = &GetAI_boss_black_knight; + NewScript->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 bbc5a803b5..813b0352f3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,11 +15,809 @@ */ /* ScriptData -SDName: grand_champions -SD%Complete: 0 -SDComment: -SDCategory: Crusader Coliseum, Trial of the Champion +SDName: boss_grand_champions +SD%Complete: 70% +SDComment: missing yells. hunter AI sucks. no pvp diminuishing returns(is it DB related?). modified by /dev/rsa +SDCategory: Trial Of the Champion EndScriptData */ #include "precompiled.h" #include "trial_of_the_champion.h" + +enum +{ + // Common + SPELL_BERSERK = 47008, + // Yells + // Warrior + SPELL_MORTAL_STRIKE = 68783, + SPELL_MORTAL_STRIKE_H = 68784, + SPELL_BLADESTORM = 63784, + SPELL_INTERCEPT = 67540, + SPELL_ROLLING_THROW = 47115, //need core support for spell 67546, using 47115 instead + // Mage + SPELL_FIREBALL = 66042, + SPELL_FIREBALL_H = 68310, + SPELL_BLAST_WAVE = 66044, + SPELL_BLAST_WAVE_H = 68312, + SPELL_HASTE = 66045, + SPELL_POLYMORPH = 66043, + SPELL_POLYMORPH_H = 68311, + // Shaman + SPELL_CHAIN_LIGHTNING = 67529, + SPELL_CHAIN_LIGHTNING_H = 68319, + SPELL_EARTH_SHIELD = 67530, + SPELL_HEALING_WAVE = 67528, + SPELL_HEALING_WAVE_H = 68318, + SPELL_HEX_OF_MENDING = 67534, + // Hunter + SPELL_DISENGAGE = 68340, + SPELL_LIGHTNING_ARROWS = 66083, + SPELL_MULTI_SHOT = 66081, + SPELL_SHOOT = 66079, + // Rogue + SPELL_EVISCERATE = 67709, + SPELL_EVISCERATE_H = 68317, + SPELL_FAN_OF_KNIVES = 67706, + SPELL_POISON_BOTTLE = 67701 +}; + +// Warrior +struct MANGOS_DLL_DECL mob_toc5_warriorAI : public ScriptedAI +{ + mob_toc5_warriorAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Mortal_Strike_Timer; + uint32 Bladestorm_Timer; + uint32 Rolling_Throw_Timer; + uint32 Intercept_Cooldown; + uint32 intercept_check; + uint32 m_uiBerserk_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + Mortal_Strike_Timer = m_bIsRegularMode ? 9000 : 6000; + Bladestorm_Timer = m_bIsRegularMode ? 30000 : 20000; + Rolling_Throw_Timer = m_bIsRegularMode ? 45000 : 30000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + Intercept_Cooldown = 0; + intercept_check = 1000; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + +// m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(DATA_CHAMPIONS_COUNT, m_pInstance->GetData(DATA_CHAMPIONS_COUNT) - 1); + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (m_pInstance->GetData(DATA_CHAMPIONS_COUNT) < 1) + { + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Mortal_Strike_Timer < diff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MORTAL_STRIKE : SPELL_MORTAL_STRIKE_H); + Mortal_Strike_Timer = m_bIsRegularMode ? 6000 : 4000; + } + else + Mortal_Strike_Timer -= diff; + + if (Rolling_Throw_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_ROLLING_THROW); + Rolling_Throw_Timer = m_bIsRegularMode ? 30000 : 15000; + } + else + Rolling_Throw_Timer -= diff; + + if (Bladestorm_Timer < diff) + { + DoCast(m_creature, SPELL_BLADESTORM); + Bladestorm_Timer = m_bIsRegularMode ? 60000 : 20000; + } + else + Bladestorm_Timer -= diff; + + if (intercept_check < diff) + { + if (!m_creature->IsWithinDistInMap(m_creature->getVictim(), 8) && m_creature->IsWithinDistInMap(m_creature->getVictim(), 25) && Intercept_Cooldown < diff) + { + DoCast(m_creature->getVictim(), SPELL_INTERCEPT); + Intercept_Cooldown = m_bIsRegularMode ? 15000 : 10000; + } + intercept_check = 1000; + } + else + { + intercept_check -= diff; + Intercept_Cooldown -= diff; + } + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_warrior(Creature* pCreature) +{ + return new mob_toc5_warriorAI(pCreature); +} + +// Mage +struct MANGOS_DLL_DECL mob_toc5_mageAI : public ScriptedAI +{ + mob_toc5_mageAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Fireball_Timer; + uint32 Blast_Wave_Timer; + uint32 Haste_Timer; + uint32 Polymorph_Timer; + uint32 m_uiBerserk_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + Fireball_Timer = 0; + Blast_Wave_Timer = m_bIsRegularMode ? 20000 : 12000; + Haste_Timer = m_bIsRegularMode ? 12000 : 9000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + Polymorph_Timer = m_bIsRegularMode ? 12000 : 10000; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + +// m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(DATA_CHAMPIONS_COUNT, m_pInstance->GetData(DATA_CHAMPIONS_COUNT) - 1); + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (m_pInstance->GetData(DATA_CHAMPIONS_COUNT) < 1) + { + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Fireball_Timer < diff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FIREBALL : SPELL_FIREBALL_H); + Fireball_Timer = m_bIsRegularMode ? 5000 : 3000; + } + else + Fireball_Timer -= diff; + + if (Blast_Wave_Timer < diff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_BLAST_WAVE : SPELL_BLAST_WAVE_H); + Blast_Wave_Timer = m_bIsRegularMode ? 20000 : 12000; + } + else + Blast_Wave_Timer -= diff; + + if (Haste_Timer < diff) + { + DoCast(m_creature, SPELL_HASTE); + Haste_Timer = m_bIsRegularMode ? 10000 : 8000; + } + else + Haste_Timer -= diff; + + if (Polymorph_Timer < diff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(target, m_bIsRegularMode ? SPELL_POLYMORPH : SPELL_POLYMORPH_H); + + Polymorph_Timer = m_bIsRegularMode ? 20000 : 15000; + } + else + Polymorph_Timer -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_mage(Creature* pCreature) +{ + return new mob_toc5_mageAI(pCreature); +} + +// Shaman +struct MANGOS_DLL_DECL mob_toc5_shamanAI : public ScriptedAI +{ + mob_toc5_shamanAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Chain_Lightning_Timer; + uint32 Earth_Shield_Timer; + uint32 Healing_Wave_Timer; + uint32 Hex_Timer; + + float mob1_health; + float mob2_health; + float mob3_health; + uint32 m_uiBerserk_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + Chain_Lightning_Timer = m_bIsRegularMode ? 2000 : 1000; + Earth_Shield_Timer = m_bIsRegularMode ? 10000 : 5000; + Healing_Wave_Timer = m_bIsRegularMode ? 20000 : 12000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + Hex_Timer = m_bIsRegularMode ? 15000 : 10000; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + +// m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(DATA_CHAMPIONS_COUNT, m_pInstance->GetData(DATA_CHAMPIONS_COUNT) - 1); + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (m_pInstance->GetData(DATA_CHAMPIONS_COUNT) < 1) + { + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Chain_Lightning_Timer < diff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING_H); + Chain_Lightning_Timer = m_bIsRegularMode ? 12000 : 8000; + } + else + Chain_Lightning_Timer -= diff; + + if (Hex_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_HEX_OF_MENDING); + Hex_Timer = m_bIsRegularMode ? 30000 : 20000; + } + else + Hex_Timer -= diff; + + if (Healing_Wave_Timer < diff) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + { + if (pTemp->isAlive()) + mob1_health = pTemp->GetHealth()*100 / pTemp->GetMaxHealth(); + else + mob1_health = 100; + } + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + { + if (pTemp->isAlive()) + mob2_health = pTemp->GetHealth()*100 / pTemp->GetMaxHealth(); + else + mob2_health = 100; + } + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + { + if (pTemp->isAlive()) + mob3_health = pTemp->GetHealth()*100 / pTemp->GetMaxHealth(); + else + mob3_health = 100; + } + if (mob1_health < mob2_health && mob1_health < mob3_health && mob1_health < 70) + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + DoCast(pTemp, m_bIsRegularMode ? SPELL_HEALING_WAVE : SPELL_HEALING_WAVE_H); + + if (mob1_health > mob2_health && mob2_health < mob3_health && mob2_health < 70) + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + DoCast(pTemp, m_bIsRegularMode ? SPELL_HEALING_WAVE : SPELL_HEALING_WAVE_H); + + if (mob3_health < mob2_health && mob1_health > mob3_health && mob3_health < 70) + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + DoCast(pTemp, m_bIsRegularMode ? SPELL_HEALING_WAVE : SPELL_HEALING_WAVE_H); + + Healing_Wave_Timer = m_bIsRegularMode ? 8000 : 6000; + } + else + Healing_Wave_Timer -= diff; + + if (Earth_Shield_Timer < diff) + { + switch(urand(0, 2)) + { + case 0: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + { + if (pTemp->isAlive()) + DoCast(pTemp, SPELL_EARTH_SHIELD); + else + DoCast(m_creature, SPELL_EARTH_SHIELD); + } + break; + case 1: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + { + if (pTemp->isAlive()) + DoCast(pTemp, SPELL_EARTH_SHIELD); + else + DoCast(m_creature, SPELL_EARTH_SHIELD); + } + break; + case 2: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + { + if (pTemp->isAlive()) + DoCast(pTemp, SPELL_EARTH_SHIELD); + else + DoCast(m_creature, SPELL_EARTH_SHIELD); + } + break; + } + Earth_Shield_Timer = m_bIsRegularMode ? 35000 : 25000; + } + else + Earth_Shield_Timer -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_shaman(Creature* pCreature) +{ + return new mob_toc5_shamanAI(pCreature); +} + +// Hunter +struct MANGOS_DLL_DECL mob_toc5_hunterAI : public ScriptedAI +{ + mob_toc5_hunterAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Shoot_Timer; + uint32 Lightning_Arrows_Timer; + uint32 Multi_Shot_Timer; + uint32 Disengage_Cooldown; + uint32 enemy_check; + uint32 disengage_check; + uint32 m_uiBerserk_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + Shoot_Timer = 0; + Lightning_Arrows_Timer = m_bIsRegularMode ? 18000 : 10000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + Multi_Shot_Timer = m_bIsRegularMode ? 15000 : 8000; + Disengage_Cooldown = 0; + enemy_check = 1000; + disengage_check = 1000; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + +// m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(DATA_CHAMPIONS_COUNT, m_pInstance->GetData(DATA_CHAMPIONS_COUNT) - 1); + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (m_pInstance->GetData(DATA_CHAMPIONS_COUNT) < 1) + { + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (enemy_check < diff) + { + if (!m_creature->IsWithinDistInMap(m_creature->getVictim(), 8) && m_creature->IsWithinDistInMap(m_creature->getVictim(), 30)) + { + m_creature->SetSpeedRate(MOVE_RUN, 0.0001f); + } + else + { + m_creature->SetSpeedRate(MOVE_RUN, 1.2f); + } + enemy_check = 100; + } + else + enemy_check -= diff; + + if (Disengage_Cooldown>0) + Disengage_Cooldown -= diff; + + if (Shoot_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_SHOOT); + Shoot_Timer = m_bIsRegularMode ? 5000 : 3000; + } + else + Shoot_Timer -= diff; + + if (Multi_Shot_Timer < diff) + { + m_creature->CastStop(SPELL_SHOOT); + DoCast(m_creature->getVictim(), SPELL_MULTI_SHOT); + Multi_Shot_Timer = m_bIsRegularMode ? 10000 : 5000; + } + else + Multi_Shot_Timer -= diff; + + if (Lightning_Arrows_Timer < diff) + { + m_creature->CastStop(SPELL_SHOOT); + DoCast(m_creature, SPELL_LIGHTNING_ARROWS); + Lightning_Arrows_Timer = m_bIsRegularMode ? 15000 : 8000; + } + else + Lightning_Arrows_Timer -= diff; + + if (disengage_check < diff) + { + if (m_creature->IsWithinDistInMap(m_creature->getVictim(), 5) && Disengage_Cooldown == 0) + { + DoCast(m_creature, SPELL_DISENGAGE); + Disengage_Cooldown = m_bIsRegularMode ? 15000 : 10000; + } + disengage_check = 1000; + } + else + disengage_check -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_hunter(Creature* pCreature) +{ + return new mob_toc5_hunterAI(pCreature); +} + +// Rogue +struct MANGOS_DLL_DECL mob_toc5_rogueAI : public ScriptedAI +{ + mob_toc5_rogueAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 Eviscerate_Timer; + uint32 FoK_Timer; + uint32 Poison_Timer; + uint32 m_uiBerserk_Timer; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + Eviscerate_Timer = m_bIsRegularMode ? 20000 : 10000; + FoK_Timer = m_bIsRegularMode ? 15000 : 10000; + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + Poison_Timer = m_bIsRegularMode ? 12000 : 5000; + m_creature->GetMotionMaster()->MovePoint(0, 746, 614, m_creature->GetPositionZ()); + m_creature->SetWalk(true); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + if (pTemp->isAlive()) + pTemp->SetInCombatWithZone(); + +// m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(DATA_CHAMPIONS_COUNT, m_pInstance->GetData(DATA_CHAMPIONS_COUNT) - 1); + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (m_pInstance->GetData(DATA_CHAMPIONS_COUNT) < 1) + { + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + pTemp->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (Eviscerate_Timer < diff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_EVISCERATE : SPELL_EVISCERATE_H); + Eviscerate_Timer = m_bIsRegularMode ? 15000 : 10000; + } + else + Eviscerate_Timer -= diff; + + if (FoK_Timer < diff) + { + DoCast(m_creature->getVictim(), SPELL_FAN_OF_KNIVES); + FoK_Timer = m_bIsRegularMode ? 12000 : 7000; + } + else + FoK_Timer -= diff; + + if (Poison_Timer < diff) + { + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(m_creature, SPELL_POISON_BOTTLE); + + Poison_Timer = m_bIsRegularMode ? 10000 : 5000; + } + else + Poison_Timer -= diff; + + if (m_uiBerserk_Timer < diff) + { + DoCast(m_creature, SPELL_BERSERK); + m_uiBerserk_Timer = m_bIsRegularMode ? 300000 : 180000; + } + else + m_uiBerserk_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_toc5_rogue(Creature* pCreature) +{ + return new mob_toc5_rogueAI(pCreature); +} + +void AddSC_boss_grand_champions() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "mob_toc5_warrior"; + NewScript->GetAI = &GetAI_mob_toc5_warrior; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_mage"; + NewScript->GetAI = &GetAI_mob_toc5_mage; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_shaman"; + NewScript->GetAI = &GetAI_mob_toc5_shaman; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_hunter"; + NewScript->GetAI = &GetAI_mob_toc5_hunter; + NewScript->RegisterSelf(); + + NewScript = new Script; + NewScript->Name = "mob_toc5_rogue"; + NewScript->GetAI = &GetAI_mob_toc5_rogue; + NewScript->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 37aeea6f66..5c4f875df9 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,17 +15,320 @@ */ /* ScriptData -SDName: instance_trial_of_the_champion -SD%Complete: 0 -SDComment: -SDCategory: Crusader Coliseum, Trial of the Champion +SDName: Instance_Trial_Of_the_Champion +SD%Complete: 70 +SDComment: modified by /dev/rsa +SDCategory: Trial Of the Champion EndScriptData */ #include "precompiled.h" #include "trial_of_the_champion.h" +#include "World.h" -/* Trial of the Champion encounters: -0 - Grand Champions -1 - Argent Champion -2 - Black Knight -*/ +struct MANGOS_DLL_DECL instance_trial_of_the_champion : public ScriptedInstance +{ + instance_trial_of_the_champion(Map* pMap) : ScriptedInstance(pMap) + { + m_bIsRegularMode = pMap->IsRegularDifficulty(); + Initialize(); + } + + uint32 m_auiEncounter[MAX_ENCOUNTER+1]; + + std::string m_strInstData; + + uint32 m_uiChampionId1; + uint32 m_uiChampionId2; + uint32 m_uiChampionId3; + uint32 m_uiChampionsCount; + uint32 m_uiArgentChallengerID; + uint32 m_uiBlackKnightMinionID; + uint32 m_uiAnnouncerID; + bool m_bIsRegularMode; + + void Initialize() override + { + m_uiBlackKnightMinionID = 0; + m_uiChampionId1 = 0; + m_uiChampionId2 = 0; + m_uiChampionId3 = 0; + m_uiChampionsCount = 3; + m_uiArgentChallengerID = 0; + m_uiAnnouncerID = 0; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + m_auiEncounter[i] = NOT_STARTED; + } + + void OnPlayerEnter(Player* pPlayer) override + { + + enum PhaseControl + { + HORDE_CONTROL_PHASE_SHIFT_1 = 55773, + HORDE_CONTROL_PHASE_SHIFT_2 = 60028, + ALLIANCE_CONTROL_PHASE_SHIFT_1 = 55774, + ALLIANCE_CONTROL_PHASE_SHIFT_2 = 60027, + }; + + if (!sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + return; + + switch (pPlayer->GetTeam()) + { + case ALLIANCE: + if (pPlayer && pPlayer->IsInWorld() && pPlayer->HasAura(HORDE_CONTROL_PHASE_SHIFT_1)) + pPlayer->RemoveAurasDueToSpell(HORDE_CONTROL_PHASE_SHIFT_1); + + pPlayer->CastSpell(pPlayer, HORDE_CONTROL_PHASE_SHIFT_2, false); + break; + case HORDE: + if (pPlayer && pPlayer->IsInWorld() && pPlayer->HasAura(ALLIANCE_CONTROL_PHASE_SHIFT_1)) + pPlayer->RemoveAurasDueToSpell(ALLIANCE_CONTROL_PHASE_SHIFT_1); + + pPlayer->CastSpell(pPlayer, ALLIANCE_CONTROL_PHASE_SHIFT_2, false); + break; + default: + break; + } + } + + void OnCreatureCreate(Creature* pCreature) override + { + switch(pCreature->GetEntry()) + { + // Champions of the Alliance + case NPC_JACOB: + case NPC_AMBROSE: + case NPC_COLOSOS: + case NPC_JAELYNE: + case NPC_LANA: + // Champions of the Horde + case NPC_MOKRA: + case NPC_ERESSEA: + case NPC_RUNOK: + case NPC_ZULTORE: + case NPC_VISCERI: + { + if (m_uiChampionId1 == 0) + m_uiChampionId1 = pCreature->GetEntry(); + else if (m_uiChampionId2 == 0) + m_uiChampionId2 = pCreature->GetEntry(); + else if (m_uiChampionId3 == 0) + m_uiChampionId3 = pCreature->GetEntry(); + else + return; + break; + } + // Argent Challenge + case NPC_EADRIC: + case NPC_PALETRESS: + m_uiArgentChallengerID = pCreature->GetEntry(); + break; + // Black Knight + case NPC_BLACK_KNIGHT: + case NPC_RISEN_JAEREN: + case NPC_RISEN_ARELAS: + // memories + case MEMORY_ALGALON: + case MEMORY_ARCHIMONDE: + case MEMORY_CHROMAGGUS: + case MEMORY_CYANIGOSA: + case MEMORY_DELRISSA: + case MEMORY_ECK: + case MEMORY_ENTROPIUS: + case MEMORY_GRUUL: + case MEMORY_HAKKAR: + case MEMORY_HEIGAN: + case MEMORY_HEROD: + case MEMORY_HOGGER: + case MEMORY_IGNIS: + case MEMORY_ILLIDAN: + case MEMORY_INGVAR: + case MEMORY_KALITHRESH: + case MEMORY_LUCIFRON: + case MEMORY_MALCHEZAAR: + case MEMORY_MUTANUS: + case MEMORY_ONYXIA: + case MEMORY_THUNDERAAN: + case MEMORY_VANCLEEF: + case MEMORY_VASHJ: + case MEMORY_VEKNILASH: + case MEMORY_VEZAX: + break; + default: + return; + } + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + } + + void OnObjectCreate(GameObject* pGo) override + { + switch(pGo->GetEntry()) + { + case GO_CHAMPIONS_LOOT: + case GO_EADRIC_LOOT: + case GO_PALETRESS_LOOT: + case GO_CHAMPIONS_LOOT_H: + case GO_EADRIC_LOOT_H: + case GO_PALETRESS_LOOT_H: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + default: + return; + } + } + + void SetData(uint32 uiType, uint32 uiData) override + { + switch(uiType) + { + case DATA_TOC5_ANNOUNCER: + m_uiAnnouncerID = uiData; + break; + case DATA_CHAMPIONID_1: + m_uiChampionId1 = uiData; + break; + case DATA_CHAMPIONID_2: + m_uiChampionId2 = uiData; + break; + case DATA_CHAMPIONID_3: + m_uiChampionId3 = uiData; + break; + case DATA_CHAMPIONS_COUNT: + m_uiChampionsCount = uiData; + break; + case DATA_ARGENT_CHALLENGER: + m_uiArgentChallengerID = uiData; + break; + case DATA_BLACK_KNIGHT_MINION: + m_uiBlackKnightMinionID = uiData; + break; + case TYPE_GRAND_CHAMPIONS: + m_auiEncounter[0] = uiData; + if (uiData == DONE) + { + if (GameObject* pChest = GetSingleGameObjectFromStorage(m_bIsRegularMode ? GO_CHAMPIONS_LOOT : GO_CHAMPIONS_LOOT_H)) + if (pChest && !pChest->isSpawned()) + pChest->SetRespawnTime(DAY); + } + if (uiData == FAIL) + { + m_auiEncounter[0] = NOT_STARTED; + } + break; + case TYPE_ARGENT_CHALLENGE: + m_auiEncounter[1] = uiData; + if (uiData == DONE) + { + if (m_uiArgentChallengerID == NPC_EADRIC) + if (GameObject* pChest = GetSingleGameObjectFromStorage(m_bIsRegularMode ? GO_EADRIC_LOOT : GO_EADRIC_LOOT_H)) + if (pChest && !pChest->isSpawned()) + pChest->SetRespawnTime(DAY); + + if (m_uiArgentChallengerID == NPC_PALETRESS) + if (GameObject* pChest = GetSingleGameObjectFromStorage(m_bIsRegularMode ? GO_PALETRESS_LOOT : GO_PALETRESS_LOOT_H)) + if (pChest && !pChest->isSpawned()) + pChest->SetRespawnTime(DAY); + } + if (uiData == FAIL) + { + m_auiEncounter[1] = NOT_STARTED; + } + break; + case TYPE_BLACK_KNIGHT: + m_auiEncounter[2] = uiData; + if (uiData == FAIL) + { + m_auiEncounter[2] = NOT_STARTED; + } + break; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + saveStream << m_auiEncounter[i] << " "; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + uint32 GetData(uint32 uiType) const override + { + switch(uiType) + { + case DATA_CHAMPIONID_1: + return m_uiChampionId1; + case DATA_CHAMPIONID_2: + return m_uiChampionId2; + case DATA_CHAMPIONID_3: + return m_uiChampionId3; + case DATA_CHAMPIONS_COUNT: + return m_uiChampionsCount; + case DATA_ARGENT_CHALLENGER: + return m_uiArgentChallengerID; + case DATA_BLACK_KNIGHT_MINION: + return m_uiBlackKnightMinionID; + case DATA_TOC5_ANNOUNCER: + return m_uiAnnouncerID; + case TYPE_GRAND_CHAMPIONS: + return m_auiEncounter[0]; + case TYPE_ARGENT_CHALLENGE: + return m_auiEncounter[1]; + case TYPE_BLACK_KNIGHT: + return m_auiEncounter[2]; + } + + return 0; + } + + const char* Save() const override + { + return m_strInstData.c_str(); + } + + void Load(const char* strIn) + { + if (!strIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(strIn); + + std::istringstream loadStream(strIn); + + for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + loadStream >> m_auiEncounter[i]; + + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; + } +}; + +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 *newscript; + newscript = new Script; + newscript->Name = "instance_trial_of_the_champion"; + newscript->GetInstanceData = &GetInstanceData_instance_trial_of_the_champion; + newscript->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 3ebfa687a1..ca48b32d64 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,11 +15,242 @@ */ /* ScriptData -SDName: trial_of_the_champion -SD%Complete: 0 -SDComment: -SDCategory: Crusader Coliseum, Trial of the Champion +SDName: Trial Of the Champion +SD%Complete: 80% +SDComment: event script. modified by /dev/rsa +SDCategory: trial_of_the_champion EndScriptData */ +/* ContentData +npc_toc5_announcer +EndContentData */ + #include "precompiled.h" #include "trial_of_the_champion.h" + +#define GOSSIP_START_EVENT "Im ready for the next challenge." + +/*###### +## npc_toc5_announcer +######*/ +struct _Messages +{ + char const* name; + uint32 id; + bool state; + uint32 encounter; +}; + +static _Messages _GossipMessage[]= +{ + {GOSSIP_START_EVENT,GOSSIP_ACTION_INFO_DEF+1,false,TYPE_GRAND_CHAMPIONS}, + {GOSSIP_START_EVENT,GOSSIP_ACTION_INFO_DEF+2,false,TYPE_ARGENT_CHALLENGE}, + {GOSSIP_START_EVENT,GOSSIP_ACTION_INFO_DEF+3,false,TYPE_BLACK_KNIGHT}, + {GOSSIP_START_EVENT,GOSSIP_ACTION_INFO_DEF+4,true,TYPE_BLACK_KNIGHT}, +}; + +struct MANGOS_DLL_DECL npc_toc5_announcerAI : public ScriptedAI +{ + npc_toc5_announcerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + } +}; + +CreatureAI* GetAI_npc_toc5_announcer(Creature* pCreature) +{ + return new npc_toc5_announcerAI(pCreature); +} + +bool GossipHello_npc_toc5_announcer(Player* pPlayer, Creature* pCreature) +{ + ScriptedInstance* m_pInstance; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if (!m_pInstance) + return false; + + if (pPlayer->IsInCombat()) + return true; + + for(uint8 i = 0; i < MAX_ENCOUNTER+1; i++) + { + if (!_GossipMessage[i].state && (m_pInstance->GetData(_GossipMessage[i].encounter) == NOT_STARTED || m_pInstance->GetData(_GossipMessage[i].encounter) == IN_PROGRESS)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, _GossipMessage[i].name, GOSSIP_SENDER_MAIN,_GossipMessage[i].id); + break; + } + if (_GossipMessage[i].state && m_pInstance->GetData(_GossipMessage[i].encounter) == DONE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, _GossipMessage[i].name, GOSSIP_SENDER_MAIN,_GossipMessage[i].id); + } + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_toc5_announcer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + ScriptedInstance* m_pInstance; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + pPlayer->CLOSE_GOSSIP_MENU(); + + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + { + if (m_pInstance->GetData(DATA_TOC5_ANNOUNCER) == 0) + { + m_pInstance->SetData(DATA_TOC5_ANNOUNCER, pCreature->GetEntry()); + if (m_pInstance->GetData(DATA_TOC5_ANNOUNCER) == NPC_ARELAS) + { + m_pInstance->SetData(DATA_BLACK_KNIGHT_MINION, 35564); + switch(urand(0, 4)) + { + case 0: m_pInstance->SetData(DATA_CHAMPIONID_1, 35572); break; + case 1: m_pInstance->SetData(DATA_CHAMPIONID_1, 35569); break; + case 2: m_pInstance->SetData(DATA_CHAMPIONID_1, 35571); break; + case 3: m_pInstance->SetData(DATA_CHAMPIONID_1, 35570); break; + case 4: m_pInstance->SetData(DATA_CHAMPIONID_1, 35617); break; + } + do { + switch(urand(0, 4)) + { + case 0: m_pInstance->SetData(DATA_CHAMPIONID_2, 35572); break; + case 1: m_pInstance->SetData(DATA_CHAMPIONID_2, 35569); break; + case 2: m_pInstance->SetData(DATA_CHAMPIONID_2, 35571); break; + case 3: m_pInstance->SetData(DATA_CHAMPIONID_2, 35570); break; + case 4: m_pInstance->SetData(DATA_CHAMPIONID_2, 35617); break; + } + } while(m_pInstance->GetData(DATA_CHAMPIONID_1) == m_pInstance->GetData(DATA_CHAMPIONID_2)); + do{ + switch(urand(0, 4)) + { + case 0: m_pInstance->SetData(DATA_CHAMPIONID_3, 35572); break; + case 1: m_pInstance->SetData(DATA_CHAMPIONID_3, 35569); break; + case 2: m_pInstance->SetData(DATA_CHAMPIONID_3, 35571); break; + case 3: m_pInstance->SetData(DATA_CHAMPIONID_3, 35570); break; + case 4: m_pInstance->SetData(DATA_CHAMPIONID_3, 35617); break; + } + } while(m_pInstance->GetData(DATA_CHAMPIONID_1) == m_pInstance->GetData(DATA_CHAMPIONID_3) || m_pInstance->GetData(DATA_CHAMPIONID_2) == m_pInstance->GetData(DATA_CHAMPIONID_3)); + } + + if (m_pInstance->GetData(DATA_TOC5_ANNOUNCER) == NPC_JAEREN) + { + m_pInstance->SetData(DATA_BLACK_KNIGHT_MINION, 35545); + + switch(urand(0, 4)) + { + case 0: m_pInstance->SetData(DATA_CHAMPIONID_1, 34705); break; + case 1: m_pInstance->SetData(DATA_CHAMPIONID_1, 34702); break; + case 2: m_pInstance->SetData(DATA_CHAMPIONID_1, 34701); break; + case 3: m_pInstance->SetData(DATA_CHAMPIONID_1, 34657); break; + case 4: m_pInstance->SetData(DATA_CHAMPIONID_1, 34703); break; + } + do{ + switch(urand(0, 4)) + { + case 0: m_pInstance->SetData(DATA_CHAMPIONID_2, 34705); break; + case 1: m_pInstance->SetData(DATA_CHAMPIONID_2, 34702); break; + case 2: m_pInstance->SetData(DATA_CHAMPIONID_2, 34701); break; + case 3: m_pInstance->SetData(DATA_CHAMPIONID_2, 34657); break; + case 4: m_pInstance->SetData(DATA_CHAMPIONID_2, 34703); break; + } + } while(m_pInstance->GetData(DATA_CHAMPIONID_1) == m_pInstance->GetData(DATA_CHAMPIONID_2)); + do{ + switch(urand(0, 4)) + { + case 0: m_pInstance->SetData(DATA_CHAMPIONID_3, 34705); break; + case 1: m_pInstance->SetData(DATA_CHAMPIONID_3, 34702); break; + case 2: m_pInstance->SetData(DATA_CHAMPIONID_3, 34701); break; + case 3: m_pInstance->SetData(DATA_CHAMPIONID_3, 34657); break; + case 4: m_pInstance->SetData(DATA_CHAMPIONID_3, 34703); break; + } + } while(m_pInstance->GetData(DATA_CHAMPIONID_1) == m_pInstance->GetData(DATA_CHAMPIONID_3) || m_pInstance->GetData(DATA_CHAMPIONID_2) == m_pInstance->GetData(DATA_CHAMPIONID_3)); + } + + switch(urand(0, 1)) + { + case 0: m_pInstance->SetData(DATA_ARGENT_CHALLENGER, 35119); break; + case 1: m_pInstance->SetData(DATA_ARGENT_CHALLENGER, 34928); break; + } + } + + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == NOT_STARTED || m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == IN_PROGRESS) + { + m_pInstance->SetData(DATA_CHAMPIONS_COUNT, 3); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_1)) + pTemp->Respawn(); + else + pCreature->SummonCreature(m_pInstance->GetData(DATA_CHAMPIONID_1), 738.665771f, 661.031433f, 412.394623f, 4.698702f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_2)) + pTemp->Respawn(); + else + pCreature->SummonCreature(m_pInstance->GetData(DATA_CHAMPIONID_2), 746.864441f, 660.918762f, 411.695465f, 4.698700f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_CHAMPION_3)) + pTemp->Respawn(); + else + pCreature->SummonCreature(m_pInstance->GetData(DATA_CHAMPIONID_3), 754.360779f, 660.816162f, 412.395996f, 4.698700f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + } + } + case GOSSIP_ACTION_INFO_DEF+2: + { + if ((m_pInstance->GetData(TYPE_ARGENT_CHALLENGE) == NOT_STARTED || m_pInstance->GetData(TYPE_ARGENT_CHALLENGE) == IN_PROGRESS) && m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(DATA_ARGENT_CHALLENGER)) + pTemp->Respawn(); + else + pCreature->SummonCreature(m_pInstance->GetData(DATA_ARGENT_CHALLENGER), 746.864441f, 660.918762f, 411.695465f, 4.698700f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + m_pInstance->SetData(TYPE_ARGENT_CHALLENGE, IN_PROGRESS); + } + } + case GOSSIP_ACTION_INFO_DEF+3: + { + if ((m_pInstance->GetData(TYPE_BLACK_KNIGHT) == NOT_STARTED || m_pInstance->GetData(TYPE_BLACK_KNIGHT) == IN_PROGRESS) && m_pInstance->GetData(TYPE_ARGENT_CHALLENGE) == DONE) + { + pCreature->SummonCreature(NPC_BLACK_KNIGHT, 746.864441f, 660.918762f, 411.695465f, 4.698700f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + pCreature->DealDamage(pCreature, pCreature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_pInstance->SetData(TYPE_BLACK_KNIGHT, IN_PROGRESS); + } + } + case GOSSIP_ACTION_INFO_DEF+4: + { + if (m_pInstance->GetData(TYPE_BLACK_KNIGHT) == DONE) + { + pCreature->DealDamage(pCreature, pCreature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + } + return true; +} + +void AddSC_trial_of_the_champion() +{ + Script* NewScript; + + NewScript = new Script; + NewScript->Name = "npc_toc5_announcer"; + NewScript->GetAI = &GetAI_npc_toc5_announcer; + NewScript->pGossipHello = &GossipHello_npc_toc5_announcer; + NewScript->pGossipSelect = &GossipSelect_npc_toc5_announcer; + NewScript->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 d7778d506c..82f5789553 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,17 +1,96 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ +/* Copyright (C) 2006 - 2013 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 + */ -#ifndef DEF_TRIAL_OF_THE_CHAMPION_H -#define DEF_TRIAL_OF_THE_CHAMPION_H +#ifndef DEF_TOC_H +#define DEF_TOC_H enum { - MAX_ENCOUNTER = 3, + MAX_ENCOUNTER = 3, - TYPE_GRAND_CHAMPIONS = 0, - TYPE_ARGENT_CHAMPION = 1, - TYPE_BLACK_KNIGHT = 2, + TYPE_GRAND_CHAMPIONS = 0, + TYPE_ARGENT_CHALLENGE = 1, + TYPE_BLACK_KNIGHT = 2, + + DATA_CHAMPION_1 = 3, + DATA_CHAMPION_2 = 4, + DATA_CHAMPION_3 = 5, + DATA_BLACK_KNIGHT = 6, + DATA_BLACK_KNIGHT_MINION = 7, + DATA_TOC5_ANNOUNCER = 8, + DATA_JAEREN = 9, + DATA_ARELAS = 10, + DATA_CHAMPIONID_1 = 11, + DATA_CHAMPIONID_2 = 12, + DATA_CHAMPIONID_3 = 13, + DATA_ARGENT_CHALLENGER = 15, + DATA_CHAMPIONS_COUNT = 16, + + NPC_JACOB = 34705, + NPC_AMBROSE = 34702, + NPC_COLOSOS = 34701, + NPC_JAELYNE = 34657, + NPC_LANA = 34703, + NPC_MOKRA = 35572, + NPC_ERESSEA = 35569, + NPC_RUNOK = 35571, + NPC_ZULTORE = 35570, + NPC_VISCERI = 35617, + NPC_EADRIC = 35119, + NPC_PALETRESS = 34928, + NPC_BLACK_KNIGHT = 35451, + NPC_RISEN_JAEREN = 35545, + NPC_RISEN_ARELAS = 35564, + NPC_JAEREN = 35004, + + NPC_ARELAS = 35005, + MEMORY_ALGALON = 35052, + MEMORY_ARCHIMONDE = 35041, + MEMORY_CHROMAGGUS = 35033, + MEMORY_CYANIGOSA = 35046, + MEMORY_DELRISSA = 35043, + MEMORY_ECK = 35047, + MEMORY_ENTROPIUS = 35044, + MEMORY_GRUUL = 35039, + MEMORY_HAKKAR = 35034, + MEMORY_HEIGAN = 35049, + MEMORY_HEROD = 35030, + MEMORY_HOGGER = 34942, + MEMORY_IGNIS = 35050, + MEMORY_ILLIDAN = 35042, + MEMORY_INGVAR = 35045, + MEMORY_KALITHRESH = 35037, + MEMORY_LUCIFRON = 35031, + MEMORY_MALCHEZAAR = 35038, + MEMORY_MUTANUS = 35029, + MEMORY_ONYXIA = 35048, + MEMORY_THUNDERAAN = 35032, + MEMORY_VANCLEEF = 35028, + MEMORY_VASHJ = 35040, + MEMORY_VEKNILASH = 35036, + MEMORY_VEZAX = 35051, + + 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, + + DESPAWN_TIME = 300000 }; #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 25a3f1f7e8..3fe7a67ee5 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,59 +16,469 @@ /* ScriptData SDName: boss_anubarak_trial -SD%Complete: 0 -SDComment: +SD%Complete: 70% +SDComment: by /dev/rsa SDCategory: EndScriptData */ #include "precompiled.h" #include "trial_of_the_crusader.h" -enum +enum Yells { - SAY_AGGRO = -1649064, - SAY_SLAY_1 = -1649065, - SAY_SLAY_2 = -1649066, - SAY_DEATH = -1649067, - SAY_BERSERK = -1649068, - SAY_SUBMERGE = -1649069, - SAY_LEECHING_SWARM = -1649070, + SAY_INTRO = -1649038, + SAY_AGGRO = -1649064, + SAY_SUBMERGE = -1649069, + SAY_LOW_HEALTH = -1649070, + SAY_SLAY_1 = -1649065, + SAY_SLAY_2 = -1649066, + SAY_DEATH = -1649067, + + EMOTE_SUBMERGE = -1649071, + EMOTE_PURSUING = -1649072, + EMOTE_OUT_OF_THE_GROUND = -1649073, + EMOTE_LEECHING_SWARM = -1649074, +}; + +enum Summons +{ + NPC_FROST_SPHERE = 34606, + NPC_PERMAFROST = 33184, + NPC_NERUBIAN_BURROW_1 = 34862, + NPC_NERUBIAN_BURROW_2 = 34863, + NPC_NERUBIAN_BURROW_3 = 34864, + NPC_NERUBIAN_BURROW_4 = 34865, + NPC_BURROWER = 34607, + NPC_SCARAB = 34605, + NPC_SPIKE = 34660, + NPC_SPIKE_TRIGGER = 5672, }; -struct MANGOS_DLL_DECL boss_anubarak_trialAI : public ScriptedAI +enum BossSpells { - boss_anubarak_trialAI(Creature* pCreature) : ScriptedAI(pCreature) + SPELL_FROST_VISUAL = 67539, + SPELL_PERMAFROST = 66193, + SPELL_PERMAFROST_SPAWN = 65882, + SPELL_COLD = 66013, + SPELL_MARK = 67574, + SPELL_LEECHING_SWARM = 66118, + SPELL_LEECHING_HEAL = 66125, + SPELL_LEECHING_DAMAGE = 66240, + SPELL_IMPALE_10 = 65919, + SPELL_IMPALE_25 = 67859, + SPELL_IMPALE_GROUND = 65921, + SPELL_PURSUING_SPIKE_LOW = 65920, + SPELL_PURSUING_SPIKE_MED = 65922, + SPELL_PURSUING_SPIKE_HIGH = 65923, + SPELL_PURSUING_SPIKE_COLD = 66181, + SPELL_POUND = 66012, + SPELL_SHOUT = 67730, + SPELL_SUBMERGE_ANUB = 53421, + SPELL_EMERGE_ANUB = 65982, + SPELL_SUBMERGE_BURROWER = 53421, // Temporal (Original: 67322) + SPELL_EMERGE_BURROWER = 65982, + SPELL_SUMMON_BEATLES = 66339, + SPELL_DETERMINATION = 66092, + SPELL_ACID_MANDIBLE = 65775, + SPELL_SPIDER_FRENZY = 66129, + SPELL_EXPOSE_WEAKNESS = 67847, + SPELL_SUMMON_SCARAB = 66340, + SPELL_SHADOW_STRIKE = 66134, + SPELL_ACHIEV_TRAITOR_KING_10 = 68186, + SPELL_ACHIEV_TRAITOR_KING_25 = 68515, + SPELL_BERSERK = 26662, +}; + +struct MANGOS_DLL_DECL boss_anubarak_trialAI : public BSWScriptedAI +{ + boss_anubarak_trialAI(Creature* pCreature) : BSWScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); } ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool intro; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiEventStep; + uint32 m_uiNextEventTimer; - void Reset() {} + uint32 m_uiPoundTimer; + uint32 m_uiColdTimer; + uint32 m_uiSummonBurrowerTimer; + uint32 m_uiSubmergeAnubTimer; + uint32 m_uiNerubianBurrowTimer; + uint32 m_uiSubmergePhaseTimer; + uint32 m_uiFrostSphereOneTimer; + uint32 m_uiFrostSphereTwoTimer; + uint32 m_uiSummonScarabTimer; + uint32 m_uiPursuingTimer; + uint32 m_uiBerserkTimer; - void JustReachedHome() + Unit* pTarget; + + void Reset() { - if (m_pInstance) - m_pInstance->SetData(TYPE_ANUBARAK, NOT_STARTED); + if (!m_pInstance) + return; + + intro = true; + pTarget = NULL; + + m_uiEventStep = 0; + m_uiNextEventTimer = 0; + + m_uiPoundTimer = 20000; + m_uiColdTimer = 30000; + m_uiSummonBurrowerTimer = 10000; + m_uiSubmergeAnubTimer = 80000; + m_uiNerubianBurrowTimer = 0; + m_uiSubmergePhaseTimer = 88000; + m_uiFrostSphereOneTimer = urand(5000, 10000); + m_uiFrostSphereTwoTimer = 2000; + m_uiSummonScarabTimer = 2000; + m_uiPursuingTimer = 1000; + m_uiBerserkTimer = 570000; + + m_creature->SetRespawnDelay(DAY); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void JustDied(Unit* pKiller) + void NextStep(uint32 uiTime = 1000) + { + ++m_uiEventStep; + m_uiNextEventTimer = uiTime; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_SLAY_1 - urand(0, 1),m_creature,pVictim); + } + void MoveInLineOfSight(Unit* pWho) override + { + if (!intro) + return; + + DoScriptText(SAY_INTRO, m_creature); + intro = false; + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_1)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_2)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_3)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_4)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + } + + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_ANUBARAK, DONE); + m_pInstance->SetData(TYPE_ANUBARAK, FAIL); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_COUNTER, m_pInstance->GetData(TYPE_COUNTER)); + DoScriptText(SAY_DEATH, m_creature); + m_pInstance->SetData(TYPE_ANUBARAK, DONE); + m_pInstance->SetData(TYPE_EVENT, 6000); } void Aggro(Unit* pWho) { + if (!intro) + DoScriptText(SAY_AGGRO, m_creature); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetInCombatWithZone(); + m_pInstance->SetData(TYPE_ANUBARAK, IN_PROGRESS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiNextEventTimer <= uiDiff) + { + switch (m_uiEventStep) + { + case 0: + if (m_uiFrostSphereOneTimer <= uiDiff) + { + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[29].x + urand(5, 15), SpawnLoc[29].y - urand(10, 20), SpawnLoc[29].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[30].x + urand(5, 15), SpawnLoc[30].y - urand(10, 20), SpawnLoc[30].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[31].x + urand(5, 15), SpawnLoc[31].y - urand(10, 20), SpawnLoc[31].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[32].x + urand(5, 15), SpawnLoc[32].y - urand(10, 20), SpawnLoc[32].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[49].x + urand(5, 15), SpawnLoc[49].y - urand(10, 20), SpawnLoc[49].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[50].x + urand(5, 15), SpawnLoc[50].y - urand(10, 20), SpawnLoc[50].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[51].x + urand(5, 15), SpawnLoc[51].y - urand(10, 20), SpawnLoc[51].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[52].x + urand(5, 15), SpawnLoc[52].y - urand(10, 20), SpawnLoc[52].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + m_uiFrostSphereOneTimer = 40000; + } + else + m_uiFrostSphereOneTimer -= uiDiff; + + if (m_uiPoundTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_POUND) == CAST_OK) + m_uiPoundTimer = 20000; + } + else + m_uiPoundTimer -= uiDiff; + + if (m_uiColdTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_COLD) == CAST_OK) + m_uiColdTimer = 25000; + } + else + m_uiColdTimer -= uiDiff; + + if (m_uiSummonBurrowerTimer <= uiDiff) + { + float x, y, z; + m_creature->GetPosition(x, y, z); + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + + if (m_bIs25Man || m_bIsHeroic) + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + + if (m_bIs25Man && m_bIsHeroic) + { + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + } + m_uiSummonBurrowerTimer = 45000; + } + else + m_uiSummonBurrowerTimer -= uiDiff; + + if (m_uiSubmergeAnubTimer <= uiDiff) + { + m_creature->CastSpell(m_creature, SPELL_SUBMERGE_ANUB, false); + m_uiSubmergeAnubTimer = 80000; + NextStep(); + } + else + m_uiSubmergeAnubTimer -= uiDiff; + + break; + case 1: + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoScriptText(SAY_SUBMERGE, m_creature); + DoScriptText(EMOTE_SUBMERGE, m_creature); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_1)) + pNerubianBurrow->SetVisibility(VISIBILITY_ON); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_2)) + pNerubianBurrow->SetVisibility(VISIBILITY_ON); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_3)) + pNerubianBurrow->SetVisibility(VISIBILITY_ON); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_4)) + pNerubianBurrow->SetVisibility(VISIBILITY_ON); + + NextStep(2000); + break; + case 2: + if (m_uiPursuingTimer <= uiDiff) + { + float x, y, z; + m_creature->GetPosition(x, y, z); + + m_creature->SummonCreature(NPC_SPIKE, x, y, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + m_uiPursuingTimer = 90000; + } + else + m_uiPursuingTimer -= uiDiff; + + if (m_uiFrostSphereTwoTimer <= uiDiff) + { + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[29].x + urand(5, 15), SpawnLoc[29].y - urand(10, 20), SpawnLoc[29].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 20000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[30].x + urand(5, 15), SpawnLoc[30].y - urand(10, 20), SpawnLoc[30].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 40000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[31].x + urand(5, 15), SpawnLoc[31].y - urand(10, 20), SpawnLoc[31].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 20000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[32].x + urand(5, 15), SpawnLoc[32].y - urand(10, 20), SpawnLoc[32].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 40000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[49].x + urand(5, 15), SpawnLoc[49].y - urand(10, 20), SpawnLoc[49].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[50].x + urand(5, 15), SpawnLoc[50].y - urand(10, 20), SpawnLoc[50].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[51].x + urand(5, 15), SpawnLoc[51].y - urand(10, 20), SpawnLoc[51].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + if (Creature *pFrostSphere = m_creature->SummonCreature(NPC_FROST_SPHERE, SpawnLoc[52].x + urand(5, 15), SpawnLoc[52].y - urand(10, 20), SpawnLoc[52].z + 10.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + pFrostSphere->CastSpell(m_creature, SPELL_FROST_VISUAL, false); + + m_uiFrostSphereTwoTimer = 30000; + } + else + m_uiFrostSphereTwoTimer -= uiDiff; + + if (m_uiSummonScarabTimer <= uiDiff) + { + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_1)) + pNerubianBurrow->CastSpell(pNerubianBurrow, SPELL_SUMMON_SCARAB, false); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_2)) + pNerubianBurrow->CastSpell(pNerubianBurrow, SPELL_SUMMON_SCARAB, false); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_3)) + pNerubianBurrow->CastSpell(pNerubianBurrow, SPELL_SUMMON_SCARAB, false); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_4)) + pNerubianBurrow->CastSpell(pNerubianBurrow, SPELL_SUMMON_SCARAB, false); + + m_uiSummonScarabTimer = 8000; + } + else + m_uiSummonScarabTimer -= uiDiff; + + if (m_uiSubmergePhaseTimer <= uiDiff) + { + m_uiSubmergePhaseTimer = 90000; + NextStep(); + } + else + m_uiSubmergePhaseTimer -= uiDiff; + + break; + case 3: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE_ANUB); + m_creature->CastSpell(m_creature, SPELL_EMERGE_ANUB, false); + DoScriptText(EMOTE_OUT_OF_THE_GROUND,m_creature); + + if (Creature *pSpike = m_pInstance->GetSingleCreatureFromStorage(NPC_SPIKE)) + pSpike->ForcedDespawn(); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_1)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_2)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_3)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + if (Creature *pNerubianBurrow = m_pInstance->GetSingleCreatureFromStorage(NPC_NERUBIAN_BURROW_4)) + pNerubianBurrow->SetVisibility(VISIBILITY_OFF); + + m_uiEventStep = 0; + break; + case 4: + m_creature->CastSpell(m_creature, SPELL_LEECHING_SWARM, false); + DoScriptText(SAY_LOW_HEALTH, m_creature); + DoScriptText(EMOTE_LEECHING_SWARM, m_creature); + m_uiEventStep = 5; + NextStep(3000); + break; + case 5: + if (m_uiPoundTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_POUND) == CAST_OK) + m_uiPoundTimer = 20000; + } + else + m_uiPoundTimer -= uiDiff; + + if (m_uiColdTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_COLD) == CAST_OK) + m_uiColdTimer = 25000; + } + else + m_uiColdTimer -= uiDiff; + + if (m_bIsHeroic) + { + if (m_uiSummonBurrowerTimer <= uiDiff) + { + float x, y, z; + m_creature->GetPosition(x, y, z); + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + + if (m_bIs25Man || m_bIsHeroic) + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + + if (m_bIs25Man && m_bIsHeroic) + { + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + m_creature->SummonCreature(NPC_BURROWER, x + 3.0f, y + 3.0f, z, 0, TEMPSUMMON_MANUAL_DESPAWN, 60000); + } + m_uiSummonBurrowerTimer = 45000; + } + else + m_uiSummonBurrowerTimer -= uiDiff; + } + break; + } + + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 570000; + } + else + m_uiBerserkTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 30.0f && m_uiEventStep == 0) + m_uiEventStep = 4; + + } + else + m_uiNextEventTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -78,12 +488,468 @@ CreatureAI* GetAI_boss_anubarak_trial(Creature* pCreature) return new boss_anubarak_trialAI(pCreature); } +struct MANGOS_DLL_DECL mob_swarm_scarabAI : public BSWScriptedAI +{ + mob_swarm_scarabAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiAcidMandibleTimer; + uint32 m_uiDeterminationTimer; + + void Reset() + { + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(DAY); + + m_uiAcidMandibleTimer = 2000; + m_uiDeterminationTimer = urand(10000, 20000); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + } + + void JustDied(Unit* Killer) + { + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_bIs25Man ? SPELL_ACHIEV_TRAITOR_KING_25 : SPELL_ACHIEV_TRAITOR_KING_10); + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_bIs25Man ? SPELL_ACHIEV_TRAITOR_KING_25 : SPELL_ACHIEV_TRAITOR_KING_10); + m_creature->ForcedDespawn(5000); + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_ANUBARAK) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiDeterminationTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DETERMINATION) == CAST_OK) + m_uiDeterminationTimer = 30000; + } + else + m_uiDeterminationTimer -= uiDiff; + + if (m_uiAcidMandibleTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ACID_MANDIBLE) == CAST_OK) + m_uiAcidMandibleTimer = 2000; + } + else + m_uiAcidMandibleTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_swarm_scarab(Creature* pCreature) +{ + return new mob_swarm_scarabAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_nerubian_borrowerAI : public BSWScriptedAI +{ + mob_nerubian_borrowerAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsSubmerged; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiExposeWeaknessTimer; + uint32 m_uiSpiderFrenzyTimer; + uint32 m_uiShadowStrikeTimer; + uint32 m_uiSubmergeBurrowerTimer; + + void Reset() + { + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(DAY); + m_bIsSubmerged = false; + + m_uiExposeWeaknessTimer = 8000; + m_uiSpiderFrenzyTimer = 0; + m_uiShadowStrikeTimer = 5000; + m_uiSubmergeBurrowerTimer = 5000; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + } + + void JustDied(Unit* Killer) + { + m_creature->ForcedDespawn(5000); + + if (Creature* pNerubianBurrower = GetClosestCreatureWithEntry(m_creature, NPC_BURROWER, 50.0f)) + pNerubianBurrower->RemoveAurasDueToSpell(SPELL_SPIDER_FRENZY); + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_ANUBARAK) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiExposeWeaknessTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_EXPOSE_WEAKNESS) == CAST_OK) + m_uiExposeWeaknessTimer = 8000; + } + else + m_uiExposeWeaknessTimer -= uiDiff; + + if (m_uiSpiderFrenzyTimer <= uiDiff) + { + if (Creature* pNerubianBurrower = GetClosestCreatureWithEntry(m_creature, NPC_BURROWER, 50.0f)) + { + m_creature->_AddAura(SPELL_SPIDER_FRENZY); + pNerubianBurrower->_AddAura(SPELL_SPIDER_FRENZY); + } + + m_uiSpiderFrenzyTimer = 1000; + } + else + m_uiSpiderFrenzyTimer -= uiDiff; + + if (m_bIsHeroic) + { + if (m_uiShadowStrikeTimer <= uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_SHADOW_STRIKE, false); + m_uiShadowStrikeTimer = 30000; + } + else + m_uiShadowStrikeTimer -= uiDiff; + } + + if (m_creature->GetHealthPercent() < 20.0f && !m_bIsSubmerged && !hasAura(SPELL_PERMAFROST, m_creature)) + { + m_creature->CastSpell(m_creature, SPELL_SUBMERGE_BURROWER, false); + m_creature->RemoveAllAuras(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoScriptText(EMOTE_SUBMERGE, m_creature); + m_bIsSubmerged = true; + } + + if (m_bIsSubmerged) + { + if (m_uiSubmergeBurrowerTimer <= uiDiff) + { + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_uiSubmergeBurrowerTimer = 5000; + } + else + m_uiSubmergeBurrowerTimer -= uiDiff; + } + + if (m_creature->GetHealthPercent() > 50.0f && m_bIsSubmerged) + { + m_creature->CastSpell(m_creature, SPELL_EMERGE_BURROWER, false); + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE_BURROWER); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoScriptText(EMOTE_OUT_OF_THE_GROUND, m_creature); + m_bIsSubmerged = false; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_nerubian_borrower(Creature* pCreature) +{ + return new mob_nerubian_borrowerAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_frost_sphereAI : public BSWScriptedAI +{ + mob_frost_sphereAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->SetLevitate(true); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveRandom(); + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->CastSpell(m_creature, SPELL_PERMAFROST_SPAWN, false); + + float x, y, z; + m_creature->GetPosition(x, y, z); + if (Creature *pPermafrost = m_creature->SummonCreature(NPC_PERMAFROST, x, y, z - 9.8f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000)) + { + pPermafrost->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pPermafrost->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pPermafrost->CastSpell(pPermafrost, SPELL_PERMAFROST, false); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_ANUBARAK) != IN_PROGRESS) + m_creature->ForcedDespawn(); + } +}; + +CreatureAI* GetAI_mob_frost_sphere(Creature* pCreature) +{ + return new mob_frost_sphereAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_anubarak_spikeAI : public BSWScriptedAI +{ + mob_anubarak_spikeAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + + bool m_bIncreaseSpeed; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiEventStep; + uint32 m_uiNextEventTimer; + + uint32 m_uiImpaleTimer; + uint32 m_uiIncreaseSpeedTimer; + uint32 m_uiSpikeCallTimer; + uint32 m_uiPermafrostTimer; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetInCombatWithZone(); + m_creature->setFaction(14); + m_creature->SetSpeedRate(MOVE_RUN, 0.0f); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_uiEventStep = 0; + m_uiNextEventTimer = 8000; + + m_uiImpaleTimer = 5000; + m_uiIncreaseSpeedTimer = 5000; + m_uiSpikeCallTimer = 4500; + m_uiPermafrostTimer = 5000; + } + + void NextStep(uint32 uiTime = 1000) + { + ++m_uiEventStep; + m_uiIncreaseSpeedTimer = uiTime; + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_ANUBARAK) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiIncreaseSpeedTimer <= uiDiff) + { + switch (m_uiEventStep) + { + case 0: + m_creature->SetSpeedRate(MOVE_RUN, 0.75f); + m_creature->CastSpell(m_creature, SPELL_PURSUING_SPIKE_LOW, false); + NextStep(7000); + break; + case 1: + m_creature->SetSpeedRate(MOVE_RUN, 1.0f); + m_creature->CastSpell(m_creature, SPELL_PURSUING_SPIKE_MED, false); + NextStep(7000); + break; + case 2: + m_creature->SetSpeedRate(MOVE_RUN, 1.5f); + m_creature->CastSpell(m_creature, SPELL_PURSUING_SPIKE_HIGH, false); + NextStep(7000); + break; + } + } + else + m_uiIncreaseSpeedTimer -= uiDiff; + + if (m_uiSpikeCallTimer <= uiDiff) + { + m_creature->SetVisibility(VISIBILITY_ON); + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoScriptText(EMOTE_PURSUING, m_creature, pTarget); + m_creature->AddThreat(pTarget, 100000.0f); + m_creature->CastSpell(pTarget, SPELL_MARK, false); + m_creature->CastSpell(m_creature, SPELL_IMPALE_GROUND, false); + } + m_uiSpikeCallTimer = 90000; + } + else + m_uiSpikeCallTimer -= uiDiff; + + if (m_uiImpaleTimer <= uiDiff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 4.0f)) + { + m_creature->CastSpell(m_creature->getVictim(), m_bIs25Man? SPELL_IMPALE_25 : SPELL_IMPALE_10, false); + m_creature->ForcedDespawn(100); + + float x, y, z; + m_creature->GetPosition(x, y, z); + m_creature->SummonCreature(NPC_SPIKE, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); + } + + m_uiImpaleTimer = 500; + } + else + m_uiImpaleTimer -= uiDiff; + + if (m_uiPermafrostTimer <= uiDiff) + { + if (m_creature->HasAura(SPELL_PERMAFROST) || GetClosestCreatureWithEntry(m_creature, NPC_PERMAFROST, 5.0f)) + { + m_creature->RemoveAllAuras(); + m_creature->ForcedDespawn(); + + float x, y, z; + m_creature->GetPosition(x, y, z); + m_creature->SummonCreature(NPC_SPIKE, x + urand(5.0f, 10.0f), y + urand(5.0f, 10.0f), z, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); + } + m_uiPermafrostTimer = 250; + } + else + m_uiPermafrostTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_anubarak_spike(Creature* pCreature) +{ + return new mob_anubarak_spikeAI(pCreature); +}; + +/*###### +## npc_nerubian_borrow +######*/ + +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct MANGOS_DLL_DECL 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* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_anubarak_trial"; + pNewScript->GetAI = &GetAI_boss_anubarak_trial; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_anubarak_spike"; + pNewScript->GetAI = &GetAI_mob_anubarak_spike; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_frost_sphere"; + pNewScript->GetAI = &GetAI_mob_frost_sphere; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_anubarak_trial"; - newscript->GetAI = &GetAI_boss_anubarak_trial; - newscript->RegisterSelf(); -} \ No newline at end of file + pNewScript = new Script; + pNewScript->Name = "npc_nerubian_borrow"; + pNewScript->GetAI = &GetAI_npc_nerubian_borrow; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_nerubian_borrower"; + pNewScript->GetAI = &GetAI_mob_nerubian_borrower; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_swarm_scarab"; + pNewScript->GetAI = &GetAI_mob_swarm_scarab; + 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 379d45ad58..75653cbe1b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -11,28 +11,2658 @@ * * 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 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* ScriptData SDName: faction_champions -SD%Complete: 0 -SDComment: +SD%Complete: 60% +SDComment: Scripts by Selector, modified by /dev/rsa SDCategory: Crusader Coliseum EndScriptData */ #include "precompiled.h" #include "trial_of_the_crusader.h" -enum +#define AI_MELEE 0 +#define AI_RANGED 1 +#define AI_HEALER 2 + +#define SPELL_ANTI_AOE 68595 +#define SPELL_PVP_TRINKET 65547 + +enum Spells { - SAY_GARROSH_PVP_A_SLAY_1 = -1649048, - SAY_GARROSH_PVP_A_SLAY_2 = -1649049, - SAY_GARROSH_PVP_A_SLAY_3 = -1649050, - SAY_GARROSH_PVP_A_SLAY_4 = -1649051, + /******************************************************************** + HEALERS + ********************************************************************/ + + //Druid Restoration + SPELL_LIFEBLOOM = 66093, + SPELL_NOURISH = 66066, + SPELL_REGROWTH = 66067, + SPELL_REJUVENATION = 66065, + SPELL_TRANQUILITY = 66086, + SPELL_BARKSKIN = 65860, //1 min cd + SPELL_THORNS = 66068, + SPELL_NATURE_GRASP = 66071, //1 min cd, self buff + SPELL_ROOTS = 66070, + + //Shaman Restoraion + SPELL_HEALING_WAVE = 66055, + SPELL_RIPTIDE = 66053, + SPELL_SPIRIT_CLEANSE = 66056, //friendly only + SPELL_HEX = 66054, + SPELL_EARTH_SHIELD = 66063, + SPELL_EARTH_SHOCK = 65973, + + //Paladyn Holy + SPELL_HAND_OF_FREEDOM = 68757, //25 sec cd + SPELL_BUBBLE = 66010, //5 min cd + SPELL_CLEANSE = 66116, + SPELL_FLASH_OF_LIGHT = 66113, + SPELL_HOLY_LIGHT = 66112, + SPELL_HOLY_SHOCK = 66114, + SPELL_FLASH_HEAL = 66113, + SPELL_HAND_OF_PROTECTION = 66009, + SPELL_HAMMER_OF_JUSTICE = 66613, + SPELL_FORBEARANCE = 25771, + + //Priest Discipline + SPELL_RENEW = 66177, + SPELL_SHIELD = 66099, + SPELL_FLASH_HEAL_P = 66104, + SPELL_DISPEL = 65546, + SPELL_PSYCHIC_SCREAM = 65543, + SPELL_MANA_BURN = 66100, + SPELL_PEANANCE = 68030, + SPELL_WEAKEN_SOUL = 6788, + + /******************************************************************** + RANGED + ********************************************************************/ + + //Priest Shadow + SPELL_SILENCE = 65542, + SPELL_VAMPIRIC_TOUCH = 65490, + SPELL_SW_PAIN = 65541, + SPELL_MIND_FLAY = 65488, + SPELL_MIND_BLAST = 65492, + SPELL_HORROR = 65545, + SPELL_DISPERSION = 65544, + SPELL_SHADOWFORM = 16592, + + //Warlock + SPELL_HELLFIRE = 65816, + SPELL_CORRUPTION = 65810, + SPELL_CURSE_OF_AGONY = 65814, + SPELL_CURSE_OF_EXHAUSTION = 65815, + SPELL_FEAR = 65809, //8s + SPELL_SEARING_PAIN = 65819, + SPELL_SHADOW_BOLT = 65821, + SPELL_UNSTABLE = 65812, + SPELL_SUMMON_FEL = 67514, + + //Mage + SPELL_BARRAGE = 65799, //3s + SPELL_BLAST = 65791, + SPELL_EXPLOSION = 65800, + SPELL_BLINK = 65793, //15s + SPELL_CS = 65790, //24s + SPELL_FROST_NOVA = 65792, //25s + SPELL_FROSTBOLT = 65807, + SPELL_ICE_BLOCK = 65802, //5min + SPELL_POLY = 65801, //15s + + //Hunter + SPELL_AIMED_SHOT = 65883, + SPELL_DETERENCE = 65871, //90s + SPELL_DISENGAGE = 65869, //30s + SPELL_EXPLOSIVE_SHOT = 65866, + SPELL_FROST_TRAP = 65880, //30s + SPELL_SHOOT = 65868, //1.7s + SPELL_STEADY_SHOT = 65867, //3s + SPELL_WING_CLIP = 66207, //6s + SPELL_WYVERN_STING = 65877, //60s + SPELL_CALL_PET = 67777, + + //Druid Balance + SPELL_CYCLONE = 65859, //6s + SPELL_ROOTS_B = 65857, //10s + SPELL_FEARIE = 65863, + SPELL_FORCED_OF_NATURE = 65861, //180s + SPELL_SWARM = 65855, + SPELL_MOONFIRE = 65856, //5s + SPELL_STARFIRE = 65854, + SPELL_WRATH = 65862, + //Barskin + + /******************************************************************** + MELEE + ********************************************************************/ - SAY_VARIAN_PVP_H_SLAY_1 = -1649052, - SAY_VARIAN_PVP_H_SLAY_2 = -1649053, - SAY_VARIAN_PVP_H_SLAY_3 = -1649054, - SAY_VARIAN_PVP_H_SLAY_4 = -1649055, + //Warrior Arms + SPELL_BLADESTORM = 65947, + SPELL_INTIMIDATING_SHOUT = 65930, + SPELL_MORTAL_STRIKE = 65926, + SPELL_CHARGE = 68764, + SPELL_DISARM = 65935, + SPELL_OVERPOWER = 65924, + SPELL_SUNDER_ARMOR = 65936, + SPELL_SHATTERING_THROW = 65940, + SPELL_RETALIATION = 65932, + + //Death Knight + SPELL_CHAINS = 66020, //8sec + SPELL_DEATH_COLI = 66019, //5sec + SPELL_DEATH_GRIP = 66017, //35sec + SPELL_FROST_STRIKE = 66047, //6sec + SPELL_ICEBOUND = 66023, //1min + SPELL_ICE_TOUCH = 66021, //8sec + SPELL_STRANGULATE = 66018, //2min + + //Rogue + SPELL_FAN_OF_KNIVES = 65955, //2sec + SPELL_BLIND = 65960, //2min + SPELL_CLOAK = 65961, //90sec + SPELL_BLADE_FLURRY = 65956, //2min + SPELL_SHADOWSTEP = 66178, //30sec + SPELL_HEMORRHAGE = 65954, + SPELL_EVISCERATE = 65957, + SPELL_WOUND_POISON = 65962, + + //Shaman En + SPELL_LAVA_LASH = 65974, + SPELL_STORMSTRIKE = 65970, + SPELL_WINDFURY = 65976, + SPELL_MALESTROM = 65986, + //Heroism + //Earth Shock + + SPELL_TOTEM_WIND = 39586, + SPELL_TOTEM_GROUND = 65989, + SPELL_TOTEM_HEAL = 71984, + SPELL_TOTEM_TREMOR = 65992, + SPELL_TOTEM_STR = 65991, + SPELL_TOTEM_SEARING = 39588, + + //Paladyn Retri + SPELL_AVENGING_WRATH = 66011, //3min cd + SPELL_STRIKE = 66003, //6sec cd + SPELL_STORM = 66006, //10sec cd + SPELL_JUDGEMENT_COMAND = 66005, //8sec cd + SPELL_REPENTANCE = 66008, //60sec cd + SPELL_SEAL_COMAND = 66004, //no cd + //SPELL_Divine_Shield = 66010, //5min cd + //SPELL_Hand_of_Protection = 66009, //5min cd + //SPELL_HAMMER_OF_JUSTICE = 66007, //40sec cd + + //Felhunter + SPELL_DEVOUR_MAGIC = 67518, + SPELL_SPELL_LOCK = 67519, + + //Cat + SPELL_CLAW = 67793, + + //Other + //SPELL_TRINKET = 65547, //5min cd + SPELL_HEROISM = 65983, + SPELL_BLOODLUST = 65980, + AURA_EXHAUSTION = 57723, + AURA_SATED = 57724, + SPELL_DIVINE_SHIELD = 63148, + SPELL_BLOCK = 45438, + + //NPC + NPC_FELHUNTER = 35465, + NPC_CAT = 35610, }; + +struct MANGOS_DLL_DECL boss_faction_championsAI : public BSWScriptedAI +{ + boss_faction_championsAI(Creature* pCreature, uint32 aitype) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroicMode = (m_uiMapDifficulty == RAID_DIFFICULTY_10MAN_HEROIC || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + mAIType = aitype; + Init(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroicMode; + + Difficulty m_uiMapDifficulty; + uint32 mAIType; + uint32 UpdateTimer; + uint32 m_uiChangeTargetTimer; + uint32 m_uiInsygniaTimer; + + void Init() + { + UpdateTimer = 5000; + m_uiChangeTargetTimer = 6000; + resetTimers(); + m_uiInsygniaTimer = urand(30*IN_MILLISECONDS, 60*IN_MILLISECONDS); + m_creature->SetRespawnDelay(DAY); + } + + void Reset() + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CRUSADERS, NOT_STARTED); + } + + void JustDied(Unit *killer) + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_CRUSADERS_COUNT, 0); + + if (m_pInstance->GetData(TYPE_CRUSADERS_COUNT) == 0) + if(!m_pInstance->GetData(TYPE_CRUSADERS_ACHIEV_FAIL)) + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ACHIEV_RESILIENCE_WILL_FIX_IT); + + m_pInstance->SetData(TYPE_CRUSADERS_DEAD, m_pInstance->GetData(TYPE_CRUSADERS_DEAD) + 1); + } + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_CRUSADERS, IN_PROGRESS); + m_creature->CastSpell(m_creature, SPELL_ANTI_AOE, true); + if (who->GetTypeId() != TYPEID_PLAYER) + if (Unit* player = doSelectRandomPlayerAtRange(80.0f)) + m_creature->AddThreat(player, 100.0f); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + + if (mAIType == AI_MELEE) + m_creature->GetMotionMaster()->MoveChase(pWho); + else + DoStartMovement(pWho, 20.0f); + + if (mAIType == AI_HEALER) + m_creature->GetMotionMaster()->MoveChase(pWho); + + if (mAIType == AI_RANGED) + m_creature->GetMotionMaster()->MoveChase(pWho); + + SetCombatMovement(true); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CRUSADERS, FAIL); + + m_creature->ForcedDespawn(); + } + + float CalculateThreat(float distance, float armor, uint32 health) + { + float dist_mod = (mAIType == AI_MELEE) ? 15.0f/(15.0f + distance) : 1.0f; + float armor_mod = (mAIType == AI_MELEE) ? armor / 16635.0f : 0.0f; + float eh = (health+1) * (1.0f + armor_mod); + return dist_mod * 30000.0f / eh; + } + + void UpdateThreat() + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + ThreatList::const_iterator itr; + for (itr = tList.begin(); itr!=tList.end(); ++itr) + { + Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); + if (pUnit && m_creature->getThreatManager().getThreat(pUnit)) + { + if (pUnit->GetTypeId()==TYPEID_PLAYER) + { + float threat = CalculateThreat(m_creature->GetDistance2d(pUnit), (float)pUnit->GetArmor(), pUnit->GetHealth()); + m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); + m_creature->AddThreat(pUnit, 1000000.0f * threat); + } + } + } + } + + void UpdatePower() + { + if (m_creature->GetPowerType() == POWER_MANA) + m_creature->ModifyPower(POWER_MANA, m_creature->GetMaxPower(POWER_MANA) / 3); + } + + void RemoveCC() + { + m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_STUN); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_FEAR); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_PACIFY); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_CONFUSE); + //DoCast(m_creature, SPELL_PVP_TRINKET); + } + + //add + Unit* SelectEnemyTargetWithinMana() + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + ThreatList::const_iterator iter; + for (iter = tList.begin(); iter!=tList.end(); ++iter) + { + Unit* target = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid()); + if (target && target->GetPowerType() == POWER_MANA) + return target; + } + return NULL; + } + + Unit* KillPlayer() + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + ThreatList::const_iterator iter; + for (iter = tList.begin(); iter!=tList.end(); ++iter) + { + Unit* target = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid()); + if (target && target->GetHealthPercent() < 30.0f) + return target; + } + return NULL; + } + + Unit* SelectTargetWithinDist() + { + ThreatList const& m_threatlist = m_creature->getThreatManager().getThreatList(); + + if (m_threatlist.empty()) + return NULL; + + GuidList distPositive; + for (ThreatList::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + { + if (Unit* pTemp = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + //player within 10 yards + if ((pTemp->GetTypeId() == TYPEID_PLAYER && !m_creature->IsWithinDist(pTemp, 1.0f) && m_creature->IsWithinDist(pTemp, 10.0f))) + distPositive.push_back(pTemp->GetObjectGuid()); + } + } + + if (!distPositive.empty()) + { + GuidList::iterator m_uiPlayerGUID = distPositive.begin(); + advance(m_uiPlayerGUID, (rand()%distPositive.size())); + + if (Player* pTemp = m_creature->GetMap()->GetPlayer(*m_uiPlayerGUID)) + return pTemp; + } + return NULL; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_CRUSADERS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiChangeTargetTimer < uiDiff) + { + UpdateThreat(); + m_uiChangeTargetTimer = 6000; + } + else + m_uiChangeTargetTimer -= uiDiff; + + if (UpdateTimer < uiDiff) + { + UpdatePower(); + UpdateTimer = 2000; + } + else + UpdateTimer -= uiDiff; + + if (m_bIsHeroicMode) + { + if (m_uiInsygniaTimer < uiDiff) + { + RemoveCC(); + m_uiInsygniaTimer = 5*MINUTE*IN_MILLISECONDS; + } + else + m_uiInsygniaTimer -= uiDiff; + } + + } +}; + +/******************************************************************** + HEALERS +********************************************************************/ + +/************** +** Druid Resto +***************/ +struct MANGOS_DLL_DECL mob_toc_druidAI : public boss_faction_championsAI +{ + mob_toc_druidAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_HEALER) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiBarskinTimer; + uint32 m_uiNatureGraspTimer; + uint32 m_uiTranquilityTimer; + uint32 m_uiThornsTimer; + uint32 m_uiLifebloomTimer; + uint32 m_uiRejuvenationTimer; + uint32 m_uiCastHealTimer; + + void Reset() + { + m_uiBarskinTimer = 0; + m_uiNatureGraspTimer = urand(20*IN_MILLISECONDS, 80*IN_MILLISECONDS); + m_uiTranquilityTimer = 35*IN_MILLISECONDS; + m_uiThornsTimer = urand(25*IN_MILLISECONDS, 90*IN_MILLISECONDS); + m_uiLifebloomTimer = urand(2*IN_MILLISECONDS, 8*IN_MILLISECONDS); + m_uiRejuvenationTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiCastHealTimer = urand(3*IN_MILLISECONDS, 5*IN_MILLISECONDS); + + SetEquipmentSlots(false, 51799, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBarskinTimer < uiDiff) + { + if (m_creature->GetHealthPercent() < 60.0f) + { + m_creature->CastSpell(m_creature, SPELL_BARKSKIN, true); + m_uiBarskinTimer = 1*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiBarskinTimer -= uiDiff; + + if (m_uiNatureGraspTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_NATURE_GRASP); + m_uiNatureGraspTimer = 1*MINUTE*IN_MILLISECONDS; + } + else + m_uiNatureGraspTimer -= uiDiff; + + if (m_uiThornsTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_THORNS); + m_uiThornsTimer = urand(25*IN_MILLISECONDS, 90*IN_MILLISECONDS); + } + else + m_uiThornsTimer -= uiDiff; + + if (m_uiTranquilityTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TRANQUILITY) == CAST_OK) + { + m_uiTranquilityTimer = 10*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiTranquilityTimer -= uiDiff; + + if (m_uiLifebloomTimer < uiDiff) + { + if (Unit *target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_LIFEBLOOM); + m_uiLifebloomTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); + } + } + else + m_uiLifebloomTimer -= uiDiff; + + if (m_uiRejuvenationTimer < uiDiff) + { + if (Unit *target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_REJUVENATION); + m_uiRejuvenationTimer = urand(8*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + } + else + m_uiRejuvenationTimer -= uiDiff; + + if (m_uiCastHealTimer < uiDiff) + { + if (Unit *target = DoSelectLowestHpFriendly(40.0f)) + { + switch(urand(0, 1)) + { + case 0: + DoCastSpellIfCan(target, SPELL_NOURISH); + m_uiCastHealTimer = 1500; + break; + case 1: + DoCastSpellIfCan(target, SPELL_REGROWTH); + m_uiCastHealTimer = urand(2500, 15000); + break; + } + } + m_uiCastHealTimer = urand(8*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiCastHealTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/**************** +** Shaman Resto +*****************/ +struct MANGOS_DLL_DECL mob_toc_shamanAI : public boss_faction_championsAI +{ + mob_toc_shamanAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_HEALER) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiHeroismOrBloodlustTimer; + uint32 m_uiHexTimer; + uint32 m_uiEartShockTimer; + uint32 m_uiHealingWaveTimer; + uint32 m_uiRiptideTimer; + uint32 m_uiEarthShieldTimer; + + void Reset() + { + m_uiEarthShieldTimer = 0; + m_uiHexTimer = urand(10*IN_MILLISECONDS, 40*IN_MILLISECONDS); + m_uiEartShockTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiHealingWaveTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiRiptideTimer = urand(2*IN_MILLISECONDS, 8*IN_MILLISECONDS); + m_uiHeroismOrBloodlustTimer = 30*IN_MILLISECONDS; + + SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHeroismOrBloodlustTimer <= uiDiff) + { + if (m_creature->getFaction()) //Am i alliance? + { + if (!m_creature->HasAura(AURA_EXHAUSTION)) + { + DoCastSpellIfCan(m_creature, SPELL_HEROISM); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_1)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_3)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_4)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_5)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_6)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_7)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_8)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_9)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_10)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_11)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_12)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_13)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_1_14)) + pChampion->_AddAura(SPELL_HEROISM, 40000); + } + } + else + { + if (!m_creature->HasAura(AURA_SATED)) + { + DoCastSpellIfCan(m_creature, SPELL_BLOODLUST); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_1)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_3)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_4)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_5)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_6)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_7)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_8)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_9)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_10)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_11)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_12)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_13)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + + if (Creature* pChampion = m_pInstance->GetSingleCreatureFromStorage(NPC_CRUSADER_2_14)) + pChampion->_AddAura(SPELL_BLOODLUST, 40000); + } + } + m_uiHeroismOrBloodlustTimer = 10*MINUTE*IN_MILLISECONDS; + } + else + m_uiHeroismOrBloodlustTimer -= uiDiff; + + if (m_uiHexTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_HEX); + m_uiHexTimer = 45*IN_MILLISECONDS; + } + } + else + m_uiHexTimer -= uiDiff; + + if (m_uiEartShockTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_EARTH_SHOCK); + m_uiEartShockTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + } + else + m_uiEartShockTimer -= uiDiff; + + if (m_uiHealingWaveTimer < uiDiff) + { + if (Unit *target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_HEALING_WAVE); + m_uiHealingWaveTimer = urand(7*IN_MILLISECONDS, 12*IN_MILLISECONDS); + } + } + else + m_uiHealingWaveTimer -= uiDiff; + + if (m_uiRiptideTimer < uiDiff) + { + if (Unit *target = DoSelectLowestHpFriendly(40.0f)) + { + switch(urand(0, 1)) + { + case 0: + m_creature->CastSpell(target, SPELL_RIPTIDE, false); + break; + case 1: + m_creature->CastSpell(target, SPELL_SPIRIT_CLEANSE , false); + break; + } + } + m_uiRiptideTimer = urand(6*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiRiptideTimer -= uiDiff; + + if (m_uiEarthShieldTimer < uiDiff) + { + if (Unit *target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_EARTH_SHIELD); + m_uiEarthShieldTimer = urand(10*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + } + else + m_uiEarthShieldTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/*************** +** Paladin Holy +****************/ +struct MANGOS_DLL_DECL mob_toc_paladinAI : public boss_faction_championsAI +{ + mob_toc_paladinAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_HEALER) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bAttack; + + uint32 m_uiBubbleTimer; + uint32 m_uiHandOfProtectionTimer; + uint32 m_uiHolyShockTimer; + uint32 m_uiHandOfFreedomTimer; + uint32 m_uiHammerOfJusticeTimer; + uint32 m_uiHolyLightTimer; + uint32 m_uiFlashHealTimer; + + void Reset() + { + m_uiBubbleTimer = 0; + m_uiHandOfProtectionTimer = 0; + m_uiHolyShockTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiHandOfFreedomTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); + m_uiHammerOfJusticeTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiHolyLightTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiFlashHealTimer = urand(2*IN_MILLISECONDS, 10*IN_MILLISECONDS); + + SetEquipmentSlots(false, 50771, 47079, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBubbleTimer <= uiDiff) + { + if (m_creature->GetHealthPercent() <= 25.0f) + { + DoCastSpellIfCan(m_creature, SPELL_BUBBLE); + m_uiBubbleTimer = 5*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiBubbleTimer -= uiDiff; + + if (m_uiHammerOfJusticeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE); + m_uiHammerOfJusticeTimer = 40*IN_MILLISECONDS; + } + else + m_uiHammerOfJusticeTimer -= uiDiff; + + if (m_uiHandOfProtectionTimer <= uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + if (target->GetHealthPercent() <= 20.0f) + { + DoCastSpellIfCan(target, SPELL_HAND_OF_PROTECTION); + m_uiHandOfProtectionTimer = 5*MINUTE*IN_MILLISECONDS; + } + } + } + else + m_uiHandOfProtectionTimer -= uiDiff; + + if (m_uiHandOfFreedomTimer <= uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_HAND_OF_FREEDOM); + m_uiHandOfFreedomTimer = 25*IN_MILLISECONDS; + } + } + else + m_uiHandOfFreedomTimer -= uiDiff; + + if (m_uiHolyLightTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_HOLY_LIGHT); + m_uiHolyLightTimer = urand(9*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + } + else + m_uiHolyLightTimer -= uiDiff; + + if (m_uiFlashHealTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_FLASH_HEAL); + m_uiFlashHealTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + } + else + m_uiFlashHealTimer -= uiDiff; + + if (m_uiHolyShockTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_HOLY_SHOCK); + m_uiHolyShockTimer = urand(6*IN_MILLISECONDS, 16*IN_MILLISECONDS); + } + } + else + m_uiHolyShockTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/************** +** Priest Disc +***************/ +struct MANGOS_DLL_DECL mob_toc_priestAI : public boss_faction_championsAI +{ + mob_toc_priestAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_HEALER) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiPeananceTimer; + uint32 m_uiRenewTimer; + uint32 m_uiShieldTimer; + uint32 m_uiFlashHealTimer; + uint32 m_uiPsychicScreamTimer; + //uint32 m_uiManaBurnTimer; + + void Reset() + { + m_uiPsychicScreamTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiPeananceTimer = urand(3*IN_MILLISECONDS, 12*IN_MILLISECONDS); + m_uiRenewTimer = urand(2*IN_MILLISECONDS, 16*IN_MILLISECONDS); + m_uiShieldTimer = 0; + m_uiFlashHealTimer = urand(6*IN_MILLISECONDS, 10*IN_MILLISECONDS); + //m_uiManaBurnTimer = urand(6*IN_MILLISECONDS, 16*IN_MILLISECONDS); + + SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPeananceTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + if (DoCastSpellIfCan(target, SPELL_PEANANCE) == CAST_OK) + { + m_uiPeananceTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + } + } + else + m_uiPeananceTimer -= uiDiff; + + if (m_uiRenewTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_RENEW); + m_uiRenewTimer = urand(10*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + } + else + m_uiRenewTimer -= uiDiff; + + if (m_uiShieldTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_SHIELD); + m_uiShieldTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + } + else + m_uiShieldTimer -= uiDiff; + + if (m_uiFlashHealTimer < uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + DoCastSpellIfCan(target, SPELL_FLASH_HEAL_P); + m_uiFlashHealTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + } + else + m_uiFlashHealTimer -= uiDiff; + + if (m_uiPsychicScreamTimer < uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_DISPEL, true); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHIC_SCREAM); + m_uiPsychicScreamTimer = 30*IN_MILLISECONDS; + } + else + m_uiPsychicScreamTimer -= uiDiff; + + /*if(m_uiManaBurnTimer < uiDiff) + { + if (Unit* pTarget = SelectEnemyTargetWithinMana()) + { + DoCastSpellIfCan(pTarget, SPELL_MANA_BURN); + m_uiManaBurnTimer = urand(6000, 15000); + } + }else m_uiManaBurnTimer -= uiDiff;*/ + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/**************************************************** + Ranged +*****************************************************/ + +/********************* +** Priest Shadow +**********************/ +struct MANGOS_DLL_DECL mob_toc_shadow_priestAI : public boss_faction_championsAI +{ + mob_toc_shadow_priestAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_RANGED) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiDispersionTimer; + uint32 m_uiBlastTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiHorrorTimer; + uint32 m_uiFearTimer; + uint32 m_uiDispelTimer; + uint32 m_uiTouchTimer; + uint32 m_uiMindFlayTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiDispersionTimer = 0; + m_uiBlastTimer = urand(1*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiHorrorTimer = urand(3*IN_MILLISECONDS, 30*IN_MILLISECONDS); + m_uiFearTimer = urand(4*IN_MILLISECONDS, 19*IN_MILLISECONDS); + m_uiDispelTimer = urand(8*IN_MILLISECONDS, 11*IN_MILLISECONDS); + m_uiTouchTimer = urand(6*IN_MILLISECONDS, 18*IN_MILLISECONDS); + m_uiMindFlayTimer = urand(7*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiSilenceTimer = urand(9*IN_MILLISECONDS, 25*IN_MILLISECONDS); + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 50040, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_MIND_BLAST, false); + m_creature->CastSpell(target, SPELL_MIND_FLAY, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiDispersionTimer < uiDiff) + { + if (m_creature->GetHealthPercent() <= 20.0f) + { + m_creature->CastSpell(m_creature, SPELL_DISPERSION, true); + m_uiDispersionTimer = 90*IN_MILLISECONDS; + } + } + else + m_uiDispersionTimer -= uiDiff; + + if (m_uiHorrorTimer < uiDiff) + { + if (Unit* target = SelectTargetWithinDist()) + { + DoCastSpellIfCan(target, SPELL_HORROR); + m_uiHorrorTimer = 2*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiHorrorTimer -= uiDiff; + + if (m_uiFearTimer < uiDiff) + { + if (SelectTargetWithinDist()) + { + DoCastSpellIfCan(m_creature, SPELL_PSYCHIC_SCREAM); + m_uiFearTimer = urand(20*IN_MILLISECONDS, 35*IN_MILLISECONDS); + } + } + else + m_uiFearTimer -= uiDiff; + + if (m_uiDispelTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISPEL); + m_uiDispelTimer = urand(2*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + else + m_uiDispelTimer -= uiDiff; + + if (m_uiTouchTimer < uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_SW_PAIN, true); + m_creature->CastSpell(m_creature->getVictim(), SPELL_VAMPIRIC_TOUCH, false); + m_uiTouchTimer = urand(5*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + else + m_uiTouchTimer -= uiDiff; + + if (m_uiBlastTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIND_BLAST); + m_uiBlastTimer = urand(8*IN_MILLISECONDS, 16*IN_MILLISECONDS); + } + else + m_uiBlastTimer -= uiDiff; + + if (m_uiMindFlayTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIND_FLAY); + m_uiMindFlayTimer = urand(9*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiMindFlayTimer -= uiDiff; + + if (m_uiSilenceTimer < uiDiff) + { + if (Unit *target = SelectEnemyTargetWithinMana()) + { + DoCastSpellIfCan(target, SPELL_SILENCE); + m_uiSilenceTimer = 45*IN_MILLISECONDS; + } + } + else + m_uiSilenceTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + + +/************ +** Warlock +*************/ +struct MANGOS_DLL_DECL mob_toc_warlockAI : public boss_faction_championsAI +{ + mob_toc_warlockAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_RANGED) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiHelfireTimer; + uint32 m_uiFearTimer; + uint32 m_uiUnstableTimer; + uint32 m_uiSearingPainTimer; + uint32 m_uiCoruptionTimer; + uint32 m_uiExhaustTimer; + uint32 m_uiAgonyTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiSummonTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiHelfireTimer = urand(30*IN_MILLISECONDS, 48*IN_MILLISECONDS); + m_uiFearTimer = urand(15*IN_MILLISECONDS, 22*IN_MILLISECONDS); + m_uiUnstableTimer = urand(9*IN_MILLISECONDS, 18*IN_MILLISECONDS); + m_uiSearingPainTimer = urand(5*IN_MILLISECONDS, 9*IN_MILLISECONDS); + m_uiCoruptionTimer = urand(2*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiExhaustTimer = urand(1*IN_MILLISECONDS, 13*IN_MILLISECONDS); + m_uiAgonyTimer = urand(3*IN_MILLISECONDS, 12*IN_MILLISECONDS); + m_uiShadowBoltTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiSummonTimer = 0; + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_FEAR, false); + m_creature->CastSpell(target, SPELL_SHADOW_BOLT, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiHelfireTimer < uiDiff) + { + if (Unit *target = SelectTargetWithinDist()) + { + DoCastSpellIfCan(m_creature, SPELL_HELLFIRE); + m_uiHelfireTimer = 45*IN_MILLISECONDS; + } + } + else + m_uiHelfireTimer -= uiDiff; + + if (m_uiCoruptionTimer < uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_UNSTABLE, false); + m_creature->CastSpell(m_creature->getVictim(), SPELL_CURSE_OF_AGONY, true); + m_creature->CastSpell(m_creature->getVictim(), SPELL_CURSE_OF_EXHAUSTION, true); + m_creature->CastSpell(m_creature->getVictim(), SPELL_CORRUPTION, true); + m_uiCoruptionTimer = urand(8*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiCoruptionTimer -= uiDiff; + + if (m_uiSearingPainTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SEARING_PAIN); + m_uiSearingPainTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + else + m_uiSearingPainTimer -= uiDiff; + + if (m_uiFearTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEAR); + m_uiFearTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + else + m_uiFearTimer -= uiDiff; + + if (m_uiShadowBoltTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT); + m_uiShadowBoltTimer = urand(4*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + else + m_uiShadowBoltTimer -= uiDiff; + + if (m_uiSummonTimer < uiDiff) + { + m_creature->SummonCreature(NPC_FELHUNTER, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0); + m_uiSummonTimer = 10*MINUTE*IN_MILLISECONDS; + } + else + m_uiSummonTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/******** +** Mage +*********/ +struct MANGOS_DLL_DECL mob_toc_mageAI : public boss_faction_championsAI +{ + mob_toc_mageAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_RANGED) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiBarrageTimer; + uint32 m_uiBlastTimer; + uint32 m_uiExplosionTimer; + uint32 m_uiCounterSpellTimer; + uint32 m_uiNovaTimer; + uint32 m_uiBlinkTimer; + uint32 m_uiPolymorphTimer; + uint32 m_uiIceBlockTimer; + uint32 m_uiFrostboltTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiBarrageTimer = urand(2*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiBlastTimer = urand(8*IN_MILLISECONDS, 19*IN_MILLISECONDS); + m_uiExplosionTimer = urand(10*IN_MILLISECONDS, 18*IN_MILLISECONDS); + m_uiCounterSpellTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + m_uiBlinkTimer = urand(7*IN_MILLISECONDS, 12*IN_MILLISECONDS); + m_uiIceBlockTimer = 0; + m_uiPolymorphTimer = urand(2*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiFrostboltTimer = urand(1*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 47524, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_CS, false); + m_creature->CastSpell(target, SPELL_BARRAGE, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiBarrageTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_BARRAGE); + m_uiBarrageTimer = urand(4*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + else + m_uiBarrageTimer -= uiDiff; + + if (m_uiBlastTimer < uiDiff) + { + for (uint32 i = 1; i < 3; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_BLAST); + m_uiBlastTimer = urand(4*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + } + } + else + m_uiBlastTimer -= uiDiff; + + if (m_uiExplosionTimer < uiDiff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 10.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_EXPLOSION); + m_uiExplosionTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + } + else + m_uiExplosionTimer -= uiDiff; + + if (m_uiBlinkTimer < uiDiff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 5.0f)) + { + m_creature->CastSpell(m_creature, SPELL_FROST_NOVA, true); + m_creature->CastSpell(m_creature, SPELL_BLINK, true); + m_uiBlinkTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); + } + } + else + m_uiBlinkTimer -= uiDiff; + + if (m_uiCounterSpellTimer < uiDiff) + { + if (Unit* pTarget = SelectEnemyTargetWithinMana()) + { + DoCastSpellIfCan(pTarget, SPELL_CS); + m_uiCounterSpellTimer = 24*IN_MILLISECONDS; + } + } + else + m_uiCounterSpellTimer -= uiDiff; + + if (m_uiFrostboltTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROSTBOLT); + m_uiFrostboltTimer = urand(3*IN_MILLISECONDS, 8*IN_MILLISECONDS); + } + else + m_uiFrostboltTimer -= uiDiff; + + if (m_uiIceBlockTimer < uiDiff) + { + if (m_creature->GetHealthPercent() <= 20.0f) + { + m_creature->CastSpell(m_creature, SPELL_ICE_BLOCK, true); + m_uiIceBlockTimer = 3*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiIceBlockTimer -= uiDiff; + + if (m_uiPolymorphTimer <= uiDiff) + { + if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_POLY); + m_uiPolymorphTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + } + else + m_uiPolymorphTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/********** +** Hunter +***********/ +struct MANGOS_DLL_DECL mob_toc_hunterAI : public boss_faction_championsAI +{ + mob_toc_hunterAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_RANGED) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiAimedShotTimer; + uint32 m_uiDeterenceTimer; + uint32 m_uiLeapTimer; + uint32 m_uiExplosivShotTimer; + uint32 m_uiFrostTrapTimer; + uint32 m_uiSteadyShotTimer; + uint32 m_uiWingClipTimer; + uint32 m_uiWyvernStingTimer; + uint32 m_uiSummonTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiAimedShotTimer = urand(2*IN_MILLISECONDS, 5*IN_MILLISECONDS); + m_uiDeterenceTimer = 0; + m_uiLeapTimer = urand(25*IN_MILLISECONDS, 45*IN_MILLISECONDS); + m_uiExplosivShotTimer = urand(4*IN_MILLISECONDS, 6*IN_MILLISECONDS); + m_uiFrostTrapTimer = urand(15*IN_MILLISECONDS, 8*IN_MILLISECONDS); + m_uiSteadyShotTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiWingClipTimer = urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS); + m_uiWyvernStingTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); + m_uiSummonTimer = 0; + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 47156, EQUIP_NO_CHANGE, 48711); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_EXPLOSIVE_SHOT, false); + m_creature->CastSpell(target, SPELL_AIMED_SHOT, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS;; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiAimedShotTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_AIMED_SHOT); + m_uiAimedShotTimer = urand(7*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + } + else + m_uiAimedShotTimer -= uiDiff; + + if (m_uiDeterenceTimer < uiDiff) + { + if (m_creature->GetHealthPercent() <= 20.0f) + { + m_creature->CastSpell(m_creature, SPELL_DETERENCE, true); + m_uiDeterenceTimer = 90*IN_MILLISECONDS; + } + } + else + m_uiDeterenceTimer -= uiDiff; + + if (m_uiLeapTimer < uiDiff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 5.0f)) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_WING_CLIP, true); + m_creature->CastSpell(m_creature, SPELL_DISENGAGE, true); + m_uiLeapTimer = urand(35*IN_MILLISECONDS, 45*IN_MILLISECONDS); + } + } + else + m_uiLeapTimer -= uiDiff; + + if (m_uiExplosivShotTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_EXPLOSIVE_SHOT); + m_uiExplosivShotTimer = urand(4*IN_MILLISECONDS, 8*IN_MILLISECONDS); + } + else + m_uiExplosivShotTimer -= uiDiff; + + if (m_uiSteadyShotTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_STEADY_SHOT); + m_uiSteadyShotTimer = urand(3*IN_MILLISECONDS, 12*IN_MILLISECONDS); + } + else + m_uiSteadyShotTimer -= uiDiff; + + if (m_uiFrostTrapTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_FROST_TRAP); + m_uiFrostTrapTimer = 1*MINUTE*IN_MILLISECONDS; + } + else + m_uiFrostTrapTimer -= uiDiff; + + if (m_uiWyvernStingTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WYVERN_STING); + m_uiWyvernStingTimer = 2*MINUTE*IN_MILLISECONDS; + } + else + m_uiWyvernStingTimer -= uiDiff; + + if (m_uiSummonTimer < uiDiff) + { + m_creature->SummonCreature(NPC_CAT, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0); + m_uiSummonTimer = 10*MINUTE*IN_MILLISECONDS; + } + else + m_uiSummonTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + + + +/***************** +** Druid Balance +******************/ +struct MANGOS_DLL_DECL mob_toc_boomkinAI : public boss_faction_championsAI +{ + mob_toc_boomkinAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_RANGED) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiCycloneTimer; + uint32 m_uiFearieFeralTimer; + uint32 m_uiForcedTimer; + uint32 m_uiSpellTimer; + uint32 m_uiMonfireTimer; + uint32 m_uiStarfireTimer; + uint32 m_uiWrathTimer; + uint32 m_uiRootsTimer; + uint32 m_uiBarkskinTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiCycloneTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + m_uiFearieFeralTimer = 0; + m_uiForcedTimer = urand(35*IN_MILLISECONDS, 45*IN_MILLISECONDS); + m_uiSpellTimer = urand(6*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiStarfireTimer = urand(8*IN_MILLISECONDS, 19*IN_MILLISECONDS); + m_uiWrathTimer = urand(3*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiBarkskinTimer = 0; + m_uiRootsTimer = urand(10*IN_MILLISECONDS, 18*IN_MILLISECONDS); + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 50966, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_WRATH, false); + m_creature->CastSpell(target, SPELL_MOONFIRE, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiBarkskinTimer < uiDiff) + { + if (m_creature->GetHealthPercent() <= 50.0f) + { + m_creature->CastSpell(m_creature, SPELL_BARKSKIN, true); + m_uiBarkskinTimer = 1*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiBarkskinTimer -= uiDiff; + + if (m_uiCycloneTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + DoCastSpellIfCan(pTarget, SPELL_CYCLONE); + m_uiCycloneTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + } + else + m_uiCycloneTimer -= uiDiff; + + if (m_uiFearieFeralTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEARIE); + m_uiFearieFeralTimer = urand(25*IN_MILLISECONDS, 60*IN_MILLISECONDS); + } + else + m_uiFearieFeralTimer -= uiDiff; + + if (m_uiForcedTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FORCED_OF_NATURE); + m_uiForcedTimer = 90*IN_MILLISECONDS; + } + else + m_uiForcedTimer -= uiDiff; + + if (m_uiSpellTimer < uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_MOONFIRE, true); + m_creature->CastSpell(m_creature->getVictim(), SPELL_SWARM, true); + m_uiSpellTimer = urand(10*IN_MILLISECONDS, 20*IN_MILLISECONDS); + } + else + m_uiSpellTimer -= uiDiff; + + if (m_uiStarfireTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_STARFIRE); + m_uiStarfireTimer = urand(8*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + else + m_uiStarfireTimer -= uiDiff; + + if (m_uiWrathTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WRATH); + m_uiWrathTimer = urand(4*IN_MILLISECONDS, 8*IN_MILLISECONDS); + } + else + m_uiWrathTimer -= uiDiff; + + if (m_uiRootsTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_ROOTS_B); + m_uiRootsTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + else + m_uiRootsTimer -= uiDiff; + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/******************************************************************** + MELEE +********************************************************************/ + +/*********** +** Warrior +************/ +struct MANGOS_DLL_DECL mob_toc_warriorAI : public boss_faction_championsAI +{ + mob_toc_warriorAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiBladestormTimer; + uint32 m_uiIntimidatingShoutTimer; + uint32 m_uiMortalStrikeTimer; + uint32 m_uiSunderArmorTimer; + uint32 m_uiChargeTimer; + uint32 m_uiRetaliationTimer; + uint32 m_uiOverpowerTimer; + uint32 m_uiShatteringThrowTimer; + uint32 m_uiDisarmTimer; + uint32 m_uiRemoveBubleTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiBladestormTimer = urand(35*IN_MILLISECONDS, 45*IN_MILLISECONDS); + m_uiChargeTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + m_uiIntimidatingShoutTimer = urand(25*IN_MILLISECONDS, 35*IN_MILLISECONDS); + m_uiMortalStrikeTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiSunderArmorTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + m_uiRetaliationTimer = urand(45*IN_MILLISECONDS, 55*IN_MILLISECONDS); + m_uiOverpowerTimer = urand(8*IN_MILLISECONDS, 8*IN_MILLISECONDS); + m_uiShatteringThrowTimer = urand(50*IN_MILLISECONDS, 55*IN_MILLISECONDS); + m_uiDisarmTimer = urand(15*IN_MILLISECONDS, 35*IN_MILLISECONDS); + m_uiRemoveBubleTimer = 0; + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 47427, 46964, EQUIP_NO_CHANGE); + } + + // Its not good idea + Unit* SelectPlayerWithDivineShield() + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + ThreatList::const_iterator iter; + for (iter = tList.begin(); iter!=tList.end(); ++iter) + { + Unit* target = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid()); + if (target && target->HasAura(SPELL_DIVINE_SHIELD)) + return target; + } + return NULL; + } + + // Its not good idea + Unit* SelectPlayerWithIceBlock() + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + ThreatList::const_iterator iter; + for (iter = tList.begin(); iter!=tList.end(); ++iter) + { + Unit* target = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid()); + if (target && target->HasAura(SPELL_ICE_BLOCK)) + return target; + } + return NULL; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_INTIMIDATING_SHOUT, false); + m_creature->CastSpell(target, SPELL_BLADESTORM, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + // Its bad solution but work + if (m_uiRemoveBubleTimer < uiDiff) + { + if (Unit *target = SelectPlayerWithDivineShield()) + { + DoCastSpellIfCan(target, SPELL_SHATTERING_THROW); + + if (target->HasAura(SPELL_SHATTERING_THROW)) + { + target->RemoveAurasDueToSpell(SPELL_DIVINE_SHIELD); + } + } + if (Unit *target = SelectPlayerWithIceBlock()) + { + DoCastSpellIfCan(target, SPELL_SHATTERING_THROW); + + if (target->HasAura(SPELL_SHATTERING_THROW)) + { + target->RemoveAurasDueToSpell(SPELL_ICE_BLOCK); + } + } + m_uiRemoveBubleTimer = 10*IN_MILLISECONDS; + } + else + m_uiRemoveBubleTimer -= uiDiff; + + if (m_uiBladestormTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLADESTORM); + m_uiBladestormTimer = 90*IN_MILLISECONDS; + } + else + m_uiBladestormTimer -= uiDiff; + + if (m_uiChargeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_CHARGE); + m_uiChargeTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); + } + } + else + m_uiChargeTimer -= uiDiff; + + if (m_uiIntimidatingShoutTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_INTIMIDATING_SHOUT); + m_uiIntimidatingShoutTimer = 2*MINUTE*IN_MILLISECONDS; + } + else + m_uiIntimidatingShoutTimer -= uiDiff; + + if (m_uiMortalStrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + m_uiMortalStrikeTimer = urand(10*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiMortalStrikeTimer -= uiDiff; + + if (m_uiSunderArmorTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR); + m_uiSunderArmorTimer = urand(10*IN_MILLISECONDS, 14*IN_MILLISECONDS); + } + else + m_uiSunderArmorTimer -= uiDiff; + + if (m_uiRetaliationTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_RETALIATION); + m_uiRetaliationTimer = 5*MINUTE*IN_MILLISECONDS; + } + else + m_uiRetaliationTimer -= uiDiff; + + if (m_uiOverpowerTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_OVERPOWER); + m_uiOverpowerTimer = urand(8*IN_MILLISECONDS, 12*IN_MILLISECONDS); + } + else + m_uiOverpowerTimer -= uiDiff; + + if (m_uiDisarmTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISARM); + m_uiDisarmTimer = 40*IN_MILLISECONDS; + } + else + m_uiDisarmTimer -= uiDiff; + + if (m_uiShatteringThrowTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_SHATTERING_THROW); + m_uiShatteringThrowTimer = 5*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiShatteringThrowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/******* +** DK +********/ +struct MANGOS_DLL_DECL mob_toc_dkAI : public boss_faction_championsAI +{ + mob_toc_dkAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiIceboundFortitudeTimer; + uint32 m_uiChainsOfIceTimer; + uint32 m_uiDeathCoilTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiFrostStrikeTimer; + uint32 m_uiIcyTouchTimer; + uint32 m_uiDeathGripTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiChainsOfIceTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiDeathCoilTimer = urand(8*IN_MILLISECONDS, 12*IN_MILLISECONDS); + m_uiSilenceTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); + m_uiFrostStrikeTimer = urand(7*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiIcyTouchTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiDeathGripTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); + m_uiIceboundFortitudeTimer = 0; + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 47518, 51021, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_CHAINS, false); + m_creature->CastSpell(target, SPELL_DEATH_COLI, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiIceboundFortitudeTimer < uiDiff) + { + if (m_creature->GetHealthPercent() < 50.0f) + { + m_creature->CastSpell(m_creature, SPELL_ICEBOUND, true); + m_uiIceboundFortitudeTimer = 2*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiIceboundFortitudeTimer -= uiDiff; + + if (m_uiChainsOfIceTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_CHAINS); + m_uiChainsOfIceTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); + } + } + else + m_uiChainsOfIceTimer -= uiDiff; + + if (m_uiDeathCoilTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_COLI); + m_uiDeathCoilTimer = urand(8*IN_MILLISECONDS, 14*IN_MILLISECONDS); + } + else + m_uiDeathCoilTimer -= uiDiff; + + if (m_uiSilenceTimer < uiDiff) + { + if (Unit *target = SelectEnemyTargetWithinMana()) + { + DoCastSpellIfCan(target, SPELL_STRANGULATE); + m_uiSilenceTimer = 2*IN_MILLISECONDS; + } + } + else + m_uiSilenceTimer -= uiDiff; + + if (m_uiFrostStrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_STRIKE); + m_uiFrostStrikeTimer = urand(8*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiFrostStrikeTimer -= uiDiff; + + if (m_uiIcyTouchTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICE_TOUCH); + m_uiIcyTouchTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + else + m_uiIcyTouchTimer -= uiDiff; + + if (m_uiDeathGripTimer <= uiDiff) + { + if (m_creature->IsInRange(m_creature->getVictim(), 10.0f, 30.0f)) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_GRIP); + m_creature->getVictim()->NearTeleportTo(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0.0f); + m_uiDeathGripTimer = 35*IN_MILLISECONDS; + } + } + else + m_uiDeathGripTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/********* +** Rogue +**********/ +struct MANGOS_DLL_DECL mob_toc_rogueAI : public boss_faction_championsAI +{ + mob_toc_rogueAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiFanOfKnivesTimer; + uint32 m_uiHemorrhageTimer; + uint32 m_uiEviscerateTimer; + uint32 m_uiShadowstepTimer; + uint32 m_uiBlindTimer; + uint32 m_uiCloakTimer; + uint32 m_uiBladeFlurryTimer; + uint32 m_uiKillPlayerTimer; + uint32 m_uiWoundPoisonTimer; + + void Reset() + { + m_uiFanOfKnivesTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiHemorrhageTimer = 0; + m_uiEviscerateTimer = urand(15*IN_MILLISECONDS, 20*IN_MILLISECONDS); + m_uiShadowstepTimer = urand(10*IN_MILLISECONDS, 80*IN_MILLISECONDS); + m_uiBlindTimer = urand(7*IN_MILLISECONDS, 8*IN_MILLISECONDS); + m_uiCloakTimer = 0; + m_uiBladeFlurryTimer = urand(12*IN_MILLISECONDS, 120*IN_MILLISECONDS); + m_uiWoundPoisonTimer = urand(2*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 47422, 49982, EQUIP_NO_CHANGE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_SHADOWSTEP, false); + m_creature->CastSpell(target, SPELL_EVISCERATE, true); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + //Its not blizzlike but work. + if (m_uiWoundPoisonTimer < uiDiff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 3.0f)) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WOUND_POISON); + m_uiWoundPoisonTimer = urand(10*IN_MILLISECONDS, 16*IN_MILLISECONDS); + } + } + else + m_uiWoundPoisonTimer -= uiDiff; + + if (m_uiFanOfKnivesTimer <= uiDiff) + { + if (Unit *target = SelectTargetWithinDist()) + { + DoCastSpellIfCan(target, SPELL_FAN_OF_KNIVES); + m_uiFanOfKnivesTimer = urand(16*IN_MILLISECONDS, 20*IN_MILLISECONDS); + } + } + else + m_uiFanOfKnivesTimer -= uiDiff; + + if (m_uiHemorrhageTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEMORRHAGE); + m_uiHemorrhageTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + else + m_uiHemorrhageTimer -= uiDiff; + + if (m_uiEviscerateTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_EVISCERATE); + m_uiEviscerateTimer = urand(20*IN_MILLISECONDS, 35*IN_MILLISECONDS); + } + else + m_uiEviscerateTimer -= uiDiff; + + if (m_uiShadowstepTimer <= uiDiff) + { + if (m_creature->IsInRange(m_creature->getVictim(), 10.0f, 40.0f)) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWSTEP); + m_uiShadowstepTimer = 40*IN_MILLISECONDS; + } + } + else + m_uiShadowstepTimer -= uiDiff; + + if (m_uiBlindTimer <= uiDiff) + { + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (Unit *target = SelectTargetWithinDist()) + { + DoCastSpellIfCan(target, SPELL_BLIND); + m_uiBlindTimer = 2*MINUTE*IN_MILLISECONDS; + } + } + } + else + m_uiBlindTimer -= uiDiff; + + if (m_uiCloakTimer <= uiDiff) + { + if (m_creature->GetHealthPercent() < 50.0f) + { + DoCastSpellIfCan(m_creature, SPELL_CLOAK); + m_uiCloakTimer = 90*IN_MILLISECONDS; + } + } + else + m_uiCloakTimer -= uiDiff; + + if (m_uiBladeFlurryTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_BLADE_FLURRY); + m_uiBladeFlurryTimer = 2*MINUTE*IN_MILLISECONDS; + } + else + m_uiBladeFlurryTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/************* +** Shaman En +**************/ +struct MANGOS_DLL_DECL mob_toc_enh_shamanAI : public boss_faction_championsAI +{ + mob_toc_enh_shamanAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + ScriptedInstance* m_pInstance; + + uint32 m_uiHeroismOrBloodlustTimer; + uint32 m_uiEarthShockTimer; + uint32 m_uiStormstrikeTimer; + uint32 m_uiLavaLashTimer; + uint32 m_uiTotemTimer; + uint32 m_uiSummonTotemTimer; + uint32 m_uiWindFuryTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiHeroismOrBloodlustTimer = urand(25*IN_MILLISECONDS, 60*IN_MILLISECONDS); + m_uiEarthShockTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiStormstrikeTimer = urand(9*IN_MILLISECONDS, 20*IN_MILLISECONDS); + m_uiLavaLashTimer = urand(5*IN_MILLISECONDS, 8*IN_MILLISECONDS); + m_uiWindFuryTimer = urand(5000, 15000); + m_uiKillPlayerTimer = 0; + m_uiSummonTotemTimer = 0; + + SetEquipmentSlots(false, 51803, 48013, EQUIP_NO_CHANGE); + } + + void Totems() + { + switch(urand(0, 1)) + { + case 0: + m_creature->CastSpell(m_creature, SPELL_TOTEM_GROUND, false); + break; + case 1: + m_creature->CastSpell(m_creature, SPELL_TOTEM_TREMOR, false); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_STORMSTRIKE, false); + m_creature->CastSpell(target, SPELL_LAVA_LASH, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiHeroismOrBloodlustTimer <= uiDiff) + { + if (m_creature->getFaction()) //Am i alliance? + { + if (!m_creature->HasAura(AURA_EXHAUSTION)) + DoCastSpellIfCan(m_creature, SPELL_HEROISM); + } + else + { + if (!m_creature->HasAura(AURA_SATED)) + DoCastSpellIfCan(m_creature, SPELL_BLOODLUST); + } + m_uiHeroismOrBloodlustTimer = 10*MINUTE*IN_MILLISECONDS; + } + else + m_uiHeroismOrBloodlustTimer -= uiDiff; + + if (m_uiEarthShockTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_EARTH_SHOCK); + m_uiEarthShockTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + else + m_uiEarthShockTimer -= uiDiff; + + if (m_uiStormstrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_STORMSTRIKE); + m_uiStormstrikeTimer = urand(14*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } + else + m_uiStormstrikeTimer -= uiDiff; + + if (m_uiLavaLashTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_LAVA_LASH); + m_uiLavaLashTimer = urand(12*IN_MILLISECONDS, 16*IN_MILLISECONDS); + } + else + m_uiLavaLashTimer -= uiDiff; + + //Its not blizzlike but work. + if (m_uiWindFuryTimer < uiDiff) + { + if (m_creature->IsWithinDist(m_creature->getVictim(), 3.0f)) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WINDFURY); + m_uiWindFuryTimer = urand(15*IN_MILLISECONDS, 25*IN_MILLISECONDS); + } + } + else + m_uiWindFuryTimer -= uiDiff; + + if (m_uiTotemTimer < uiDiff) + { + Totems(); + m_uiTotemTimer = urand(1*IN_MILLISECONDS, 3*IN_MILLISECONDS); + } + else + m_uiTotemTimer -= uiDiff; + + if (m_uiSummonTotemTimer < uiDiff) + { + m_creature->CastSpell(m_creature, SPELL_TOTEM_SEARING, true); + m_creature->CastSpell(m_creature, SPELL_TOTEM_HEAL, true); + m_creature->CastSpell(m_creature, SPELL_TOTEM_STR, true); + m_creature->CastSpell(m_creature, SPELL_TOTEM_WIND, true); + + m_uiSummonTotemTimer = urand(18*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } + else + m_uiSummonTotemTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/**************** +** Paladyn Retri +*****************/ +struct MANGOS_DLL_DECL mob_toc_retro_paladinAI : public boss_faction_championsAI +{ + mob_toc_retro_paladinAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiRepeteanceTimer; + uint32 m_uiCrusaderStrikeTimer; + uint32 m_uiAvengingWrathTimer; + uint32 m_uiDivineShieldTimer; + uint32 m_uiDivineStormTimer; + uint32 m_uiJudgementOfCommandTimer; + uint32 m_uiHammerOfJusticeTimer; + uint32 m_uiHandOfProtectionTimer; + uint32 m_uiKillPlayerTimer; + + void Reset() + { + m_uiRepeteanceTimer = 30*IN_MILLISECONDS; + m_uiCrusaderStrikeTimer = urand(6*IN_MILLISECONDS, 18*IN_MILLISECONDS); + m_uiAvengingWrathTimer = urand(35*IN_MILLISECONDS, 40*IN_MILLISECONDS); + m_uiDivineShieldTimer = urand(0*IN_MILLISECONDS, 360*IN_MILLISECONDS); + m_uiDivineStormTimer = urand(9*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiJudgementOfCommandTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiHammerOfJusticeTimer = urand(5*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiHandOfProtectionTimer = 0; + m_uiKillPlayerTimer = 0; + + SetEquipmentSlots(false, 47519, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + DoCastSpellIfCan(m_creature, SPELL_SEAL_COMAND); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiKillPlayerTimer < uiDiff) + { + if (Unit *target = KillPlayer()) + { + m_creature->CastSpell(target, SPELL_STRIKE, false); + m_creature->CastSpell(target, SPELL_STORM, false); + m_uiKillPlayerTimer = 10*IN_MILLISECONDS; + } + } + else + m_uiKillPlayerTimer -= uiDiff; + + if (m_uiRepeteanceTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCastSpellIfCan(pTarget, SPELL_REPENTANCE); + m_uiRepeteanceTimer = 1*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiRepeteanceTimer -= uiDiff; + + if (m_uiHammerOfJusticeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE); + m_uiHammerOfJusticeTimer = 35*IN_MILLISECONDS; + } + else + m_uiHammerOfJusticeTimer -= uiDiff; + + if (m_uiHandOfProtectionTimer <= uiDiff) + { + if (Unit* target = DoSelectLowestHpFriendly(40.0f)) + { + if (target->GetHealthPercent() <= 20.0f) + { + DoCastSpellIfCan(target, SPELL_HAND_OF_PROTECTION); + m_uiHandOfProtectionTimer = 5*MINUTE*IN_MILLISECONDS; + } + } + } + else + m_uiHandOfProtectionTimer -= uiDiff; + + if (m_uiCrusaderStrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRIKE); + m_uiCrusaderStrikeTimer = urand(6*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiCrusaderStrikeTimer -= uiDiff; + + if (m_uiAvengingWrathTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_AVENGING_WRATH); + m_uiAvengingWrathTimer = 2*MINUTE*IN_MILLISECONDS; + } + else + m_uiAvengingWrathTimer -= uiDiff; + + if (m_uiDivineShieldTimer <= uiDiff) + { + if (m_creature->GetHealthPercent() < 50.0f) + { + DoCastSpellIfCan(m_creature, SPELL_DIVINE_SHIELD); + m_uiDivineShieldTimer = 5*MINUTE*IN_MILLISECONDS; + } + } + else + m_uiDivineShieldTimer -= uiDiff; + + if (m_uiDivineStormTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_STORM); + m_uiDivineStormTimer = urand(10*IN_MILLISECONDS, 18*IN_MILLISECONDS); + } + else + m_uiDivineStormTimer -= uiDiff; + + if (m_uiJudgementOfCommandTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_JUDGEMENT_COMAND); + m_uiJudgementOfCommandTimer = urand(8*IN_MILLISECONDS, 15*IN_MILLISECONDS); + } + else + m_uiJudgementOfCommandTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/**************** +** Felhunter +*****************/ +struct MANGOS_DLL_DECL mob_toc_pet_warlockAI : public boss_faction_championsAI +{ + mob_toc_pet_warlockAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + + uint32 m_uiDevourMagicTimer; + uint32 m_uiSpellLockTimer; + + void Reset() + { + m_uiDevourMagicTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + m_uiSpellLockTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_CRUSADERS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiDevourMagicTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEVOUR_MAGIC); + m_uiDevourMagicTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } + else + m_uiDevourMagicTimer -= uiDiff; + + if (m_uiSpellLockTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SPELL_LOCK); + m_uiSpellLockTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); + } + else + m_uiSpellLockTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +/******** +** Cat +*********/ +struct MANGOS_DLL_DECL mob_toc_pet_hunterAI : public boss_faction_championsAI +{ + mob_toc_pet_hunterAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE) + { + m_pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + Reset(); + } + + uint32 m_uiClawTimer; + + void Reset() + { + m_uiClawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_CRUSADERS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiClawTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLAW); + m_uiClawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + else + m_uiClawTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + boss_faction_championsAI::UpdateAI(uiDiff); + } +}; + +CreatureAI* GetAI_mob_toc_druid(Creature *pCreature) +{ + return new mob_toc_druidAI (pCreature); +} +CreatureAI* GetAI_mob_toc_shaman(Creature *pCreature) +{ + return new mob_toc_shamanAI (pCreature); +} +CreatureAI* GetAI_mob_toc_paladin(Creature *pCreature) +{ + return new mob_toc_paladinAI (pCreature); +} +CreatureAI* GetAI_mob_toc_priest(Creature *pCreature) +{ + return new mob_toc_priestAI (pCreature); +} +CreatureAI* GetAI_mob_toc_shadow_priest(Creature *pCreature) +{ + return new mob_toc_shadow_priestAI (pCreature); +} +CreatureAI* GetAI_mob_toc_warlock(Creature *pCreature) +{ + return new mob_toc_warlockAI (pCreature); +} +CreatureAI* GetAI_mob_toc_mage(Creature *pCreature) +{ + return new mob_toc_mageAI (pCreature); +} +CreatureAI* GetAI_mob_toc_hunter(Creature *pCreature) +{ + return new mob_toc_hunterAI (pCreature); +} +CreatureAI* GetAI_mob_toc_boomkin(Creature *pCreature) +{ + return new mob_toc_boomkinAI (pCreature); +} +CreatureAI* GetAI_mob_toc_warrior(Creature *pCreature) +{ + return new mob_toc_warriorAI (pCreature); +} +CreatureAI* GetAI_mob_toc_dk(Creature *pCreature) +{ + return new mob_toc_dkAI (pCreature); +} +CreatureAI* GetAI_mob_toc_rogue(Creature *pCreature) +{ + return new mob_toc_rogueAI (pCreature); +} +CreatureAI* GetAI_mob_toc_enh_shaman(Creature *pCreature) +{ + return new mob_toc_enh_shamanAI (pCreature); +} +CreatureAI* GetAI_mob_toc_retro_paladin(Creature *pCreature) +{ + return new mob_toc_retro_paladinAI (pCreature); +} +CreatureAI* GetAI_mob_toc_pet_warlock(Creature *pCreature) +{ + return new mob_toc_pet_warlockAI (pCreature); +} +CreatureAI* GetAI_mob_toc_pet_hunter(Creature *pCreature) +{ + return new mob_toc_pet_hunterAI (pCreature); +} + +void AddSC_boss_faction_champions() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "mob_toc_druid"; + newscript->GetAI = &GetAI_mob_toc_druid; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_shaman"; + newscript->GetAI = &GetAI_mob_toc_shaman; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_paladin"; + newscript->GetAI = &GetAI_mob_toc_paladin; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_priest"; + newscript->GetAI = &GetAI_mob_toc_priest; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_shadow_priest"; + newscript->GetAI = &GetAI_mob_toc_shadow_priest; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_mage"; + newscript->GetAI = &GetAI_mob_toc_mage; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_warlock"; + newscript->GetAI = &GetAI_mob_toc_warlock; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_hunter"; + newscript->GetAI = &GetAI_mob_toc_hunter; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_boomkin"; + newscript->GetAI = &GetAI_mob_toc_boomkin; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_warrior"; + newscript->GetAI = &GetAI_mob_toc_warrior; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_dk"; + newscript->GetAI = &GetAI_mob_toc_dk; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_rogue"; + newscript->GetAI = &GetAI_mob_toc_rogue; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_enh_shaman"; + newscript->GetAI = &GetAI_mob_toc_enh_shaman; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_retro_paladin"; + newscript->GetAI = &GetAI_mob_toc_retro_paladin; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_pet_warlock"; + newscript->GetAI = &GetAI_mob_toc_pet_warlock; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_toc_pet_hunter"; + newscript->GetAI = &GetAI_mob_toc_pet_hunter; + newscript->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 fc50b8c26c..6395b35e81 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -13,67 +13,265 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +// Jaraxxus - Magic aura (from start?) not fully offlike implemented. +// Legion flame visual effect not imlemented /* ScriptData SDName: trial_of_the_crusader -SD%Complete: 0 -SDComment: +SD%Complete: 80% +SDComment: by /dev/rsa SDCategory: Crusader Coliseum EndScriptData */ #include "precompiled.h" #include "trial_of_the_crusader.h" -/*###### -## boss_jaraxxus -######*/ +enum Yells +{ + SAY_AGGRO = -1649040, + SAY_DEATH = -1649043, + SAY_SLAY_1 = -1649041, + SAY_SLAY_2 = -1649042, + SAY_INFERNAL_VOLCANO = -1649080, + SAY_NETHER_PORTAL = -1649081, + SAY_SUMMON_MISTRESS = -1649046, + SAY_SUMMON_INFERNAL = -1649047, + SAY_INCINERATE_FLESH = -1649045, + //SAY_ENRAGE = -1713750, -- FixMe + + EMOTE_INCINERATE_FLESH = -1649082, +}; + +enum Equipment +{ + EQUIP_MAIN = 47266, + EQUIP_DONE = EQUIP_NO_CHANGE, +}; -enum +enum Summons { - SAY_AGGRO = -1649040, - SAY_SLAY_1 = -1649041, - SAY_SLAY_2 = -1649042, - SAY_DEATH = -1649043, - SAY_BERSERK = -1649044, - SAY_INCINERATE = -1649045, - SAY_MISTRESS = -1649046, - SAY_INFERNO = -1649047, + NPC_LEGION_FLAME = 34784, + NPC_INFERNAL_VOLCANO = 34813, + NPC_FEL_INFERNAL = 34815, + NPC_NETHER_PORTAL = 34825, + NPC_MISTRESS = 34826, }; +enum BossSpells +{ + SPELL_NETHER_POWER = 67108, + SPELL_SUMMON_VOLCAN_N = 66258, + SPELL_SUMMON_VOLCAN_H = 67902, + SPELL_SUMMON_INFERNAL_PERIODIC = 66252, + SPELL_FEL_FIREBALL = 66532, + SPELL_FEL_LIGHTING = 66528, + SPELL_INCINERATE_FLESH = 66237, + SPELL_BURNING_INFERNO = 66242, + SPELL_SUMMON_NETHER_PORTAL_N = 66269, + SPELL_SUMMON_NETHER_PORTAL_H = 67899, + SPELL_SUMMON_MISTRESS_PERIODIC = 67103, + SPELL_LEGION_FLAME = 66197, + SPELL_LEGION_FLAME_AURA = 66201, + SPELL_SHIVAN_SLASH = 67098, + SPELL_SPINNING_STRIKE = 66283, // Need core support + SPELL_MISTRESS_KISS = 67906, + SPELL_FEL_INFERNO = 67047, + SPELL_FEL_STREAK = 66494, + SPELL_WILFRED_PORTAL = 68424, + SPELL_ENRAGE = 26662, +}; + +/*###### +## boss_jaraxxus +######*/ + struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI { boss_jaraxxusAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); Reset(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; - void Reset() {} + uint32 m_uiNetherPowerTimer; + uint32 m_uiFelFireballTimer; + uint32 m_uiFelLightingTimer; + uint32 m_uiIncinerateFleshTimer; + uint32 m_uiLegionFlameTimer; + uint32 m_uiInfernalEruptionTimer; + uint32 m_uiNetherPortalTimer; + uint32 m_uiEnrageTimer; - void JustReachedHome() + std::list mistressEntryList; + + void Reset() { - if (m_pInstance) - m_pInstance->SetData(TYPE_JARAXXUS, NOT_STARTED); + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_JARAXXUS, NOT_STARTED); + + m_uiNetherPowerTimer = 0; + m_uiFelFireballTimer = 15000; + m_uiFelLightingTimer = 12000; + m_uiIncinerateFleshTimer = 20000; + m_uiLegionFlameTimer = 30000; + m_uiInfernalEruptionTimer = 80000; + m_uiNetherPortalTimer = 20000; + m_uiEnrageTimer = 600000; + + m_creature->SetRespawnDelay(DAY); + + mistressEntryList.clear(); } - void JustDied(Unit* pKiller) + void JustReachedHome() override { - if (m_pInstance) - m_pInstance->SetData(TYPE_JARAXXUS, DONE); + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_JARAXXUS, FAIL); + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + // Find required NPC as achievement criteria + mistressEntryList.clear(); + GetCreatureListWithEntryInGrid(mistressEntryList, m_creature, NPC_MISTRESS, 250.0f); + + if (mistressEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(TYPE_THREE_SIXTY_PAIN_SPIKE, false); + else + m_pInstance->SetSpecialAchievementCriteria(TYPE_THREE_SIXTY_PAIN_SPIKE, mistressEntryList.size() >= 2); + + DoScriptText(SAY_DEATH, m_creature); + m_pInstance->SetData(TYPE_JARAXXUS, DONE); + m_pInstance->SetData(TYPE_EVENT,1999); + m_pInstance->SetData(TYPE_STAGE,0); } void Aggro(Unit* pWho) { + if (!m_pInstance) + return; + + DoScriptText(SAY_AGGRO, m_creature); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->SetInCombatWithZone(); + m_pInstance->SetData(TYPE_JARAXXUS, IN_PROGRESS); } - void UpdateAI(const uint32 uiDiff) + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_SLAY_1 - urand(0, 1),m_creature,pVictim); + } + + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + m_uiEnrageTimer = 600000; + //DoScriptText(SAY_ENRAGE, m_creature); + } + } + else + m_uiEnrageTimer -= uiDiff; + + if (m_uiNetherPowerTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NETHER_POWER) == CAST_OK) + m_uiNetherPowerTimer = 30000; + } + else + m_uiNetherPowerTimer -= uiDiff; + + if (m_uiFelFireballTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, SPELL_FEL_FIREBALL) == CAST_OK) + m_uiFelFireballTimer = 12000; + } + else + m_uiFelFireballTimer -= uiDiff; + + if (m_uiFelLightingTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, SPELL_FEL_LIGHTING) == CAST_OK) + m_uiFelLightingTimer = 25000; + } + else + m_uiFelLightingTimer -= uiDiff; + + if (m_uiIncinerateFleshTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_INCINERATE_FLESH) == CAST_OK) + { + DoScriptText(SAY_INCINERATE_FLESH, m_creature); + DoScriptText(EMOTE_INCINERATE_FLESH, m_creature, pTarget); + m_uiIncinerateFleshTimer = 22000; + } + } + } + else + m_uiIncinerateFleshTimer -= uiDiff; + + if (m_uiLegionFlameTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + m_creature->CastSpell(pTarget, SPELL_LEGION_FLAME, false); + + m_uiLegionFlameTimer = 30000; + } + else + m_uiLegionFlameTimer -= uiDiff; + + if (m_uiInfernalEruptionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsHeroic ? SPELL_SUMMON_VOLCAN_H : SPELL_SUMMON_VOLCAN_N) == CAST_OK) + { + m_uiInfernalEruptionTimer = 120000; + DoScriptText(SAY_INFERNAL_VOLCANO, m_creature); + DoScriptText(SAY_SUMMON_INFERNAL, m_creature); + } + } + else + m_uiInfernalEruptionTimer -= uiDiff; + + if (m_uiNetherPortalTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsHeroic ? SPELL_SUMMON_NETHER_PORTAL_H : SPELL_SUMMON_NETHER_PORTAL_N) == CAST_OK) + { + DoScriptText(SAY_NETHER_PORTAL, m_creature); + m_uiNetherPortalTimer = 120000; + } + } + else + m_uiNetherPortalTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -83,12 +281,366 @@ CreatureAI* GetAI_boss_jaraxxus(Creature* pCreature) return new boss_jaraxxusAI(pCreature); } +struct MANGOS_DLL_DECL mob_legion_flameAI : public ScriptedAI +{ + mob_legion_flameAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_creature->_AddAura(SPELL_LEGION_FLAME_AURA); + m_creature->ForcedDespawn(60000); + m_creature->SetRespawnDelay(DAY); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + { + m_creature->RemoveAllAuras(); + m_creature->ForcedDespawn(); + } + } +}; + +CreatureAI* GetAI_mob_legion_flame(Creature* pCreature) +{ + return new mob_legion_flameAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_infernal_volcanoAI : public ScriptedAI +{ + mob_infernal_volcanoAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiSummonInfernalTimer; + + void Reset() + { + m_creature->SetInCombatWithZone(); + SetCombatMovement(false); + + m_uiSummonInfernalTimer = 12000; + + if (!m_bIsHeroic) + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_INFERNAL_PERIODIC); + } + + void JustDied(Unit* Killer) + { + m_creature->ForcedDespawn(); + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiSummonInfernalTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_INFERNAL_PERIODIC); + m_uiSummonInfernalTimer = 9000; + } + else + m_uiSummonInfernalTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_infernal_volcano(Creature* pCreature) +{ + return new mob_infernal_volcanoAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_fel_infernalAI : public ScriptedAI +{ + mob_fel_infernalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiFelInfernoTimer; + uint32 m_uiFelStreakTimer; + + void Reset() + { + m_uiFelInfernoTimer = 10000, + m_uiFelStreakTimer = 20000, + + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(DAY); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + } + + void JustDied(Unit* Killer) + { + m_creature->ForcedDespawn(5000); + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiFelInfernoTimer <= uiDiff) + { + if (Unit* pTarget= m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->CastSpell(pTarget, SPELL_FEL_INFERNO, false); + + m_uiFelInfernoTimer = 25000; + } + else + m_uiFelInfernoTimer -= uiDiff; + + if (m_uiFelStreakTimer <= uiDiff) + { + if (Unit* pTarget= m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->CastSpell(pTarget, SPELL_FEL_STREAK, false); + + m_uiFelStreakTimer = 25000; + } + else + m_uiFelStreakTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_fel_infernal(Creature* pCreature) +{ + return new mob_fel_infernalAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_nether_portalAI : public ScriptedAI +{ + mob_nether_portalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiSummonMistressTimer; + + void Reset() + { + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(DAY); + SetCombatMovement(false); + + m_uiSummonMistressTimer = 18000; + + if (!m_bIsHeroic) + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MISTRESS_PERIODIC, CAST_TRIGGERED); + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiSummonMistressTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MISTRESS_PERIODIC, CAST_TRIGGERED); + m_uiSummonMistressTimer = 9000; + } + else + m_uiSummonMistressTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_nether_portal(Creature* pCreature) +{ + return new mob_nether_portalAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_mistress_of_painAI : public ScriptedAI +{ + mob_mistress_of_painAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_uiShivanSlashTimer; + uint32 m_uiSpinningStrikeTimer; + uint32 m_uiMistressKissTimer; + + void Reset() + { + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(DAY); + + m_uiShivanSlashTimer = 10000; + m_uiSpinningStrikeTimer = 5000; + m_uiMistressKissTimer = 8000; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + } + + void JustDied(Unit* Killer) + { + m_creature->ForcedDespawn(); + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + } + + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiShivanSlashTimer <= uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_SHIVAN_SLASH, false); + m_uiShivanSlashTimer = 10000; + } + else + m_uiShivanSlashTimer -= uiDiff; + + if (m_uiSpinningStrikeTimer <= uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_SPINNING_STRIKE, false); + m_uiSpinningStrikeTimer = 10000; + } + else + m_uiSpinningStrikeTimer -= uiDiff; + + if (m_bIsHeroic) + { + if (m_uiMistressKissTimer <= uiDiff) + { + if (Unit* pTarget= m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->CastSpell(pTarget, SPELL_MISTRESS_KISS, false); + + m_uiMistressKissTimer = 10000; + } + else + m_uiMistressKissTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_mistress_of_pain(Creature* pCreature) +{ + return new mob_mistress_of_painAI(pCreature); +} + void AddSC_boss_jaraxxus() { - Script* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_jaraxxus"; + pNewScript->GetAI = &GetAI_boss_jaraxxus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_legion_flame"; + pNewScript->GetAI = &GetAI_mob_legion_flame; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_infernal_volcano"; + pNewScript->GetAI = &GetAI_mob_infernal_volcano; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_fel_infernal"; + pNewScript->GetAI = &GetAI_mob_fel_infernal; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_nether_portal"; + pNewScript->GetAI = &GetAI_mob_nether_portal; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_jaraxxus"; - newscript->GetAI = &GetAI_boss_jaraxxus; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_mistress_of_pain"; + pNewScript->GetAI = &GetAI_mob_mistress_of_pain; + pNewScript->RegisterSelf(); } 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 561aaa48af..a88d937717 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -13,49 +13,255 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +// Gormok - Firebomb not implemented, timers need correct +// Snakes - Underground phase not worked, timers need correct +// Icehowl - Trample&Crash event not implemented, timers need correct /* ScriptData -SDName: -SD%Complete: 0 -SDComment: +SDName: northrend_beasts +SD%Complete: 90% +SDComment: by /dev/rsa SDCategory: EndScriptData */ +// Snobols have to jump into players. Need core support +// Some spells have wrong target, invalid. + #include "precompiled.h" #include "trial_of_the_crusader.h" -/*###### -## boss_gormok -######*/ +enum Emotes +{ + EMOTE_SUMMON_SNOBOLD = -1649076, + EMOTE_ENRAGE = -1649077, + EMOTE_TRAMPLE = -1649078, + EMOTE_STAGGERED = -1649079, + EMOTE_CRASH = -1649039, +}; + +enum Equipment +{ + EQUIP_MAIN = 47505, + EQUIP_DONE = EQUIP_NO_CHANGE, +}; + +enum Summons +{ + NPC_SNOBOLD_VASSAL = 34800, + NPC_SLIME_POOL = 35176, + NPC_FIRE_BOMB = 34854, +}; + +enum BossSpells +{ + // Gormok + SPELL_IMPALE = 66331, + SPELL_STAGGERING_STOMP = 67648, + SPELL_RISING_ANGER = 66636, + SPELL_SNOBOLLED = 66406, + SPELL_BATTER = 66408, + SPELL_FIRE_BOMB = 66313, + SPELL_FIRE_BOMB_DOT = 66318, + SPELL_HEAD_CRACK = 66407, + + // Acidmaw & Dreadscale + SPELL_EMERGE = 66947, + SPELL_SUBMERGE = 66948, + SPELL_ENRAGE = 68335, + SPELL_ACID_SPIT = 66880, + SPELL_PARALYTIC_SPRAY = 66901, + SPELL_PARALYTIC_TOXIN = 66823, + SPELL_ACID_SPEW = 66819, + SPELL_PARALYTIC_BITE = 66824, + SPELL_SWEEP = 66794, + SPELL_FIRE_SPIT = 66796, + SPELL_MOLTEN_SPEW = 66821, + SPELL_BURNING_BITE = 66879, + SPELL_BURNING_SPRAY = 66902, + SPELL_BURNING_BILE = 66869, + SPELL_AUTO_GROW = 62559, + SPELL_SLIME_POOL = 66883, + SPELL_SLIME_POOL_AURA = 66882, + SPELL_SLIME_POOL_VISUAL = 63084, + + // Icehowl + SPELL_FEROCIOUS_BUTT = 66770, + SPELL_MASSIVE_CRASH = 66683, + SPELL_WHIRL = 67345, + SPELL_ARCTIC_BREATH = 66689, + SPELL_TRAMPLE = 66734, + SPELL_ADRENALINE = 68667, + SPELL_FROTHING_RAGE = 66759, + SPELL_STAGGERED_DAZE = 66758, +}; + +enum Models +{ + MODEL_ACIDMAW_STATIONARY = 29815, + MODEL_ACIDMAW_MOBILE = 29816, + MODEL_DREADSCALE_STATIONARY = 26935, + MODEL_DREADSCALE_MOBILE = 24564, +}; + +enum Phases +{ + // Snakes + PHASE_EMERGED = 0, + PHASE_SUBMERGED = 1, + + // Icehowl + PHASE_NORMAL = 0, + PHASE_MOVING = 1, + PHASE_TRAMPLE = 2, +}; + +enum Points +{ + POINT_CENTER = 0, + POINT_TARGET = 1, +}; struct MANGOS_DLL_DECL boss_gormokAI : public ScriptedAI { boss_gormokAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); Reset(); } ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + Unit* pFocus; + + bool m_bIsHeroic; + bool m_bIs25Man; + + uint8 SnoboldsCount; + + uint32 m_uiImpaleTimer; + uint32 m_uiStaggeringStompTimer; + uint32 m_uiSummonSnoboldTimer; + + std::list mobsGuidList; + + void Reset() + { + if (!m_pInstance) + return; + + SetEquipmentSlots(false, EQUIP_MAIN, -1, -1); + m_creature->SetRespawnDelay(7*DAY); + m_creature->SetInCombatWithZone(); + + SnoboldsCount = m_bIs25Man? 5 : 4; + + pFocus = NULL; + + m_uiImpaleTimer = urand(15000, 30000); + m_uiStaggeringStompTimer = urand(20000, 25000); + m_uiSummonSnoboldTimer = urand(20000, 30000); + + mobsGuidList.clear(); + } + + void SummonAdds() + { + if (!m_pInstance) + return; + + for (uint32 i = 0; i < SnoboldsCount; i++) + { + Unit *pTemp = m_creature->SummonCreature(NPC_SNOBOLD_VASSAL, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0); + pTemp->EnterVehicle(m_creature->GetVehicleKit(), i); + mobsGuidList.push_back(pTemp->GetObjectGuid()); + } + } + + void ThrowAdd(Unit *pTarget) + { + if (!m_pInstance || mobsGuidList.empty()) + return; + + for(std::list::iterator itr = mobsGuidList.begin(); itr != mobsGuidList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + if (pTemp->isAlive()) + { + pTemp->ExitVehicle(); + pTemp->SetInCombatWithZone(); + pTemp->AddThreat(pTarget, 10000.0f); + pTemp->AI()->AttackStart(pTarget); + mobsGuidList.remove(pTemp->GetObjectGuid()); + break; + } + } + } + } - void Reset() {} + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_DONE); + } - void JustReachedHome() + void JustReachedHome() override { - if (m_pInstance) - m_pInstance->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + + m_creature->ForcedDespawn(); } void Aggro(Unit* pWho) { - m_creature->SetInCombatWithZone(); + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS); + SummonAdds(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiImpaleTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_IMPALE) == CAST_OK) + m_uiImpaleTimer = 10000; + } + else + m_uiImpaleTimer -= uiDiff; + + if (m_uiStaggeringStompTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STAGGERING_STOMP) == CAST_OK) + m_uiStaggeringStompTimer = 20000; + } + else + m_uiStaggeringStompTimer -= uiDiff; + + if (m_uiSummonSnoboldTimer <= uiDiff && SnoboldsCount > 0) + { + DoScriptText(EMOTE_SUMMON_SNOBOLD, m_creature); + ThrowAdd(pFocus = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); + pFocus->_AddAura(SPELL_SNOBOLLED); + m_creature->_AddAura(SPELL_RISING_ANGER); + --SnoboldsCount; + m_uiSummonSnoboldTimer = 20000; + } + else + m_uiSummonSnoboldTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -65,13 +271,108 @@ CreatureAI* GetAI_boss_gormok(Creature* pCreature) return new boss_gormokAI(pCreature); } -/*###### -## boss_acidmaw -######*/ +struct MANGOS_DLL_DECL mob_snobold_vassalAI : public ScriptedAI +{ + mob_snobold_vassalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } -struct MANGOS_DLL_DECL boss_acidmawAI : public ScriptedAI + ScriptedInstance* m_pInstance; + Unit *pFocus; + + uint32 m_uiBatterTimer; + uint32 m_uiFireBombTimer; + uint32 m_uiHeadCrackTimer; + + void Reset() + { + pFocus = NULL; + + m_uiBatterTimer = 10000; + m_uiFireBombTimer = urand(10000, 20000); + m_uiHeadCrackTimer = urand(10000, 30000); + + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(DAY); + } + + void Aggro(Unit *pWho) + { + if (!m_pInstance) + return; + + pFocus = pWho; + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* pKiller) override + { + if (pFocus && pFocus->isAlive()) + pFocus->RemoveAurasDueToSpell(SPELL_SNOBOLLED); + + m_creature->ForcedDespawn(5000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == FAIL) + m_creature->ForcedDespawn(); + + if (m_uiBatterTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BATTER) == CAST_OK) + m_uiBatterTimer = 15000; + } + else + m_uiBatterTimer -= uiDiff; + + if (m_uiFireBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIRE_BOMB) == CAST_OK) + { + float x, y, z; + m_creature->GetPosition(x, y, z); + + if (Creature *pBomb = m_creature->SummonCreature(NPC_FIRE_BOMB, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 60000)) + pBomb->CastSpell(pBomb, SPELL_FIRE_BOMB_DOT, true); + } + m_uiFireBombTimer = urand(10000, 20000); + } + else + m_uiFireBombTimer -= uiDiff; + + if (m_uiHeadCrackTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEAD_CRACK) == CAST_OK) + m_uiHeadCrackTimer = urand(10000, 30000); + } + else + m_uiHeadCrackTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_snobold_vassal(Creature* pCreature) { - boss_acidmawAI(Creature* pCreature) : ScriptedAI(pCreature) + return new mob_snobold_vassalAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_fire_bombAI : public ScriptedAI +{ + mob_fire_bombAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -79,24 +380,220 @@ struct MANGOS_DLL_DECL boss_acidmawAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() {} + void Reset() + { + m_creature->SetInCombatWithZone(); + SetCombatMovement(false); + } - void JustReachedHome() + void UpdateAI(const uint32 uiDiff) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == FAIL) + m_creature->ForcedDespawn(); } +}; - void Aggro(Unit* pWho) +CreatureAI* GetAI_mob_fire_bomb(Creature* pCreature) +{ + return new mob_fire_bombAI(pCreature); +} + +struct MANGOS_DLL_DECL boss_acidmawAI : public ScriptedAI +{ + boss_acidmawAI(Creature* pCreature) : ScriptedAI(pCreature) { + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_crusader* m_pInstance; + + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + uint32 m_uiAcidSpewTimer; + uint32 m_uiParalyticBiteTimer; + uint32 m_uiAcidSpitTimer; + uint32 m_uiParalyticSprayTimer; + uint32 m_uiSweepTimer; + uint32 m_uiSlimePoolTimer; + uint32 m_uiAchievTimer; + + bool m_bIsEnraged; + bool m_bAchievFailed; + + void Reset() + { + m_uiPhaseTimer = 65000; + m_uiAcidSpewTimer = urand(10000, 20000); + m_uiParalyticBiteTimer = 15000; + m_uiAcidSpitTimer = 0; + m_uiParalyticSprayTimer = 15000; + m_uiSweepTimer = 20000; + m_uiSlimePoolTimer = 10000; + + m_uiPhase = PHASE_SUBMERGED; + + m_uiAchievTimer = 10000; + + m_bIsEnraged = false; + m_bAchievFailed = false; + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(7*DAY); + m_creature->SetDisplayId(MODEL_ACIDMAW_STATIONARY); + m_creature->SetSpeedRate(MOVE_WALK, 0); + m_creature->SetSpeedRate(MOVE_RUN, 0); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL && !m_bAchievFailed) + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ACHIEV_NOT_ONE_BUT_TWO_JORMUNGARS); + + if (Creature* pDreadscale = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE)) + { + if (!pDreadscale->isAlive()) + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_DONE); + else + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_SPECIAL); + } + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_BEASTS) == IN_PROGRESS && m_pInstance->GetData(TYPE_NORTHREND_BEASTS) != FAIL) + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + + m_creature->ForcedDespawn(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + switch (m_uiPhase) + { + case PHASE_EMERGED: + if (m_uiAcidSpewTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ACID_SPEW) == CAST_OK) + m_uiAcidSpewTimer = urand(15000, 30000); + } + else + m_uiAcidSpewTimer -= uiDiff; + + if (m_uiParalyticBiteTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PARALYTIC_BITE) == CAST_OK) + m_uiParalyticBiteTimer = urand(15000, 30000); + } + else + m_uiParalyticBiteTimer -= uiDiff; + + if (m_uiSlimePoolTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SLIME_POOL) == CAST_OK) + m_uiSlimePoolTimer = 12000; + } + else + m_uiSlimePoolTimer -= uiDiff; + + if (m_uiPhaseTimer <= uiDiff) + { + m_creature->SetDisplayId(MODEL_ACIDMAW_STATIONARY); + m_creature->SetSpeedRate(MOVE_WALK, 0); + m_creature->SetSpeedRate(MOVE_RUN, 0); + DoCastSpellIfCan(m_creature, SPELL_EMERGE); + m_uiPhase = PHASE_SUBMERGED; + m_uiPhaseTimer = 65000; + } + else + m_uiPhaseTimer -= uiDiff; + + break; + case PHASE_SUBMERGED: + if (m_uiAcidSpitTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ACID_SPIT) == CAST_OK) + m_uiAcidSpitTimer = 1200; + } + } + else + m_uiAcidSpitTimer -= uiDiff; + + if (m_uiParalyticSprayTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if(DoCastSpellIfCan(pTarget, SPELL_PARALYTIC_SPRAY, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + m_uiParalyticSprayTimer = 20000; + } + } + else + m_uiParalyticSprayTimer -= uiDiff; + + if (m_uiSweepTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SWEEP, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + m_uiSweepTimer = 20000; + m_uiAcidSpitTimer = 3000; + } + } + else + m_uiSweepTimer -= uiDiff; + + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = PHASE_EMERGED; + m_creature->RemoveAurasDueToSpell(SPELL_EMERGE); + m_creature->SetDisplayId(MODEL_ACIDMAW_MOBILE); + m_creature->SetSpeedRate(MOVE_WALK, 1); + m_creature->SetSpeedRate(MOVE_RUN, 1); + SetCombatMovement(true); + DoResetThreat(); + m_uiPhaseTimer = 65000; + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL && !m_bIsEnraged) + { + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); + m_creature->SetDisplayId(MODEL_ACIDMAW_MOBILE); + m_creature->SetSpeedRate(MOVE_WALK, 1); + m_creature->SetSpeedRate(MOVE_RUN, 1); + DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_EMERGE); + + DoScriptText(EMOTE_ENRAGE, m_creature); + + m_bIsEnraged = true; + m_uiPhase = PHASE_EMERGED; + } + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL) + { + m_uiAchievTimer -= uiDiff; + if (m_uiAchievTimer <= uiDiff) + m_bAchievFailed = true; + } + DoMeleeAttackIfReady(); } }; @@ -106,38 +603,197 @@ CreatureAI* GetAI_boss_acidmaw(Creature* pCreature) return new boss_acidmawAI(pCreature); } -/*###### -## boss_dreadscale -######*/ - struct MANGOS_DLL_DECL boss_dreadscaleAI : public ScriptedAI { boss_dreadscaleAI(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_uiPhase; + uint32 m_uiPhaseTimer; + uint32 m_uiBurningBiteTimer; + uint32 m_uiMoltenSpewTimer; + uint32 m_uiFireSpitTimer; + uint32 m_uiBurningSprayTimer; + uint32 m_uiSweepTimer; + uint32 m_uiSlimePoolTimer; + uint32 m_uiAchievTimer; - void Reset() {} + bool m_bIsEnraged; + bool m_bAchievFailed; - void JustReachedHome() + void Reset() { - if (m_pInstance) - m_pInstance->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); + m_uiPhaseTimer = 65000; + m_uiBurningBiteTimer = urand(10000, 20000); + m_uiMoltenSpewTimer = urand(15000, 30000); + m_uiFireSpitTimer = 1000; + m_uiBurningSprayTimer = 15000; + m_uiSweepTimer = 20000; + m_uiSlimePoolTimer = 10000; + m_uiAchievTimer = 10000; + + m_uiPhase = PHASE_EMERGED; + + m_bIsEnraged = false; + m_bAchievFailed = false; + + m_creature->SetInCombatWithZone(); + m_creature->SetRespawnDelay(7*DAY); + m_creature->SetDisplayId(MODEL_DREADSCALE_MOBILE); + m_creature->SetSpeedRate(MOVE_WALK, 1); + m_creature->SetSpeedRate(MOVE_RUN, 1); } - void Aggro(Unit* pWho) + void JustDied(Unit* pKiller) override { - m_creature->SetInCombatWithZone(); + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL && !m_bAchievFailed) + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ACHIEV_NOT_ONE_BUT_TWO_JORMUNGARS); + + if (Creature *pSister = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW)) + { + if (!pSister->isAlive()) + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_DONE); + else + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_SPECIAL); + } + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_BEASTS) == IN_PROGRESS && m_pInstance->GetData(TYPE_NORTHREND_BEASTS) != FAIL) + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + + m_creature->ForcedDespawn(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + switch (m_uiPhase) + { + case PHASE_EMERGED: + if (m_uiBurningBiteTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BURNING_BITE) == CAST_OK) + m_uiBurningBiteTimer = urand(15000, 30000); + } + else + m_uiBurningBiteTimer -= uiDiff; + + if (m_uiMoltenSpewTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MOLTEN_SPEW) == CAST_OK) + m_uiMoltenSpewTimer = urand(15000, 30000); + } + else + m_uiMoltenSpewTimer -= uiDiff; + + if (m_uiSlimePoolTimer <= uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_SLIME_POOL) == CAST_OK) + m_uiSlimePoolTimer = 12000; + } + else + m_uiSlimePoolTimer -= uiDiff; + + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = PHASE_SUBMERGED; + DoCastSpellIfCan(m_creature, SPELL_EMERGE); + m_creature->SetDisplayId(MODEL_DREADSCALE_STATIONARY); + m_creature->SetSpeedRate(MOVE_WALK, 0); + m_creature->SetSpeedRate(MOVE_RUN, 0); + m_uiPhaseTimer = 65000; + } + else + m_uiPhaseTimer -= uiDiff; + + break; + case PHASE_SUBMERGED: + if (m_uiFireSpitTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIRE_SPIT) == CAST_OK) + m_uiFireSpitTimer = 1200; + } + } + else + m_uiFireSpitTimer -= uiDiff; + + if (m_uiBurningSprayTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BURNING_SPRAY, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + m_uiBurningSprayTimer = 20000; + } + } + else + m_uiBurningSprayTimer -= uiDiff; + + if (m_uiSweepTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SWEEP, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + m_uiSweepTimer = 20000; + m_uiFireSpitTimer = 3000; + } + } + else + m_uiSweepTimer -= uiDiff; + + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = PHASE_EMERGED; + m_creature->SetDisplayId(MODEL_DREADSCALE_MOBILE); + m_creature->SetSpeedRate(MOVE_WALK, 1); + m_creature->SetSpeedRate(MOVE_RUN, 1); + SetCombatMovement(true); + m_creature->RemoveAurasDueToSpell(SPELL_EMERGE); + DoResetThreat(); + m_uiPhaseTimer = 65000; + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL && !m_bIsEnraged) + { + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); + m_creature->SetDisplayId(MODEL_DREADSCALE_MOBILE); + m_creature->SetSpeedRate(MOVE_WALK, 1); + m_creature->SetSpeedRate(MOVE_RUN, 1); + DoCastSpellIfCan(m_creature, SPELL_EMERGE, CAST_TRIGGERED); + + DoScriptText(EMOTE_ENRAGE, m_creature); + DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_TRIGGERED); + + m_bIsEnraged = true; + } + + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_SPECIAL) + { + m_uiAchievTimer -= uiDiff; + if (m_uiAchievTimer <= uiDiff) + m_bAchievFailed = true; + } + DoMeleeAttackIfReady(); } }; @@ -147,44 +803,280 @@ CreatureAI* GetAI_boss_dreadscale(Creature* pCreature) return new boss_dreadscaleAI(pCreature); } -/*###### -## boss_icehowl -######*/ - -enum +struct MANGOS_DLL_DECL mob_slime_poolAI : public ScriptedAI { - EMOTE_MASSIVE_CRASH = -1649039, + mob_slime_poolAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + + ScriptedInstance *m_pInstance; + + uint32 m_uiIncreaseSizeTimer; + + float m_fSize; + bool m_bIsCloudCasted; + + void Reset() + { + if (!m_pInstance) + return; + + m_uiIncreaseSizeTimer = 0; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + //m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_SLIME_POOL_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_AUTO_GROW, CAST_TRIGGERED); + + SetCombatMovement(false); + + m_fSize = m_creature->GetFloatValue(OBJECT_FIELD_SCALE_X); + m_bIsCloudCasted = false; + } + + void AttackStart(Unit *who) + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_DONE) + m_creature->ForcedDespawn(); + + if (!m_bIsCloudCasted) + { + m_creature->CastSpell(m_creature, SPELL_SLIME_POOL_VISUAL, false); + m_bIsCloudCasted = true; + } + + if (m_fSize >= 6.0f) + m_creature->ForcedDespawn(); + } + }; +CreatureAI* GetAI_mob_slime_pool(Creature* pCreature) +{ + return new mob_slime_poolAI(pCreature); +} + struct MANGOS_DLL_DECL 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_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + Difficulty m_uiMapDifficulty; - void Reset() {} + uint32 m_uiFerociousButtTimer; + uint32 m_uiArcticBreathTimer; + uint32 m_uiWhirlTimer; + uint32 m_uiMassiveCrashTimer; + uint32 m_uiWaitTimer; + uint32 m_uiPhaseTimer; + uint32 m_uiPhase; - void JustReachedHome() + float fPosX, fPosY, fPosZ; + Unit *pFocus; + + std::list vassalsEntryList; + + void Reset() { - if (m_pInstance) - m_pInstance->SetData(TYPE_NORTHREND_BEASTS, NOT_STARTED); + if (!m_pInstance) + return; + + m_uiFerociousButtTimer = 15000; + m_uiArcticBreathTimer = 25000; + m_uiWhirlTimer = 20000; + m_uiMassiveCrashTimer = 30000; + m_uiPhase = PHASE_NORMAL; + + m_creature->SetRespawnDelay(7*DAY); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetSpeedRate(MOVE_WALK, 3.0f); + m_creature->SetSpeedRate(MOVE_RUN, 3.0f); + + pFocus = NULL; + + vassalsEntryList.clear(); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_CENTER) + { + if (m_uiPhase == PHASE_MOVING) + { + if (DoCastSpellIfCan(m_creature, SPELL_MASSIVE_CRASH) == CAST_OK) + { + pFocus = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + DoScriptText(EMOTE_TRAMPLE, m_creature, pFocus); + m_creature->SetSpeedRate(MOVE_WALK, 6.0f); + m_creature->SetSpeedRate(MOVE_RUN, 6.0f); + m_uiWaitTimer = 5000; + m_uiPhaseTimer = 8000; + m_uiPhase = PHASE_TRAMPLE; + } + } + } + else if (uiData == POINT_TARGET) + { + if (m_uiPhase == PHASE_MOVING) + { + if (pFocus && pFocus->isAlive() && m_creature->IsWithinDistInMap(pFocus, 10.0f)) // I think that it should be any player not only focused. + { + DoCastSpellIfCan(m_creature, SPELL_TRAMPLE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FROTHING_RAGE, CAST_TRIGGERED); + } + else + { + DoCastSpellIfCan(m_creature, SPELL_STAGGERED_DAZE, CAST_TRIGGERED); + DoScriptText(EMOTE_STAGGERED, m_creature); + } + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetSpeedRate(MOVE_WALK, 3.0f); + m_creature->SetSpeedRate(MOVE_RUN, 3.0f); + SetCombatMovement(true); + m_uiPhase = PHASE_NORMAL; + pFocus = NULL; + } + } + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + // Find required NPC as achievement criteria + vassalsEntryList.clear(); + GetCreatureListWithEntryInGrid(vassalsEntryList, m_creature, NPC_SNOBOLD_VASSAL, 250.0f); + + if (vassalsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(TYPE_UPPER_BACK_PAIN, false); + else + { + if(m_uiMapDifficulty == RAID_DIFFICULTY_10MAN_HEROIC || m_uiMapDifficulty == RAID_DIFFICULTY_10MAN_NORMAL) + m_pInstance->SetSpecialAchievementCriteria(TYPE_UPPER_BACK_PAIN, vassalsEntryList.size() >= 2); + else + m_pInstance->SetSpecialAchievementCriteria(TYPE_UPPER_BACK_PAIN, vassalsEntryList.size() >= 4); + } + + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_DONE); + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, FAIL); + + m_creature->ForcedDespawn(); } void Aggro(Unit* pWho) { m_creature->SetInCombatWithZone(); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_IN_PROGRESS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); + switch (m_uiPhase) + { + case PHASE_NORMAL: + if (m_uiFerociousButtTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEROCIOUS_BUTT) == CAST_OK) + m_uiFerociousButtTimer = urand(15000, 30000); + } + else + m_uiFerociousButtTimer -= uiDiff; + + if (m_uiArcticBreathTimer <= uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + if (DoCastSpellIfCan(pTarget, SPELL_ARCTIC_BREATH) == CAST_OK) + m_uiArcticBreathTimer = urand(25000, 40000); + } + else + m_uiArcticBreathTimer -= uiDiff; + + if (m_uiWhirlTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WHIRL) == CAST_OK) + m_uiWhirlTimer = urand(20000, 30000); + } + else + m_uiWhirlTimer -= uiDiff; + + if (m_uiMassiveCrashTimer <= uiDiff) + { + m_creature->AttackStop(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + m_uiPhase = PHASE_MOVING; + m_uiMassiveCrashTimer = 40000; + } + else + m_uiMassiveCrashTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + case PHASE_TRAMPLE: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + if (m_uiWaitTimer < uiDiff) + { + if (pFocus && pFocus->isAlive()) + { + pFocus->GetPosition(fPosX, fPosY, fPosZ); + m_creature->SetFacingToObject(pFocus); + m_uiWaitTimer = 10000; // For count only once + } + } + else + m_uiWaitTimer -= uiDiff; + + if (m_uiPhaseTimer <= uiDiff) + { + if (pFocus && pFocus->isAlive()) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_TARGET, fPosX, fPosY, fPosZ); + DoScriptText(EMOTE_CRASH, m_creature); + m_uiPhase = PHASE_MOVING; + } + } + else + m_uiPhaseTimer -= uiDiff; + break; + case PHASE_MOVING: + break; + } } }; @@ -195,26 +1087,40 @@ CreatureAI* GetAI_boss_icehowl(Creature* pCreature) void AddSC_northrend_beasts() { - Script* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_gormok"; + pNewScript->GetAI = &GetAI_boss_gormok; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_acidmaw"; + pNewScript->GetAI = &GetAI_boss_acidmaw; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_gormok"; - newscript->GetAI = &GetAI_boss_gormok; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_dreadscale"; + pNewScript->GetAI = &GetAI_boss_dreadscale; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_acidmaw"; - newscript->GetAI = &GetAI_boss_acidmaw; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_icehowl"; + pNewScript->GetAI = &GetAI_boss_icehowl; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_dreadscale"; - newscript->GetAI = &GetAI_boss_dreadscale; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_snobold_vassal"; + pNewScript->GetAI = &GetAI_mob_snobold_vassal; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_icehowl"; - newscript->GetAI = &GetAI_boss_icehowl; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_fire_bomb"; + pNewScript->GetAI = &GetAI_mob_fire_bomb; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_slime_pool"; + pNewScript->GetAI = &GetAI_mob_slime_pool; + 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 7647d9d761..1414f5db23 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,48 +16,352 @@ /* ScriptData SDName: trial_of_the_crusader -SD%Complete: 0 -SDComment: +SD%Complete: 80% +SDComment: by /dev/rsa SDCategory: Crusader Coliseum EndScriptData */ #include "precompiled.h" #include "trial_of_the_crusader.h" -enum +enum BossSpells { - SAY_AGGRO = -1649056, - SAY_BERSERK = -1649057, - SAY_COLORSWITCH = -1649058, - SAY_DEATH = -1649059, - SAY_SLAY_1 = -1649060, - SAY_SLAY_2 = -1649061, - SAY_TO_BLACK = -1649062, - SAY_TO_WHITE = -1649063, + // Fjola + SPELL_TWIN_SPIKE_L = 66075, + SPELL_LIGHT_SURGE = 65766, + SPELL_LIGHT_SHIELD = 65858, + SPELL_TWIN_PACT_L = 65876, + SPELL_LIGHT_VORTEX = 66046, + SPELL_LIGHT_TOUCH = 67296, + + // Eydis + SPELL_TWIN_SPIKE_D = 66069, + SPELL_DARK_SURGE = 65768, + SPELL_DARK_SHIELD = 65874, + SPELL_TWIN_PACT_D = 65875, + SPELL_DARK_VORTEX = 66058, + SPELL_DARK_TOUCH = 67281, + + SPELL_TWIN_POWER = 65916, + + SPELL_LIGHT_ESSENCE = 65686, + SPELL_DARK_ESSENCE = 65684, + + SPELL_EMPOWERED_DARK = 67215, + SPELL_EMPOWERED_LIGHT = 65748, + + SPELL_BERSERK = 64238, + SPELL_REMOVE_TOUCH = 68084, + SPELL_NONE = 0, + + SPELL_UNLEASHED_DARK = 65808, + SPELL_UNLEASHED_LIGHT = 65795, +}; + +enum Equipment +{ + EQUIP_MAIN_1 = 49303, + EQUIP_OFFHAND_1 = 47146, + EQUIP_RANGED_1 = 47267, + EQUIP_MAIN_2 = 45990, + EQUIP_OFFHAND_2 = 47470, + EQUIP_RANGED_2 = 47267, + EQUIP_DONE = EQUIP_NO_CHANGE, +}; + +enum Summons +{ + NPC_DARK_ESSENCE = 34567, + NPC_LIGHT_ESSENCE = 34568, + + NPC_UNLEASHED_DARK = 34628, + NPC_UNLEASHED_LIGHT = 34630, +}; + +enum Yells +{ + SAY_AGGRO = -1649056, + SAY_DARK_VORTEX = -1649062, + SAY_LIGHT_VORTEX = -1649063, + SAY_SLAY_1 = -1649060, + SAY_SLAY_2 = -1649061, + SAY_PACT = -1649058, + SAY_DEATH = -1649059, + + EMOTE_LIGHT_VORTEX = -1649083, + EMOTE_PACT = -1649084, + EMOTE_DARK_VORTEX = -1649085, +}; + +enum Phases +{ + PHASE_NORMAL = 0, + PHASE_SPECIAL = 1, +}; + +enum Specials +{ + LIGHT_VORTEX = 0, + LIGHT_PACT = 1, + DARK_VORTEX = 2, + DARK_PACT = 3, }; -/*###### -## boss_fjola -######*/ +#define MAX_X = 598.80f; +#define MIN_X = 527.54f; +#define MAX_Y = 176.33f; +#define MIN_Y = 104.54f; struct MANGOS_DLL_DECL 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(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + float x, y, z; + + uint32 m_uiPhase; + uint32 m_uiTwinSpikeLTimer; + uint32 m_uiSpecialAbilityTimer; + uint32 m_uiLightTouchTimer; + uint32 m_uiCheckTouchBuff; + uint32 m_uiOrbsTimer; + uint32 m_uiNextSpell; + + Unit *pSister; + + void Reset() + { + if (!m_pInstance) + return; + + pSister = NULL; + + m_uiPhase = PHASE_NORMAL; + m_uiNextSpell = urand(0,1); + m_uiTwinSpikeLTimer = 10000; + m_uiSpecialAbilityTimer = 45000; + m_uiLightTouchTimer = 15000; + m_uiCheckTouchBuff = 1000; + m_uiOrbsTimer = 2500; + + SetEquipmentSlots(false, EQUIP_MAIN_1, EQUIP_OFFHAND_1, EQUIP_RANGED_1); + + m_creature->SetRespawnDelay(7*DAY); + m_creature->SetHealth(m_creature->GetMaxHealth()); + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_VALKIRIES, FAIL); + m_pInstance->SetData(DATA_HEALTH_FJOLA, m_creature->GetMaxHealth()); + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + DoScriptText(SAY_DEATH, m_creature); + m_pInstance->SetData(TYPE_VALKIRIES, DONE); + + if (pSister) + { + if (pSister->isAlive()) + pKiller->DealDamage(pSister, pSister->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } - void Reset() {} + m_pInstance->SetData(DATA_HEALTH_FJOLA, 0); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_SLAY_1 - urand(0, 1),m_creature,pVictim); + } void Aggro(Unit* pWho) { + if (!m_pInstance) + return; + + pSister = m_pInstance->GetSingleCreatureFromStorage(NPC_DARKBANE); + m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_LIGHT_SURGE, CAST_TRIGGERED); + + m_pInstance->SetData(DATA_HEALTH_FJOLA, m_creature->GetMaxHealth()); + m_pInstance->SetData(TYPE_VALKIRIES, IN_PROGRESS); + + m_creature->SummonCreature(NPC_LIGHT_ESSENCE, SpawnLoc[24].x, SpawnLoc[24].y, SpawnLoc[24].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + m_creature->SummonCreature(NPC_LIGHT_ESSENCE, SpawnLoc[25].x, SpawnLoc[25].y, SpawnLoc[25].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!m_pInstance) + return; + + if (!m_creature || !m_creature->isAlive()) + return; + + if (pDoneBy->GetObjectGuid() == m_creature->GetObjectGuid()) + return; + + if (pDoneBy->GetTypeId() == TYPEID_PLAYER) + { + if (pDoneBy->HasAura(SPELL_LIGHT_ESSENCE)) + uiDamage /= 2; + else if (pDoneBy->HasAura(SPELL_DARK_ESSENCE)) + uiDamage += uiDamage/2; + } + + m_pInstance->SetData(DATA_HEALTH_FJOLA, m_creature->GetHealth() >= uiDamage ? m_creature->GetHealth() - uiDamage : 0); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (!m_pInstance) + return; + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (!pSister) + return; + + if (m_creature->GetHealth() > m_pInstance->GetData(DATA_HEALTH_EYDIS) && + m_pInstance->GetData(DATA_HEALTH_EYDIS) != 0) + m_creature->SetHealth(m_pInstance->GetData(DATA_HEALTH_EYDIS)); + + if (m_bIsHeroic) + { + if (m_uiCheckTouchBuff <= uiDiff) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + + if (!pPlayer) + continue; + + if (pPlayer->HasAura(SPELL_LIGHT_ESSENCE)) + pPlayer->RemoveAurasDueToSpell(SPELL_LIGHT_TOUCH); + } + m_uiCheckTouchBuff = 1000; + } + else + m_uiCheckTouchBuff -= uiDiff; + } + + if (m_uiOrbsTimer <= uiDiff) + { + for (uint32 i = 33; i < 37; i++) + { + m_creature->SummonCreature(NPC_UNLEASHED_LIGHT, SpawnLoc[i].x + urand(2.0f, 10.0f), SpawnLoc[i].y + urand(2.0f, 10.0f), SpawnLoc[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + if (m_bIs25Man) + m_creature->SummonCreature(NPC_UNLEASHED_LIGHT, SpawnLoc[i + 8].x + urand(2.0f, 10.0f), SpawnLoc[i + 8].y + urand(2.0f, 10.0f), SpawnLoc[i + 8].z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + } + m_uiOrbsTimer = 30000; + } + else + m_uiOrbsTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_NORMAL: + if (m_uiTwinSpikeLTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWIN_SPIKE_L) == CAST_OK) + m_uiTwinSpikeLTimer = 10000; + } + else + m_uiTwinSpikeLTimer -= uiDiff; + + if (m_bIsHeroic) + { + if (m_uiLightTouchTimer <= uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, SPELL_LIGHT_TOUCH) == CAST_OK) + m_uiLightTouchTimer = 20000; + } + else + m_uiLightTouchTimer -= uiDiff; + } + + if (m_uiSpecialAbilityTimer <= uiDiff) + { + m_creature->InterruptNonMeleeSpells(true); + switch(m_uiNextSpell) + { + case LIGHT_VORTEX: // Vortex + if (DoCastSpellIfCan(m_creature, SPELL_LIGHT_VORTEX) == CAST_OK) + { + m_creature->SetLevitate(true); + m_creature->GetPosition(x, y, z); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z + 5.0f); + DoScriptText(EMOTE_LIGHT_VORTEX, m_creature); + DoScriptText(SAY_LIGHT_VORTEX, m_creature); + m_uiPhase = PHASE_SPECIAL; + m_uiNextSpell = LIGHT_PACT; + } + break; + case LIGHT_PACT: // Pact + pSister->CastSpell(pSister, SPELL_TWIN_POWER, true); + m_creature->_AddAura(SPELL_LIGHT_SHIELD, 14000); + if (DoCastSpellIfCan(m_creature, SPELL_TWIN_PACT_L) == CAST_OK) + { + m_creature->SetLevitate(true); + m_creature->GetPosition(x, y, z); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z + 5.0f); + DoScriptText(EMOTE_PACT, m_creature); + DoScriptText(SAY_PACT, m_creature); + m_uiPhase = PHASE_SPECIAL; + m_uiNextSpell = LIGHT_VORTEX; + } + break; + default: + break; + } + m_uiSpecialAbilityTimer = 90000; + } + else + m_uiSpecialAbilityTimer -= uiDiff; + + break; + case PHASE_SPECIAL: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + m_creature->SetLevitate(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiPhase = PHASE_NORMAL; + m_uiSpecialAbilityTimer -= uiDiff; + break; + default: + break; + } DoMeleeAttackIfReady(); } }; @@ -67,26 +371,258 @@ CreatureAI* GetAI_boss_fjola(Creature* pCreature) return new boss_fjolaAI(pCreature); } -/*###### -## boss_eydis -######*/ - struct MANGOS_DLL_DECL 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(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + instance_trial_of_the_crusader* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + float x, y, z; + + uint32 m_uiPhase; + uint32 m_uiTwinSpikeDTimer; + uint32 m_uiSpecialAbilityTimer; + uint32 m_uiDarkTouchTimer; + uint32 m_uiCheckTouchBuff; + uint32 m_uiOrbsTimer; + uint32 m_uiNextSpell; + + Unit *pSister; + + void Reset() + { + if (!m_pInstance) + return; - void Reset() {} + pSister = NULL; + + m_uiPhase = PHASE_NORMAL; + m_uiNextSpell = urand(2,3); + m_uiTwinSpikeDTimer = 10000; + m_uiSpecialAbilityTimer = 90000; + m_uiDarkTouchTimer = 5000; + m_uiCheckTouchBuff = 1000; + m_uiOrbsTimer = 2500; + + SetEquipmentSlots(false, EQUIP_MAIN_2, EQUIP_OFFHAND_2, EQUIP_RANGED_2); + + m_creature->SetRespawnDelay(7*DAY); + m_creature->SetHealth(m_creature->GetMaxHealth()); + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_VALKIRIES, FAIL); + m_pInstance->SetData(DATA_HEALTH_EYDIS, m_creature->GetMaxHealth()); + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + DoScriptText(SAY_DEATH, m_creature); + m_pInstance->SetData(TYPE_VALKIRIES, DONE); + + if (pSister) + { + if (pSister->isAlive()) + pKiller->DealDamage(pSister, pSister->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + m_pInstance->SetData(DATA_HEALTH_EYDIS, 0); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_SLAY_1 - urand(0, 1),m_creature,pVictim); + } void Aggro(Unit* pWho) { + if (!m_pInstance) + return; + + pSister = m_pInstance->GetSingleCreatureFromStorage(NPC_LIGHTBANE); + m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_DARK_SURGE, CAST_TRIGGERED); + + m_pInstance->SetData(DATA_HEALTH_EYDIS, m_creature->GetMaxHealth()); + m_pInstance->SetData(TYPE_VALKIRIES, IN_PROGRESS); + + m_creature->SummonCreature(NPC_DARK_ESSENCE, SpawnLoc[22].x, SpawnLoc[22].y, SpawnLoc[22].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + m_creature->SummonCreature(NPC_DARK_ESSENCE, SpawnLoc[23].x, SpawnLoc[23].y, SpawnLoc[23].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!m_pInstance) + return; + + if (!m_creature || !m_creature->isAlive()) + return; + + if (pDoneBy->GetObjectGuid() == m_creature->GetObjectGuid()) + return; + + if (pDoneBy->GetTypeId() == TYPEID_PLAYER) + { + if (pDoneBy->HasAura(SPELL_DARK_ESSENCE)) + uiDamage /= 2; + else if (pDoneBy->HasAura(SPELL_LIGHT_ESSENCE)) + uiDamage += uiDamage/2; + } + + m_pInstance->SetData(DATA_HEALTH_EYDIS, m_creature->GetHealth() >= uiDamage ? m_creature->GetHealth() - uiDamage : 0); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (!m_pInstance) + return; + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (!pSister) + return; + + + if (m_creature->GetHealth() > m_pInstance->GetData(DATA_HEALTH_FJOLA) && + m_pInstance->GetData(DATA_HEALTH_FJOLA) != 0) + m_creature->SetHealth(m_pInstance->GetData(DATA_HEALTH_FJOLA)); + + if (m_bIsHeroic) + { + if (m_uiCheckTouchBuff <= uiDiff) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + + if (!pPlayer) + continue; + + if (pPlayer->HasAura(SPELL_DARK_ESSENCE)) + pPlayer->RemoveAurasDueToSpell(SPELL_DARK_TOUCH); + } + m_uiCheckTouchBuff = 1000; + } + else + m_uiCheckTouchBuff -= uiDiff; + } + + if (m_uiOrbsTimer <= uiDiff) + { + for (uint32 i = 37; i < 41; i++) + { + m_creature->SummonCreature(NPC_UNLEASHED_DARK, SpawnLoc[i].x + urand(2.0f, 10.0f), SpawnLoc[i].y + urand(2.0f, 5.0f), SpawnLoc[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + if (m_bIs25Man) + m_creature->SummonCreature(NPC_UNLEASHED_DARK, SpawnLoc[i + 8].x + urand(2.0f, 10.0f), SpawnLoc[i + 8].y + urand(2.0f, 5.0f), SpawnLoc[i + 8].z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + } + m_uiOrbsTimer = 30000; + } + else + m_uiOrbsTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_NORMAL: + if (m_uiTwinSpikeDTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWIN_SPIKE_D) == CAST_OK) + m_uiTwinSpikeDTimer = 10000; + } + else + m_uiTwinSpikeDTimer -= uiDiff; + + if (m_bIsHeroic) + { + if (m_uiDarkTouchTimer <= uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, SPELL_DARK_TOUCH) == CAST_OK) + m_uiDarkTouchTimer = 20000; + } + else + m_uiDarkTouchTimer -= uiDiff; + } + + if (m_uiSpecialAbilityTimer <= uiDiff) + { + m_creature->InterruptNonMeleeSpells(true); + switch(m_uiNextSpell) + { + case DARK_VORTEX: + if (DoCastSpellIfCan(m_creature, SPELL_DARK_VORTEX) == CAST_OK) + { + m_creature->SetLevitate(true); + m_creature->GetPosition(x, y, z); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z + 5.0f); + DoScriptText(EMOTE_DARK_VORTEX, m_creature); + DoScriptText(SAY_DARK_VORTEX, m_creature); + m_uiPhase = PHASE_SPECIAL; + m_uiNextSpell = DARK_PACT; + } + break; + case DARK_PACT: + pSister->CastSpell(pSister, SPELL_TWIN_POWER, true); + m_creature->_AddAura(SPELL_DARK_SHIELD, 14000); + if (DoCastSpellIfCan(m_creature, SPELL_TWIN_PACT_D) == CAST_OK) + { + m_creature->SetLevitate(true); + m_creature->GetPosition(x, y, z); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z + 5.0f); + DoScriptText(EMOTE_PACT, m_creature); + DoScriptText(SAY_PACT, m_creature); + m_uiPhase = PHASE_SPECIAL; + m_uiNextSpell = DARK_VORTEX; + } + break; + default: + break; + } + m_uiSpecialAbilityTimer = 90000; + } + else + m_uiSpecialAbilityTimer -= uiDiff; + + break; + case PHASE_SPECIAL: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + //m_creature->SetLevitate(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiPhase = PHASE_NORMAL; + m_uiSpecialAbilityTimer -= uiDiff; + break; + default: + break; + } DoMeleeAttackIfReady(); } }; @@ -96,17 +632,304 @@ CreatureAI* GetAI_boss_eydis(Creature* pCreature) return new boss_eydisAI(pCreature); } +struct MANGOS_DLL_DECL mob_light_essenceAI : public ScriptedAI +{ + mob_light_essenceAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->SetWalk(true); + SetCombatMovement(false); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + m_creature->ForcedDespawn(); + + if (m_pInstance->GetData(TYPE_VALKIRIES) != IN_PROGRESS) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + if (!pPlayer) continue; + if (pPlayer) + pPlayer->RemoveAurasDueToSpell(SPELL_LIGHT_ESSENCE); + } + + m_creature->ForcedDespawn(); + } + return; + } +}; + +CreatureAI* GetAI_mob_light_essence(Creature* pCreature) +{ + return new mob_light_essenceAI(pCreature); +}; + +bool GossipHello_mob_light_essence(Player *player, Creature* pCreature) +{ + ScriptedInstance *pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + + if (!pInstance) + return true; + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetObjectGuid()); + player->RemoveAurasDueToSpell(SPELL_DARK_ESSENCE); + player->CastSpell(player,SPELL_LIGHT_ESSENCE, true); + player->RemoveAurasDueToSpell(SPELL_LIGHT_TOUCH); + player->CLOSE_GOSSIP_MENU(); + return true; +}; + +struct MANGOS_DLL_DECL mob_dark_essenceAI : public ScriptedAI +{ + mob_dark_essenceAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->SetWalk(true); + SetCombatMovement(false); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + m_creature->ForcedDespawn(); + + if (m_pInstance->GetData(TYPE_VALKIRIES) != IN_PROGRESS) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + if (!pPlayer) continue; + if (pPlayer) + pPlayer->RemoveAurasDueToSpell(SPELL_DARK_ESSENCE); + } + m_creature->ForcedDespawn(); + } + return; + } +}; + +CreatureAI* GetAI_mob_dark_essence(Creature* pCreature) +{ + return new mob_dark_essenceAI(pCreature); +}; + +bool GossipHello_mob_dark_essence(Player *player, Creature* pCreature) +{ + ScriptedInstance *pInstance = (ScriptedInstance *) pCreature->GetInstanceData(); + + if (!pInstance) + return true; + + player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetObjectGuid()); + player->RemoveAurasDueToSpell(SPELL_LIGHT_ESSENCE); + player->CastSpell(player,SPELL_DARK_ESSENCE, false); + player->RemoveAurasDueToSpell(SPELL_DARK_TOUCH); + player->CLOSE_GOSSIP_MENU(); + return true; +} + +struct MANGOS_DLL_DECL mob_unleashed_darkAI : public ScriptedAI +{ + mob_unleashed_darkAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiCheckTimer; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->MoveRandom(); + + SetCombatMovement(false); + + m_uiCheckTimer = 1000; + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_VALKIRIES) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiCheckTimer < uiDiff) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + + if (!pPlayer) + continue; + + if (pPlayer->isAlive() && pPlayer->IsWithinDistInMap(m_creature, 4.0f)) + { + if (pPlayer->HasAura(SPELL_DARK_ESSENCE)) + { + if (pPlayer->HasAura(SPELL_EMPOWERED_LIGHT)) + pPlayer->RemoveAurasDueToSpell(SPELL_EMPOWERED_LIGHT); + + pPlayer->_AddAura(SPELL_EMPOWERED_DARK, 20000); + m_creature->ForcedDespawn(300); + } + else + { + DoCastSpellIfCan(m_creature, SPELL_UNLEASHED_DARK, CAST_TRIGGERED); + m_creature->ForcedDespawn(700); + } + } + } + m_uiCheckTimer = 500; + } + else + m_uiCheckTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_unleashed_dark(Creature *pCreature) +{ + return new mob_unleashed_darkAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_unleashed_lightAI : public ScriptedAI +{ + mob_unleashed_lightAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiCheckTimer; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->MoveRandom(); + + SetCombatMovement(false); + + m_uiCheckTimer = 1000; + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_VALKIRIES) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiCheckTimer < uiDiff) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + + if (!pPlayer) + continue; + + if (pPlayer->isAlive() && pPlayer->IsWithinDistInMap(m_creature, 4.0f)) + { + if (pPlayer->HasAura(SPELL_LIGHT_ESSENCE)) + { + if (pPlayer->HasAura(SPELL_EMPOWERED_DARK)) + pPlayer->RemoveAurasDueToSpell(SPELL_EMPOWERED_DARK); + + pPlayer->_AddAura(SPELL_EMPOWERED_LIGHT, 20000); + m_creature->ForcedDespawn(300); + } + else + { + DoCastSpellIfCan(m_creature, SPELL_UNLEASHED_LIGHT, CAST_TRIGGERED); + m_creature->ForcedDespawn(700); + } + } + } + m_uiCheckTimer = 500; + } + else + m_uiCheckTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_unleashed_light(Creature *pCreature) +{ + return new mob_unleashed_lightAI(pCreature); +} + void AddSC_twin_valkyr() { - Script* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_fjola"; + pNewScript->GetAI = &GetAI_boss_fjola; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_eydis"; + pNewScript->GetAI = &GetAI_boss_eydis; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_unleashed_light"; + pNewScript->GetAI = &GetAI_mob_unleashed_light; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_unleashed_dark"; + pNewScript->GetAI = &GetAI_mob_unleashed_dark; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_fjola"; - newscript->GetAI = &GetAI_boss_fjola; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_light_essence"; + pNewScript->GetAI = &GetAI_mob_light_essence; + pNewScript->pGossipHello = &GossipHello_mob_light_essence; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_eydis"; - newscript->GetAI = &GetAI_boss_fjola; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_dark_essence"; + pNewScript->GetAI = &GetAI_mob_dark_essence; + pNewScript->pGossipHello = &GossipHello_mob_dark_essence; + 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 21c424fe3f..f695e73ae2 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,172 +16,526 @@ /* ScriptData SDName: instance_trial_of_the_crusader -SD%Complete: 100 -SDComment: -SDCategory: Crusader Coliseum +SD%Complete: 80% +SDComment: by /dev/rsa +SDCategory: Trial of the Crusader EndScriptData */ #include "precompiled.h" #include "trial_of_the_crusader.h" -/* Trial Of The Crusader encounters: -0 - Northrend Beasts -1 - Jaraxxus -2 - Faction Champions -3 - Twin Valkyr -4 - Anubarak -*/ +instance_trial_of_the_crusader::instance_trial_of_the_crusader(Map* pMap) : BSWScriptedInstance(pMap) +{ + Difficulty = pMap->GetDifficulty(); + Initialize(); +} -struct MANGOS_DLL_DECL instance_trial_of_the_crusader : public ScriptedInstance +void instance_trial_of_the_crusader::Initialize() { - instance_trial_of_the_crusader(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + m_auiEncounter[i] = NOT_STARTED; - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; + for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS - 1; ++i) + m_bAchievCriteria[i] = false; - uint32 m_uiGormokGUID; - uint32 m_uiAcidmawGUID; - uint32 m_uiDreadscaleGUID; - uint32 m_uiIcehowlGUID; - uint32 m_uiJaraxxusGUID; - uint32 m_uiFjolaGUID; - uint32 m_uiEydisGUID; - uint32 m_uiAnubarakGUID; + SetSpecialAchievementCriteria(TYPE_SKILL, true); + SetSpecialAchievementCriteria(TYPE_MAD_SKILL, true); + SetSpecialAchievementCriteria(TYPE_INSANITY, true); + SetSpecialAchievementCriteria(TYPE_IMMORTALITY, true); - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + m_auiEncounter[TYPE_STAGE] = 0; + m_auiEncounter[TYPE_COUNTER] = 50; + m_auiEncounter[TYPE_DEATHS] = 0; + m_auiEncounter[TYPE_EVENT] = 0; - m_uiGormokGUID = 0; - m_uiAcidmawGUID = 0; - m_uiDreadscaleGUID = 0; - m_uiIcehowlGUID = 0; - m_uiJaraxxusGUID = 0; - m_uiFjolaGUID = 0; - m_uiEydisGUID = 0; - m_uiAnubarakGUID = 0; + m_auiNorthrendBeasts = NOT_STARTED; + m_auiEventTimer = 1000; + m_auiCrusadersCount = 6; + m_auiCrusadersDead = 0; + m_auiCrusadersAchievFail = 0; + m_auiCrusadersAchievTimer = 60000; + needsave = false; +} +bool instance_trial_of_the_crusader::IsEncounterInProgress() const +{ + for(uint8 i = 1; i < MAX_ENCOUNTERS-2 ; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + + return false; +} + +void instance_trial_of_the_crusader::OnPlayerEnter(Player *m_player) +{ + if (Difficulty == RAID_DIFFICULTY_10MAN_HEROIC || Difficulty == RAID_DIFFICULTY_25MAN_HEROIC) + { + m_player->SendUpdateWorldState(UPDATE_STATE_UI_SHOW, 1); + m_player->SendUpdateWorldState(UPDATE_STATE_UI_COUNT, GetData(TYPE_COUNTER)); } +} + +void instance_trial_of_the_crusader::OnPlayerDeath(Player* pPlayer) +{ + if (IsEncounterInProgress()) + SetData(TYPE_DEATHS, 1); +} - bool IsEncounterInProgress() const +bool instance_trial_of_the_crusader::IsRaidWiped() +{ + Map::PlayerList const &players = instance->GetPlayers(); + + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; + if (Player* pPlayer = i->getSource()) + { + if (pPlayer->isAlive()) + return false; - return false; + } } + return true; +} + +void instance_trial_of_the_crusader::UpdateWorldState() +{ + Map::PlayerList const &players = instance->GetPlayers(); - void OnCreatureCreate(Creature* pCreature) + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) { - switch(pCreature->GetEntry()) + if (Player* pPlayer = i->getSource()) { - case 34796: m_uiGormokGUID = pCreature->GetGUID(); break; - case 35144: m_uiAcidmawGUID = pCreature->GetGUID(); break; - case 34799: m_uiDreadscaleGUID = pCreature->GetGUID(); break; - case 34797: m_uiIcehowlGUID = pCreature->GetGUID(); break; - case 34780: m_uiJaraxxusGUID = pCreature->GetGUID(); break; - case 34497: m_uiFjolaGUID = pCreature->GetGUID(); break; - case 34496: m_uiEydisGUID = pCreature->GetGUID(); break; - case 34564: m_uiAnubarakGUID = pCreature->GetGUID(); break; + if (Difficulty == RAID_DIFFICULTY_10MAN_HEROIC || Difficulty == RAID_DIFFICULTY_25MAN_HEROIC) + { + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_SHOW, 1); + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_COUNT, GetData(TYPE_COUNTER)); + } } } +} + +void instance_trial_of_the_crusader::OnCreatureCreate(Creature* pCreature) +{ + if (!pCreature) + return; + + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); +} + +void instance_trial_of_the_crusader::OnObjectCreate(GameObject *pGo) +{ + if (!pGo) + return; + + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void SetData(uint32 uiType, uint32 uiData) +bool instance_trial_of_the_crusader::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const +{ + switch (uiCriteriaId) { - debug_log("SD2: Instance Trial Of The Crusader: SetData received for type %u with data %u",uiType,uiData); + case CRITERIA_ACHIEV_UPPER_BACK_PAIN_10N: + case CRITERIA_ACHIEV_UPPER_BACK_PAIN_10H: + case CRITERIA_ACHIEV_UPPER_BACK_PAIN_25N: + case CRITERIA_ACHIEV_UPPER_BACK_PAIN_25H: + return m_bAchievCriteria[TYPE_UPPER_BACK_PAIN]; + case CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_10N: + case CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_10H: + case CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_25N: + case CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_25H: + return m_bAchievCriteria[TYPE_THREE_SIXTY_PAIN_SPIKE]; + case CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_10_1: + case CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_10_2: + //case CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_10_3: + return Difficulty == RAID_DIFFICULTY_10MAN_HEROIC ? m_bAchievCriteria[TYPE_SKILL] : false; + case CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_25_1: + case CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_25_2: + //case CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_25_3: + return Difficulty == RAID_DIFFICULTY_25MAN_HEROIC ? m_bAchievCriteria[TYPE_SKILL] : false; + case CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_10_1: + case CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_10_2: + return Difficulty == RAID_DIFFICULTY_10MAN_HEROIC ? m_bAchievCriteria[TYPE_MAD_SKILL] : false; + case CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_25_1: + case CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_25_2: + return Difficulty == RAID_DIFFICULTY_25MAN_HEROIC ? m_bAchievCriteria[TYPE_MAD_SKILL] : false; + case CRITERIA_ACHIEV_TRIBUTE_TO_INSANITY_10: + return Difficulty == RAID_DIFFICULTY_10MAN_HEROIC ? m_bAchievCriteria[TYPE_INSANITY] : false; + case CRITERIA_ACHIEV_TRIBUTE_TO_INSANITY_25: + return Difficulty == RAID_DIFFICULTY_25MAN_HEROIC ? m_bAchievCriteria[TYPE_INSANITY] : false; + case CRITERIA_ACHIEV_TRIBUTE_TO_IMMORTALITY_HORDE: + case CRITERIA_ACHIEV_TRIBUTE_TO_IMMORTALITY_ALLY: + return Difficulty == RAID_DIFFICULTY_25MAN_HEROIC ? m_bAchievCriteria[TYPE_IMMORTALITY] : false; + default: + return false; + } +} + +void instance_trial_of_the_crusader::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < MAX_SPECIAL_ACHIEV_CRITS) + m_bAchievCriteria[uiType] = bIsMet; +} - switch(uiType) +void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) +{ + switch(uiType) + { + case TYPE_STAGE: + m_auiEncounter[TYPE_STAGE] = uiData; + break; + case TYPE_BEASTS: + m_auiEncounter[TYPE_BEASTS] = uiData; + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_UPPER_BACK_PAIN, false); + break; + case TYPE_JARAXXUS: + m_auiEncounter[TYPE_JARAXXUS] = uiData; + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_THREE_SIXTY_PAIN_SPIKE, false); + break; + case TYPE_CRUSADERS: + if (uiData == FAIL && (m_auiEncounter[TYPE_CRUSADERS] == FAIL || m_auiEncounter[TYPE_CRUSADERS] == NOT_STARTED)) + m_auiEncounter[TYPE_CRUSADERS] = NOT_STARTED; + else + m_auiEncounter[TYPE_CRUSADERS] = uiData; + if (uiData == DONE) { - case TYPE_NORTHREND_BEASTS: - m_auiEncounter[0] = uiData; - break; - case TYPE_JARAXXUS: - m_auiEncounter[1] = uiData; - break; - case TYPE_FACTION_CHAMPIONS: - m_auiEncounter[2] = uiData; - break; - case TYPE_TWIN_VALKYR: - m_auiEncounter[3] = uiData; - break; - case TYPE_ANUBARAK: - m_auiEncounter[4] = uiData; - break; - default: - error_log("SD2: Instance Trial of The Crusader: ERROR SetData = %u for type %u does not exist/not implemented.",uiType,uiData); - break; + if (GetSingleCreatureFromStorage(NPC_TIRION)) + DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ACHIEV_FACTION_CHAMPIONS_DEFEAT); + + uint32 uiCacheEntry = GO_CRUSADERS_CACHE_10; + + switch (instance->GetDifficulty()) + { + case RAID_DIFFICULTY_10MAN_HEROIC: + uiCacheEntry = GO_CRUSADERS_CACHE_10_H; + break; + case RAID_DIFFICULTY_25MAN_NORMAL: + uiCacheEntry = GO_CRUSADERS_CACHE_25; + break; + case RAID_DIFFICULTY_25MAN_HEROIC: + uiCacheEntry = GO_CRUSADERS_CACHE_25_H; + break; + default: + uiCacheEntry = GO_CRUSADERS_CACHE_10; + break; + } + if (GameObject* pChest = GetSingleGameObjectFromStorage(uiCacheEntry)) + if (!pChest->isSpawned()) + pChest->SetRespawnTime(7*DAY); + }; + break; + case TYPE_CRUSADERS_COUNT: + if (uiData == 0) + --m_auiCrusadersCount; + else + m_auiCrusadersCount = uiData; + break; + case TYPE_CRUSADERS_DEAD: + m_auiCrusadersDead = uiData; + break; + case TYPE_CRUSADERS_ACHIEV_TIMER: + if(m_auiCrusadersAchievFail) + break; + if (m_auiCrusadersAchievTimer <= uiData) + m_auiCrusadersAchievFail = 1; + else + m_auiCrusadersAchievTimer -= uiData; + break; + case TYPE_CRUSADERS_ACHIEV_FAIL: + m_auiCrusadersAchievFail = uiData; + break; + case TYPE_VALKIRIES: + /*if (m_auiEncounter[4] == SPECIAL && uiData == SPECIAL) + uiData = DONE;*/ + m_auiEncounter[TYPE_VALKIRIES] = uiData; + break; + case TYPE_LICH_KING: + m_auiEncounter[TYPE_LICH_KING] = uiData; + break; + case TYPE_ANUBARAK: + m_auiEncounter[TYPE_ANUBARAK] = uiData; + + if (uiData == IN_PROGRESS) + { + DoCloseDoor(GO_WEB_DOOR); } + else + DoOpenDoor(GO_WEB_DOOR); if (uiData == DONE) { - OUT_SAVE_INST_DATA; + if (Difficulty == RAID_DIFFICULTY_10MAN_HEROIC) + { + if (m_auiEncounter[TYPE_COUNTER] >= 25) + m_uiTributeChest1 = GO_TRIBUTE_CHEST_10H_25; + if (m_auiEncounter[TYPE_COUNTER] >= 45) + m_uiTributeChest2 = GO_TRIBUTE_CHEST_10H_45; + if (m_auiEncounter[TYPE_COUNTER] > 49) + m_uiTributeChest3 = GO_TRIBUTE_CHEST_10H_50; + + m_uiTributeChest4 = GO_TRIBUTE_CHEST_10H_99; + } + if (Difficulty == RAID_DIFFICULTY_25MAN_HEROIC) + { + if (m_auiEncounter[TYPE_COUNTER] >= 25) + m_uiTributeChest1 = GO_TRIBUTE_CHEST_25H_25; + if (m_auiEncounter[TYPE_COUNTER] >= 45) + m_uiTributeChest2 = GO_TRIBUTE_CHEST_25H_45; + if (m_auiEncounter[TYPE_COUNTER] > 49) + m_uiTributeChest3 = GO_TRIBUTE_CHEST_25H_50; + + m_uiTributeChest4 = GO_TRIBUTE_CHEST_25H_99; + } + // Attention! It is (may be) not off-like, but spawning all Tribute Chests is real + // reward for clearing TOC instance + if (m_uiTributeChest1) + if (GameObject* pChest1 = GetSingleGameObjectFromStorage(m_uiTributeChest1)) + if (pChest1 && !pChest1->isSpawned()) + pChest1->SetRespawnTime(7*DAY); - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4]; + if (m_uiTributeChest2) + if (GameObject* pChest2 = GetSingleGameObjectFromStorage(m_uiTributeChest2)) + if (pChest2 && !pChest2->isSpawned()) + pChest2->SetRespawnTime(7*DAY); - strInstData = saveStream.str(); + if (m_uiTributeChest3) + if (GameObject* pChest3 = GetSingleGameObjectFromStorage(m_uiTributeChest3)) + if (pChest3 && !pChest3->isSpawned()) + pChest3->SetRespawnTime(7*DAY); - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; + if (m_uiTributeChest4) + if (GameObject* pChest4 = GetSingleGameObjectFromStorage(m_uiTributeChest4)) + if (pChest4 && !pChest4->isSpawned()) + pChest4->SetRespawnTime(7*DAY); + }; + break; + case TYPE_COUNTER: + m_auiEncounter[TYPE_COUNTER] = uiData; + if (uiData < 25) + SetSpecialAchievementCriteria(TYPE_SKILL, false); + if (uiData < 45) + SetSpecialAchievementCriteria(TYPE_MAD_SKILL, false); + if (uiData < 50) + { + SetSpecialAchievementCriteria(TYPE_INSANITY, false); + SetSpecialAchievementCriteria(TYPE_IMMORTALITY, false); } + + //uiData = DONE; + break; + case TYPE_DEATHS: + m_auiEncounter[TYPE_DEATHS] += uiData; + if (GetData(TYPE_DEATHS)) + SetSpecialAchievementCriteria(TYPE_IMMORTALITY, false); + break; + case TYPE_EVENT: + m_auiEncounter[TYPE_EVENT] = uiData; + uiData = NOT_STARTED; + break; + case TYPE_EVENT_TIMER: + m_auiEventTimer = uiData; + uiData = NOT_STARTED; + break; + case TYPE_NORTHREND_BEASTS: + m_auiNorthrendBeasts = uiData; + break; + case DATA_HEALTH_FJOLA: + m_uiDataDamageFjola = uiData; uiData = NOT_STARTED; + break; + case DATA_HEALTH_EYDIS: + m_uiDataDamageEydis = uiData; uiData = NOT_STARTED; + break; } - uint32 GetData(uint32 uiType) + if (IsEncounterInProgress()) { - switch(uiType) - { - case TYPE_NORTHREND_BEASTS: return m_auiEncounter[0]; - case TYPE_JARAXXUS: return m_auiEncounter[1]; - case TYPE_FACTION_CHAMPIONS: return m_auiEncounter[2]; - case TYPE_TWIN_VALKYR: return m_auiEncounter[3]; - case TYPE_ANUBARAK: return m_auiEncounter[4]; - } - return 0; + DoCloseDoor(GO_WEST_PORTCULLIS); + DoCloseDoor(GO_NORTH_PORTCULLIS); + DoCloseDoor(GO_SOUTH_PORTCULLIS); + + if (Creature* pBarrent = GetSingleCreatureFromStorage(NPC_BARRENT)) + pBarrent->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } + else + { + DoOpenDoor(GO_WEST_PORTCULLIS); + DoCloseDoor(GO_NORTH_PORTCULLIS); + DoCloseDoor(GO_SOUTH_PORTCULLIS); + + if (Creature* pBarrent = GetSingleCreatureFromStorage(NPC_BARRENT)) + pBarrent->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + }; - uint64 GetData64(uint32 uiData) + if (uiData == FAIL && uiType != TYPE_STAGE && uiType != TYPE_EVENT && uiType != TYPE_COUNTER && uiType != TYPE_EVENT_TIMER) { - switch(uiData) + if (IsRaidWiped()) { - case DATA_GORMOK: return m_uiGormokGUID; - case DATA_ACIDMAW: return m_uiAcidmawGUID; - case DATA_DREADSCALE: return m_uiDreadscaleGUID; - case DATA_ICEHOWL: return m_uiIcehowlGUID; - case DATA_JARAXXUS: return m_uiJaraxxusGUID; - case DATA_FJOLA: return m_uiFjolaGUID; - case DATA_EYDIS: return m_uiEydisGUID; - case DATA_ANUBARAK: return m_uiAnubarakGUID; + //--m_auiEncounter[TYPE_COUNTER]; + SetData(TYPE_COUNTER, GetData(TYPE_COUNTER) - 1); + needsave = true; + UpdateWorldState(); } - return 0; + uiData = NOT_STARTED; } - const char* Save() + if ((uiData == DONE && uiType != TYPE_STAGE && uiType != TYPE_EVENT && uiType != TYPE_EVENT_TIMER) || needsave == true) { - return strInstData.c_str(); + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + saveStream << m_auiEncounter[i] << " "; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + needsave = false; } +} - void Load(const char* chrIn) +uint32 instance_trial_of_the_crusader::GetData(uint32 uiType) +{ + switch(uiType) { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + case TYPE_STAGE: return m_auiEncounter[0]; + case TYPE_BEASTS: return m_auiEncounter[1]; + case TYPE_JARAXXUS: return m_auiEncounter[2]; + case TYPE_CRUSADERS: return m_auiEncounter[3]; + case TYPE_VALKIRIES: return m_auiEncounter[4]; + case TYPE_LICH_KING: return m_auiEncounter[5]; + case TYPE_ANUBARAK: return m_auiEncounter[6]; + case TYPE_COUNTER: return m_auiEncounter[7]; + case TYPE_DEATHS: return m_auiEncounter[8]; + case TYPE_EVENT: return m_auiEncounter[9]; + case TYPE_DIFFICULTY: return Difficulty; + case TYPE_NORTHREND_BEASTS: return m_auiNorthrendBeasts; + case TYPE_EVENT_TIMER: return m_auiEventTimer; + case TYPE_CRUSADERS_COUNT: return m_auiCrusadersCount; + case TYPE_CRUSADERS_DEAD: return m_auiCrusadersDead; + case TYPE_CRUSADERS_ACHIEV_TIMER:return m_auiCrusadersAchievTimer; + case TYPE_CRUSADERS_ACHIEV_FAIL :return m_auiCrusadersAchievFail; + case TYPE_EVENT_NPC: + switch (m_auiEncounter[TYPE_EVENT]) + { + case 110: + case 115: + case 116: + case 140: + case 150: + case 200: + case 205: + case 210: + case 300: + case 305: + case 310: + case 400: + case 666: + case 1010: + case 1180: + case 1999: + case 2000: + case 2030: + case 3000: + case 3001: + case 3060: + case 3061: + case 3090: + case 3091: + case 3100: + case 3110: + case 4000: + case 4010: + case 4015: + case 4040: + case 4050: + case 5000: + case 5005: + case 5020: + case 6000: + case 6005: + case 6010: + m_auiEventNPCId = NPC_TIRION; + break; + case 5010: + case 5030: + case 5040: + case 5050: + case 5060: + case 5070: + case 5080: + m_auiEventNPCId = NPC_LICH_KING_1; + break; + case 130: + case 2020: + case 3080: + case 3051: + case 3071: + case 4020: + m_auiEventNPCId = NPC_RINN; + break; + case 120: + case 2010: + case 3050: + case 3070: + case 3081: + case 4030: + m_auiEventNPCId = NPC_GARROSH; + break; + case 1110: + case 1120: + case 1130: + case 1132: + case 1134: + case 1135: + case 1140: + case 1142: + case 1144: + case 1145: + case 1150: + case 1160: + case 1170: + m_auiEventNPCId = NPC_FIZZLEBANG; + break; + default: + m_auiEventNPCId = NPC_TIRION; + break; + }; + return m_auiEventNPCId; + case DATA_HEALTH_FJOLA: return m_uiDataDamageFjola; + case DATA_HEALTH_EYDIS: return m_uiDataDamageEydis; + } + return 0; +} - OUT_LOAD_INST_DATA(chrIn); +void instance_trial_of_the_crusader::Load(const char* strIn) +{ + if (!strIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4]; + OUT_LOAD_INST_DATA(strIn); - 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; + std::istringstream loadStream(strIn); + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + { + loadStream >> m_auiEncounter[i]; - OUT_LOAD_INST_DATA_COMPLETE; + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } -}; + m_auiEncounter[TYPE_EVENT] = 0; + m_auiEncounter[TYPE_STAGE] = 0; + SetData(TYPE_DEATHS, m_auiEncounter[TYPE_DEATHS]); // Refresh achievement criteria + + OUT_LOAD_INST_DATA_COMPLETE; + +} InstanceData* GetInstanceData_instance_trial_of_the_crusader(Map* pMap) { @@ -190,10 +544,9 @@ InstanceData* GetInstanceData_instance_trial_of_the_crusader(Map* pMap) void AddSC_instance_trial_of_the_crusader() { - Script* newscript; - - newscript = new Script; - newscript->Name = "instance_trial_of_the_crusader"; - newscript->GetInstanceData = &GetInstanceData_instance_trial_of_the_crusader; - newscript->RegisterSelf(); + Script *pNewScript; + pNewScript = new Script; + pNewScript->Name = "instance_trial_of_the_crusader"; + pNewScript->GetInstanceData = &GetInstanceData_instance_trial_of_the_crusader; + pNewScript->RegisterSelf(); } 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 45496c338a..6e8c85faa3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,123 +15,1669 @@ */ /* ScriptData -SDName: trial_of_the_crusader -SD%Complete: 0 -SDComment: -SDCategory: Crusader Coliseum +SDName: Trial Of the crusader +SD%Complete: 60% +SDComment: event script by /dev/rsa +SDCategory: trial_of_the_crusader EndScriptData */ #include "precompiled.h" #include "trial_of_the_crusader.h" -enum +struct _Messages { - SAY_TIRION_RAID_INTRO_LONG = -1649000, - SAY_RAID_TRIALS_INTRO = -1649001, - - // Northrend Beasts - SAY_TIRION_BEAST_1 = -1649002, - SAY_VARIAN_BEAST_1 = -1649003, - SAY_GARROSH_BEAST_1 = -1649004, - SAY_TIRION_BEAST_2 = -1649005, - SAY_TIRION_BEAST_3 = -1649006, - SAY_TIRION_BEAST_SLAY = -1649007, - SAY_TIRION_BEAST_WIPE = -1649008, - - // Jaraxxus Encounter - SAY_TIRION_JARAXXUS_INTRO_1 = -1649009, - SAY_WILFRED_JARAXXUS_INTRO_1 = -1649010, - SAY_WILFRED_JARAXXUS_INTRO_2 = -1649011, - SAY_WILFRED_JARAXXUS_INTRO_3 = -1649012, - SAY_JARAXXUS_JARAXXAS_INTRO_1 = -1649013, - SAY_WILFRED_DEATH = -1649014, - SAY_TIRION_JARAXXUS_INTRO_2 = -1649015, - SAY_TIRION_JARAXXUS_EXIT_1 = -1649016, - SAY_GARROSH_JARAXXUS_EXIT_1 = -1649017, - SAY_VARIAN_JARAXXUS_SLAY = -1649018, - SAY_TIRION_JARAXXUS_EXIT_2 = -1649019, - - // Faction-Champions - SAY_TIRION_PVP_INTRO_1 = -1649020, - SAY_GARROSH_PVP_A_INTRO_1 = -1649021, - SAY_VARIAN_PVP_H_INTRO_1 = -1649022, - SAY_TIRION_PVP_INTRO_2 = -1649023, - SAY_VARIAN_PVP_A_INTRO_2 = -1649024, - SAY_GARROSH_PVP_H_INTRO_2 = -1649025, - SAY_VARIAN_PVP_A_WIN = -1649026, - SAY_GARROSH_PVP_H_WIN = -1649027, - SAY_TIRION_PVP_WIN = -1649028, - - // Twin Valkyrs - SAY_TIRION_TWINS_INTRO = -1649029, - SAY_RAID_INTRO_SHORT = -1649030, - SAY_VARIAN_TWINS_A_WIN = -1649031, - SAY_GARROSH_TWINS_H_WIN = -1649032, - SAY_TIRION_TWINS_WIN = -1649033, - - // Anub'Arak Encounter - SAY_LKING_ANUB_INTRO_1 = -1649034, - SAY_TIRION_ABUN_INTRO_1 = -1649035, - SAY_LKING_ANUB_INTRO_2 = -1649036, - SAY_LKING_ANUB_INTRO_3 = -1649037, - SAY_ANUB_ANUB_INTRO_1 = -1649038, - - NPC_GORMOK = 34796, - NPC_JARAXXUS = 34780, - - GOSSIP_ITEM_START_EVENT1 = -3649000 + AnnounserMessages msgnum; + uint32 id; + bool state; + uint32 encounter; }; -/*###### -## npc_barrett_ramsey -######*/ +static _Messages _GossipMessage[]= +{ + {MSG_BEASTS,GOSSIP_ACTION_INFO_DEF+1,false,TYPE_BEASTS}, + {MSG_JARAXXUS,GOSSIP_ACTION_INFO_DEF+2,false,TYPE_JARAXXUS}, + {MSG_CRUSADERS,GOSSIP_ACTION_INFO_DEF+3,false,TYPE_CRUSADERS}, + {MSG_VALKIRIES,GOSSIP_ACTION_INFO_DEF+4,false,TYPE_VALKIRIES}, + {MSG_LICH_KING,GOSSIP_ACTION_INFO_DEF+5,false,TYPE_ANUBARAK}, +}; -struct MANGOS_DLL_DECL npc_barrett_ramseyAI : public ScriptedAI +enum { - npc_barrett_ramseyAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + NUM_MESSAGES = 5, + SPELL_WILFRED_PORTAL = 68424, + SPELL_JARAXXUS_CHAINS = 67924, + + // Say and Yells + SAY_LKING_ANUB_INTRO_1 = -1649034, + SAY_LKING_ANUB_INTRO_2 = -1649036, + SAY_LKING_ANUB_INTRO_3 = -1649037, + + SAY_WILFRED_JARAXXUS_INTRO_1 = -1649010, + SAY_WILFRED_JARAXXUS_INTRO_2 = -1649011, + SAY_WILFRED_JARAXXUS_INTRO_3 = -1649012, + + SAY_JARAXXUS_JARAXXAS_INTRO_1 = -1649013, + SAY_WILFRED_DEATH = -1649014, + + SAY_TIRION_RAID_INTRO_LONG = -1649000, + + SAY_TIRION_BEAST_1 = -1649002, + SAY_TIRION_BEAST_2 = -1649005, + SAY_TIRION_BEAST_3 = -1649006, + SAY_TIRION_BEAST_SLAY = -1649007, + SAY_TIRION_BEAST_WIPE = -1649008, + SAY_TIRION_JARAXXUS_INTRO_1 = -1649009, + SAY_TIRION_JARAXXUS_INTRO_2 = -1649015, + SAY_TIRION_JARAXXUS_EXIT_1 = -1649016, + SAY_TIRION_JARAXXUS_EXIT_2 = -1649019, + SAY_TIRION_PVP_INTRO_1 = -1649020, + SAY_TIRION_PVP_INTRO_2 = -1649023, + SAY_TIRION_PVP_WIN = -1649028, + SAY_TIRION_TWINS_INTRO = -1649029, + SAY_TIRION_TWINS_WIN = -1649033, + SAY_TIRION_ABUN_INTRO_1 = -1649035, + TIRION_SAY_EPILOGUE = -1649075, + + SAY_GARROSH_BEAST_1 = -1649004, + SAY_GARROSH_JARAXXUS_EXIT_1 = -1649017, + SAY_GARROSH_PVP_A_INTRO_1 = -1649021, + SAY_GARROSH_PVP_A_INTRO_2 = -1649025, + SAY_GARROSH_PVP_H_WIN = -1649027, + SAY_GARROSH_TWINS_H_WIN = -1649032, + + SAY_RAID_INTRO_SHORT = -1649030, + + SAY_VARIAN_JARAXXUS_SLAY = -1649018, + SAY_VARIAN_PVP_H_INTRO_1 = -1649022, + SAY_VARIAN_PVP_H_INTRO_2 = -1649024, + SAY_VARIAN_PVP_A_WIN = -1649026, + SAY_VARIAN_TWINS_A_WIN = -1649031, +}; + +struct MANGOS_DLL_DECL npc_toc_announcerAI : public ScriptedAI +{ + npc_toc_announcerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 DelayTimer; + uint32 substage; + + uint32 WormsTimer; + uint32 IcehowlTimer; + + void Reset() + { + if (!m_pInstance) + return; - void Reset() {} + WormsTimer = 150000; + IcehowlTimer = 150000; + + m_pInstance->SetData(TYPE_STAGE, 0); + DelayTimer = 0; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (Creature *pHorde = GetClosestCreatureWithEntry(m_creature, NPC_THRALL, 300.0f)) + pHorde->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (Creature *pAlly = GetClosestCreatureWithEntry(m_creature, NPC_PROUDMOORE, 300.0f)) + pAlly->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + } + + void AttackStart(Unit *who) + { + return; + } - void StartEvent(Player* pPlayer) + void UpdateAI(const uint32 diff) { - // code starting the event here + if (!m_pInstance) + return; + + if (DelayTimer < diff) + { + switch (m_pInstance->GetData(TYPE_STAGE)) + { + case 0: + break; + case 1: + if (m_bIsHeroic) + { + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == GORMOK_IN_PROGRESS) + { + if (WormsTimer <= diff) + { + m_pInstance->SetData(TYPE_STAGE,2); + m_pInstance->SetData(TYPE_EVENT,200); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS,SNAKES_IN_PROGRESS); + m_pInstance->SetData(TYPE_BEASTS,IN_PROGRESS); + } + else + WormsTimer -= diff; + } + } + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == GORMOK_DONE) + { + m_pInstance->SetData(TYPE_STAGE,2); + m_pInstance->SetData(TYPE_EVENT,200); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS,SNAKES_IN_PROGRESS); + m_pInstance->SetData(TYPE_BEASTS,IN_PROGRESS); + } + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == FAIL) + { + m_pInstance->SetData(TYPE_STAGE,0); + m_pInstance->SetData(TYPE_EVENT,666); + m_pInstance->SetData(TYPE_BEASTS, NOT_STARTED); + m_creature->SetDeathState(JUST_DIED); + m_creature->Respawn(); + } + break; + case 2: + if (m_bIsHeroic) + { + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) != ICEHOWL_IN_PROGRESS) + { + if (IcehowlTimer <= diff) + { + m_pInstance->SetData(TYPE_STAGE,3); + m_pInstance->SetData(TYPE_EVENT,300); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS,ICEHOWL_IN_PROGRESS); + m_pInstance->SetData(TYPE_BEASTS,IN_PROGRESS); + } + else + IcehowlTimer -= diff; + } + } + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == SNAKES_DONE) + { + m_pInstance->SetData(TYPE_STAGE,3); + m_pInstance->SetData(TYPE_EVENT,300); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, ICEHOWL_IN_PROGRESS); + m_pInstance->SetData(TYPE_BEASTS, IN_PROGRESS); + } + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == FAIL) + { + m_pInstance->SetData(TYPE_STAGE,0); + m_pInstance->SetData(TYPE_EVENT,666); + m_pInstance->SetData(TYPE_BEASTS, NOT_STARTED); + m_creature->SetDeathState(JUST_DIED); + m_creature->Respawn(); + } + break; + case 3: + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == ICEHOWL_DONE) + { + m_pInstance->SetData(TYPE_STAGE,0); + m_pInstance->SetData(TYPE_BEASTS, DONE); + m_pInstance->SetData(TYPE_EVENT,400); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS, DONE); + } + if (m_pInstance->GetData(TYPE_NORTHREND_BEASTS) == FAIL) + { + m_pInstance->SetData(TYPE_STAGE,0); + m_pInstance->SetData(TYPE_EVENT,666); + m_pInstance->SetData(TYPE_BEASTS, NOT_STARTED); + m_creature->SetDeathState(JUST_DIED); + m_creature->Respawn(); + }; + break; + case 4: + break; + case 5: + break; + case 6: + if (m_pInstance->GetData(TYPE_CRUSADERS_COUNT) == 0 && m_pInstance->GetData(TYPE_CRUSADERS) == IN_PROGRESS) + { + m_pInstance->SetData(TYPE_STAGE, 0); + m_pInstance->SetData(TYPE_CRUSADERS, DONE); + m_pInstance->SetData(TYPE_EVENT, 3100); + } + break; + case 7: + if (m_pInstance->GetData(TYPE_VALKIRIES) == DONE) + { + m_pInstance->SetData(TYPE_STAGE, 0); + m_pInstance->SetData(TYPE_EVENT, 4020); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + if (m_pInstance->GetData(TYPE_VALKIRIES) == FAIL) + { + m_pInstance->SetData(TYPE_STAGE, 0); + m_pInstance->SetData(TYPE_EVENT, 0); + } + break; + case 8: + break; + case 9: + if (m_pInstance->GetData(TYPE_ANUBARAK) == DONE) + { + m_pInstance->SetData(TYPE_STAGE, 10); + m_pInstance->SetData(TYPE_EVENT, 6000); + } + if (m_pInstance->GetData(TYPE_ANUBARAK) == FAIL) + { + m_pInstance->SetData(TYPE_STAGE, 0); + m_pInstance->SetData(TYPE_EVENT, 0); + } + break; + case 10: + //m_creature->ForcedDespawn(); + break; + } + } + else DelayTimer -= diff; } }; -bool GossipHello_npc_barrett_ramsey(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_toc_announcer(Creature* pCreature) +{ + return new npc_toc_announcerAI(pCreature); +} + +bool GossipHello_npc_toc_announcer(Player* pPlayer, Creature* pCreature) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START_EVENT1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + ScriptedInstance* m_pInstance; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + char const* _message; + uint8 i; + + if (!m_pInstance) + return false; + + if (pPlayer->IsInCombat() || m_pInstance->IsEncounterInProgress() || m_pInstance->GetData(TYPE_EVENT)) + return true; + + switch (pPlayer->GetSession()->GetSessionDbcLocale()) + { + case LOCALE_esES: + _message = "¡Estamos listos!"; + break; + case LOCALE_esMX: + _message = "¡Estamos listos!"; + break; + case LOCALE_ruRU: + _message = "Всегда готовы!"; + break; + case LOCALE_enUS: + case LOCALE_koKR: + case LOCALE_frFR: + case LOCALE_deDE: + case LOCALE_zhCN: + case LOCALE_zhTW: + default: + _message = "We are ready!"; + break; + }; + + for (i = 0; i < NUM_MESSAGES; i++) + { + if (!_GossipMessage[i].state && (m_pInstance->GetData(_GossipMessage[i].encounter) != DONE )) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, _message, GOSSIP_SENDER_MAIN,_GossipMessage[i].id); + break; + } + if (_GossipMessage[i].state && m_pInstance->GetData(_GossipMessage[i].encounter) == DONE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, _message, GOSSIP_SENDER_MAIN,_GossipMessage[i].id); + break; + } + }; + + pPlayer->SEND_GOSSIP_MENU(_GossipMessage[i].msgnum, pCreature->GetObjectGuid()); + return true; } -bool GossipSelect_npc_barrett_ramsey(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_toc_announcer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + ScriptedInstance* pInstance; + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if (!pInstance) + return false; + +pPlayer->CLOSE_GOSSIP_MENU(); + +switch(uiAction) { + case GOSSIP_ACTION_INFO_DEF+1: + if (pInstance->GetData(TYPE_BEASTS) != DONE) + { + pInstance->SetData(TYPE_EVENT,110); + pInstance->SetData(TYPE_NORTHREND_BEASTS,NOT_STARTED); + pInstance->SetData(TYPE_BEASTS,IN_PROGRESS); + }; + break; + case GOSSIP_ACTION_INFO_DEF+2: + if (pInstance->GetData(TYPE_JARAXXUS) != DONE) + pInstance->SetData(TYPE_EVENT,1010); + + break; + case GOSSIP_ACTION_INFO_DEF+3: + if (pInstance->GetData(TYPE_CRUSADERS) != DONE) + { + if (pPlayer->GetTeam() == ALLIANCE) + pInstance->SetData(TYPE_EVENT,3000); + else + pInstance->SetData(TYPE_EVENT,3001); + }; + break; + case GOSSIP_ACTION_INFO_DEF+4: + if (pInstance->GetData(TYPE_VALKIRIES) != DONE) + pInstance->SetData(TYPE_EVENT,4000); + + break; + case GOSSIP_ACTION_INFO_DEF+5: + Map* pMap = pCreature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + if (!pPlayer) + continue; + float x, y, z; + pPlayer->GetPosition(x, y, z); + pPlayer->MonsterMoveToDestination(x, y, z + 10.0f, M_PI_F, 10.0f, 0.0f, true); + } + if (GameObject* pGoFloor = pInstance->GetSingleGameObjectFromStorage(GO_ARGENT_COLISEUM_FLOOR)) + { + pGoFloor->SetUInt32Value(GAMEOBJECT_DISPLAYID,9060); + pGoFloor->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_NODESPAWN); + pGoFloor->SetUInt32Value(GAMEOBJECT_BYTES_1,8449); + } + pCreature->CastSpell(pCreature,69016,false); + + Creature* pTemp = pInstance->GetSingleCreatureFromStorage(NPC_ANUBARAK); + + if (!pTemp || !pTemp->isAlive()) + pCreature->SummonCreature(NPC_ANUBARAK, SpawnLoc[19].x, SpawnLoc[19].y, SpawnLoc[19].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + + if (pCreature->GetVisibility() == VISIBILITY_ON) + pCreature->SetVisibility(VISIBILITY_OFF); + + break; +}; + +return true; +} + +struct MANGOS_DLL_DECL boss_lich_king_tocAI : public ScriptedAI +{ + boss_lich_king_tocAI(Creature *pCreature) : ScriptedAI(pCreature) { - pPlayer->CLOSE_GOSSIP_MENU(); - if (npc_barrett_ramseyAI* pBarrettAI = dynamic_cast(pCreature->AI())) - pBarrettAI->StartEvent(pPlayer); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + WayPointList.clear(); + JustRespawned(); } - return true; + ScriptedInstance* m_pInstance; + uint32 UpdateTimer; + uint32 event_state_lich_king; + bool Event; + bool MovementStarted; + std::list WayPointList; + std::list::iterator WayPoint; + uint32 WalkTimer; + bool IsWalking; + ObjectGuid m_uiPortalGuid; + + void Reset() + { + UpdateTimer = 0; + event_state_lich_king = 0; + Event = false; + MovementStarted = false; + m_creature->SetRespawnDelay(DAY); + if (Creature* pPortal = m_creature->SummonCreature(NPC_TRIGGER, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME)) + { + pPortal->SetRespawnDelay(DAY); + pPortal->CastSpell(pPortal, 51807, false); + pPortal->SetDisplayId(17612); + m_uiPortalGuid = pPortal->GetObjectGuid(); + } + if (m_pInstance) + m_pInstance->SetData(TYPE_LICH_KING,IN_PROGRESS); + } + + Creature* GetCreatureFromGuid(ObjectGuid m_uiGuid) + { + if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_uiGuid)) + return pCreature; + + return NULL; + } + + void AttackStart(Unit *who) + { + return; + } + + void JustRespawned() override + { + Reset(); + } + + void StartMovement() + { + if(!WayPointList.empty() || MovementStarted) + return; + + AddWaypoint(0, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z); + AddWaypoint(1, SpawnLoc[18].x, SpawnLoc[18].y, SpawnLoc[18].z); + AddWaypoint(2, SpawnLoc[18].x, SpawnLoc[18].y, SpawnLoc[18].z); + m_creature->SetWalk(true); + WayPoint = WayPointList.begin(); + MovementStarted = true; + IsWalking = true; + WalkTimer = 200; + event_state_lich_king = 1; + UpdateTimer = m_pInstance->GetData(TYPE_EVENT_TIMER); + } + + void AddWaypoint(uint32 id, float x, float y, float z) + { + WayPoints wp(id, x, y, z); + WayPointList.push_back(wp); + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EVENT_NPC) != NPC_LICH_KING_1) + return; + + if (!MovementStarted) + StartMovement(); + + if (IsWalking && WalkTimer) + { + if (WalkTimer <= diff) + { + if (WayPoint != WayPointList.end()) + { + m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); + WalkTimer = 0; + } + } + else + WalkTimer -= diff; + } + + UpdateTimer = m_pInstance->GetData(TYPE_EVENT_TIMER); + + if (UpdateTimer <= diff) + { + switch (m_pInstance->GetData(TYPE_EVENT)) + { + case 5010: + DoScriptText(SAY_LKING_ANUB_INTRO_1, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,5020); + break; + case 5030: + DoScriptText(SAY_LKING_ANUB_INTRO_2, m_creature); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,5040); + break; + case 5040: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + UpdateTimer = 1000; + m_pInstance->SetData(TYPE_EVENT,5050); + break; + case 5050: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + UpdateTimer = 9000; + m_pInstance->SetData(TYPE_EVENT,5060); + break; + case 5060: + if (Event) + { + DoScriptText(SAY_LKING_ANUB_INTRO_3, m_creature); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + UpdateTimer = 2500; + m_pInstance->SetData(TYPE_EVENT,5070); + } + break; + case 5070: + { + m_creature->CastSpell(m_creature,68198,false); + Map* pMap = m_creature->GetMap(); + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Unit* pPlayer = itr->getSource(); + if (!pPlayer) + continue; + + float x, y, z; + pPlayer->GetPosition(x, y, z); + pPlayer->MonsterMoveToDestination(x, y, z + 10.0f, M_PI_F, 10.0f, 0.0f, true); + } + UpdateTimer = 1500; + m_pInstance->SetData(TYPE_EVENT,5080); + break; + } + case 5080: + if (GameObject* pGoFloor = m_pInstance->GetSingleGameObjectFromStorage(GO_ARGENT_COLISEUM_FLOOR)) + { + pGoFloor->SetUInt32Value(GAMEOBJECT_DISPLAYID,9060); + pGoFloor->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_NODESPAWN); + pGoFloor->SetUInt32Value(GAMEOBJECT_BYTES_1,8449); + } + + m_creature->CastSpell(m_creature,69016,false); + + if(m_pInstance) + m_pInstance->SetData(TYPE_LICH_KING,DONE); + + if (Creature *pAnubarak = m_creature->SummonCreature(NPC_ANUBARAK, SpawnLoc[19].x, SpawnLoc[19].y, SpawnLoc[19].z, 3.14f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME)) + pAnubarak->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_pInstance->SetData(TYPE_STAGE,9); + Event=false; + m_creature->ForcedDespawn(); + + if (Creature* pPortal = GetCreatureFromGuid(m_uiPortalGuid)) + pPortal->ForcedDespawn(); + + m_pInstance->SetData(TYPE_EVENT,0); + UpdateTimer = 20000; + break; + } + } + else + UpdateTimer -= diff; + + m_pInstance->SetData(TYPE_EVENT_TIMER, UpdateTimer); + } + + void MovementInform(uint32 type, uint32 id) + { + if (m_pInstance) + { + if (id == 2) + { + Event = true; + } + } + if (type != POINT_MOTION_TYPE) + return; + + if (WayPoint->id != id) + return; + + ++WayPoint; + WalkTimer = 200; + } +}; + +CreatureAI* GetAI_boss_lich_king_toc(Creature* pCreature) +{ + return new boss_lich_king_tocAI(pCreature); +}; + +struct MANGOS_DLL_DECL npc_fizzlebang_tocAI : public ScriptedAI +{ + npc_fizzlebang_tocAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (BSWScriptedInstance*)m_creature->GetInstanceData(); + Reset(); + } + + BSWScriptedInstance* m_pInstance; + uint32 UpdateTimer; + ObjectGuid m_uiPortalGuid; + ObjectGuid m_uiTriggerGuid; + + Creature* GetCreatureFromGuid(ObjectGuid m_uiGuid) + { + if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_uiGuid)) + return pCreature; + + return NULL; + } + + void JustDied(Unit* pKiller) override + { + m_pInstance->SetData(TYPE_EVENT, 1179); + + if (Creature* pPortal = GetCreatureFromGuid(m_uiPortalGuid)) + pPortal->ForcedDespawn(); + + m_creature->ForcedDespawn(5000); + } + + void Reset() + { + m_creature->SetRespawnDelay(DAY); + m_creature->GetMotionMaster()->MovePoint(1, SpawnLoc[27].x, SpawnLoc[27].y, SpawnLoc[27].z); + m_uiPortalGuid.Clear(); + } + + void UpdateAI(const uint32 diff) + { + if(!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EVENT_NPC) != NPC_FIZZLEBANG) + return; + + UpdateTimer = m_pInstance->GetData(TYPE_EVENT_TIMER); + if(UpdateTimer <= diff) + { + switch(m_pInstance->GetData(TYPE_EVENT)) + { + case 1110: + m_pInstance->SetData(TYPE_EVENT, 1120); + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_JARAXXUS,IN_PROGRESS); + break; + case 1120: + DoScriptText(SAY_WILFRED_JARAXXUS_INTRO_1, m_creature); + m_pInstance->SetData(TYPE_EVENT, 1130); + UpdateTimer = 12000; + break; + case 1130: + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->HandleEmoteCommand(EMOTE_STATE_SPELL_CHANNEL_OMNI); + + if (Creature* pPortal = m_creature->SummonCreature(NPC_WILFRED_PORTAL, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 5, TEMPSUMMON_MANUAL_DESPAWN, 5000)) + { + pPortal->SetRespawnDelay(DAY); + pPortal->SetDisplayId(22862); + pPortal->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.5f); + m_uiPortalGuid = pPortal->GetObjectGuid(); + } + + DoScriptText(SAY_WILFRED_JARAXXUS_INTRO_2, m_creature); + m_pInstance->SetData(TYPE_EVENT, 1132); + UpdateTimer = 4000; + break; + case 1132: + m_creature->GetMotionMaster()->MovementExpired(); + m_pInstance->SetData(TYPE_EVENT, 1134); + UpdateTimer = 1000; + break; + case 1134: + if (Creature* pPortal = GetCreatureFromGuid(m_uiPortalGuid)) + pPortal->ForcedDespawn(16000); + + if (Creature* pTrigger = m_creature->SummonCreature(NPC_TRIGGER, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 5.0f, TEMPSUMMON_MANUAL_DESPAWN, 5000)) + { + pTrigger->SetDisplayId(17612); + pTrigger->CastSpell(pTrigger, SPELL_WILFRED_PORTAL, false); + pTrigger->SetRespawnDelay(DAY); + pTrigger->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f); + m_uiTriggerGuid = pTrigger->GetObjectGuid(); + } + + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SPELLCAST_OMNI); + UpdateTimer = 4000; + m_pInstance->SetData(TYPE_EVENT, 1135); + break; + case 1135: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SPELLCAST_OMNI); + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_EVENT, 1140); + break; + case 1140: + m_pInstance->SetData(TYPE_STAGE,4); + m_creature->SummonCreature(NPC_JARAXXUS, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JARAXXUS)) + { + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTemp->SetWalk(true); + pTemp->GetMotionMaster()->MovePoint(1, SpawnLoc[28].x, SpawnLoc[28].y, SpawnLoc[28].z); + } + m_pInstance->SetData(TYPE_EVENT, 1142); + UpdateTimer = 3000; + break; + case 1142: + if (Creature* pTrigger = GetCreatureFromGuid(m_uiTriggerGuid)) + pTrigger->RemoveAurasDueToSpell(SPELL_WILFRED_PORTAL); + + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JARAXXUS)) + pTemp->SetFacingToObject(m_creature); + + DoScriptText(SAY_WILFRED_JARAXXUS_INTRO_3, m_creature); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_POINT); + m_pInstance->SetData(TYPE_EVENT, 1144); + UpdateTimer = 3000; + break; + case 1144: + if (Creature* pTrigger = GetCreatureFromGuid(m_uiTriggerGuid)) + pTrigger->ForcedDespawn(); + + m_pInstance->SetData(TYPE_EVENT, 1145); + UpdateTimer = 9000; + break; + case 1145: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JARAXXUS)) + { + DoScriptText(SAY_JARAXXUS_JARAXXAS_INTRO_1, pTemp); + pTemp->HandleEmoteCommand(EMOTE_ONESHOT_POINT); + } + + m_pInstance->SetData(TYPE_EVENT, 1150); + UpdateTimer = 5000; + break; + case 1150: + DoScriptText(SAY_WILFRED_DEATH, m_creature); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JARAXXUS)) + pTemp->CastSpell(m_creature, 66532, false); + + m_pInstance->SetData(TYPE_EVENT, 1160); + UpdateTimer = 4000; + break; + case 1160: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_JARAXXUS)) + pTemp->SetInCombatWithZone(); + + UpdateTimer = 1000; + break; + } + } + else + UpdateTimer -= diff; + + m_pInstance->SetData(TYPE_EVENT_TIMER, UpdateTimer); + } +}; + +CreatureAI* GetAI_npc_fizzlebang_toc(Creature* pCreature) +{ + return new npc_fizzlebang_tocAI(pCreature); } -CreatureAI* GetAI_npc_barrett_ramsey(Creature* pCreature) +struct MANGOS_DLL_DECL npc_tirion_tocAI : public ScriptedAI { - return new npc_barrett_ramseyAI(pCreature); + npc_tirion_tocAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 UpdateTimer; + uint32 crusader[12]; + uint8 crusaderscount; + + void Reset() + { + crusaderscount = 0; + memset(&crusader, 0, sizeof(crusader)); + } + + void AttackStart(Unit *who) + { + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + if (m_pInstance->GetData(TYPE_EVENT_NPC) != NPC_TIRION) + return; + + if (m_pInstance->GetData(TYPE_STAGE) == 6) // Crusaders + if (m_pInstance->GetData(TYPE_CRUSADERS) == IN_PROGRESS) + if (m_pInstance->GetData(TYPE_CRUSADERS_DEAD)) + m_pInstance->SetData(TYPE_CRUSADERS_ACHIEV_TIMER, diff); + + UpdateTimer = m_pInstance->GetData(TYPE_EVENT_TIMER); + + if (UpdateTimer <= diff) + { + switch (m_pInstance->GetData(TYPE_EVENT)) + { + case 110: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); + DoScriptText(SAY_TIRION_RAID_INTRO_LONG, m_creature); + UpdateTimer = 22000; + m_pInstance->SetData(TYPE_EVENT,130); + break; + case 140: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); + DoScriptText(SAY_TIRION_BEAST_1, m_creature); + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,150); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 150: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + if (m_pInstance->GetData(TYPE_BEASTS) != DONE) + { + m_creature->SummonCreature(NPC_GORMOK, SpawnLoc[26].x, SpawnLoc[26].y, SpawnLoc[26].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_GORMOK)) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + pTemp->SetInCombatWithZone(); + } + } + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,160); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + m_pInstance->SetData(TYPE_STAGE,1); + m_pInstance->SetData(TYPE_BEASTS,IN_PROGRESS); + break; + case 200: + DoScriptText(SAY_TIRION_BEAST_2, m_creature); + UpdateTimer = 4000; + m_pInstance->SetData(TYPE_EVENT,205); + break; + case 205: + UpdateTimer = 8000; + m_pInstance->SetData(TYPE_EVENT,210); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 210: + if (m_pInstance->GetData(TYPE_BEASTS) != DONE) + { + m_creature->SummonCreature(NPC_DREADSCALE, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + m_creature->SummonCreature(NPC_ACIDMAW, SpawnLoc[4].x, SpawnLoc[4].y, SpawnLoc[4].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE)) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + pTemp->SetInCombatWithZone(); + } + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW)) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + pTemp->SetInCombatWithZone(); + } + } + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,220); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 300: + DoScriptText(SAY_TIRION_BEAST_3, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,305); + break; + case 305: + UpdateTimer = 8000; + m_pInstance->SetData(TYPE_EVENT,310); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 310: + if (m_pInstance->GetData(TYPE_BEASTS) != DONE) + { + m_creature->SummonCreature(NPC_ICEHOWL, SpawnLoc[26].x, SpawnLoc[26].y, SpawnLoc[26].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_ICEHOWL)) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + pTemp->SetInCombatWithZone(); + } + } + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,320); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 400: + DoScriptText(SAY_TIRION_BEAST_SLAY, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,0); + break; + case 666: + DoScriptText(SAY_TIRION_BEAST_WIPE, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,0); + m_pInstance->SetData(TYPE_NORTHREND_BEASTS,NOT_STARTED); + break; + case 1010: + DoScriptText(SAY_TIRION_JARAXXUS_INTRO_1, m_creature); + UpdateTimer = 5000; + m_creature->SummonCreature(NPC_FIZZLEBANG, SpawnLoc[21].x, SpawnLoc[21].y, SpawnLoc[21].z, 2, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + m_pInstance->SetData(TYPE_EVENT,1110); + break; + case 1179: + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT, 1180); + break; + case 1180: + DoScriptText(SAY_TIRION_JARAXXUS_INTRO_2, m_creature); + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_EVENT,0); + break; + + case 1999: + UpdateTimer = 6000; + m_pInstance->SetData(TYPE_EVENT,2000); + break; + case 2000: + DoScriptText(SAY_TIRION_JARAXXUS_EXIT_1, m_creature); + UpdateTimer = 15000; + m_pInstance->SetData(TYPE_EVENT,2010); + break; + case 2030: + DoScriptText(SAY_TIRION_JARAXXUS_EXIT_2, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,0); + break; + case 3000: + DoScriptText(SAY_TIRION_PVP_INTRO_1, m_creature); + UpdateTimer = 8000; + m_pInstance->SetData(TYPE_EVENT,3050); + break; + case 3001: + DoScriptText(SAY_TIRION_PVP_INTRO_1, m_creature); + UpdateTimer = 8000; + m_pInstance->SetData(TYPE_EVENT,3051); + break; + case 3060: + DoScriptText(SAY_TIRION_PVP_INTRO_2, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,3070); + break; + case 3061: + DoScriptText(SAY_TIRION_PVP_INTRO_2, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,3071); + break; + //Summoning crusaders + case 3091: + m_pInstance->SetData(TYPE_STAGE,6); + if (m_pInstance->GetData(TYPE_DIFFICULTY) == RAID_DIFFICULTY_25MAN_NORMAL || m_pInstance->GetData(TYPE_DIFFICULTY) == RAID_DIFFICULTY_25MAN_HEROIC) + { + crusaderscount = 12; + switch (urand(0,3)) + { // Healers, 3 in 25-mode + case 0: + crusader[0] = NPC_CRUSADER_1_1; + crusader[1] = NPC_CRUSADER_1_12; + crusader[2] = NPC_CRUSADER_1_13; + break; + case 1: + crusader[0] = NPC_CRUSADER_1_1; + crusader[1] = NPC_CRUSADER_1_2; + crusader[2] = NPC_CRUSADER_1_13; + break; + case 2: + crusader[0] = NPC_CRUSADER_1_1; + crusader[1] = NPC_CRUSADER_1_2; + crusader[2] = NPC_CRUSADER_1_12; + break; + case 3: + crusader[0] = NPC_CRUSADER_1_2; + crusader[1] = NPC_CRUSADER_1_12; + crusader[2] = NPC_CRUSADER_1_13; + break; + } + switch (urand(0,5)) + { // Random melee DD, 2 in 25-mode + case 0: + crusader[3] = NPC_CRUSADER_1_3; + crusader[4] = NPC_CRUSADER_1_4; + break; + case 1: + crusader[3] = NPC_CRUSADER_1_3; + crusader[4] = NPC_CRUSADER_1_5; + break; + case 2: + crusader[3] = NPC_CRUSADER_1_3; + crusader[4] = NPC_CRUSADER_1_6; + break; + case 3: + crusader[3] = NPC_CRUSADER_1_4; + crusader[4] = NPC_CRUSADER_1_5; + break; + case 4: + crusader[3] = NPC_CRUSADER_1_4; + crusader[4] = NPC_CRUSADER_1_6; + break; + case 5: + crusader[3] = NPC_CRUSADER_1_5; + crusader[4] = NPC_CRUSADER_1_6; + break; + } + switch (urand(0,3)) + { // Random magic DD, 3 in 25-mode + case 0: + crusader[5] = NPC_CRUSADER_1_7; + crusader[6] = NPC_CRUSADER_1_8; + crusader[7] = NPC_CRUSADER_1_11; + break; + case 1: + crusader[5] = NPC_CRUSADER_1_7; + crusader[6] = NPC_CRUSADER_1_8; + crusader[7] = NPC_CRUSADER_1_14; + break; + case 2: + crusader[5] = NPC_CRUSADER_1_8; + crusader[6] = NPC_CRUSADER_1_11; + crusader[7] = NPC_CRUSADER_1_14; + break; + case 3: + crusader[5] = NPC_CRUSADER_1_7; + crusader[6] = NPC_CRUSADER_1_11; + crusader[7] = NPC_CRUSADER_1_14; + break; + } + crusader[8] = NPC_CRUSADER_1_9; //Hunter+warlock + crusader[9] = NPC_CRUSADER_1_10; + crusader[10] = NPC_CRUSADER_0_1; + crusader[11] = NPC_CRUSADER_0_2; + } + else + { + crusaderscount = 6; + switch (urand(0,5)) + { // Healers, 2 in 10-mode + case 0: + crusader[0] = NPC_CRUSADER_1_1; + crusader[1] = NPC_CRUSADER_1_12; + break; + case 1: + crusader[0] = NPC_CRUSADER_1_1; + crusader[1] = NPC_CRUSADER_1_2; + break; + case 2: + crusader[0] = NPC_CRUSADER_1_2; + crusader[1] = NPC_CRUSADER_1_12; + break; + case 3: + crusader[0] = NPC_CRUSADER_1_1; + crusader[1] = NPC_CRUSADER_1_13; + break; + case 4: + crusader[0] = NPC_CRUSADER_1_2; + crusader[1] = NPC_CRUSADER_1_13; + break; + case 5: + crusader[0] = NPC_CRUSADER_1_12; + crusader[1] = NPC_CRUSADER_1_13; + break; + } + switch (urand(0,5)) + { // Random melee DD, 2 in 10-mode + case 0: + crusader[3] = NPC_CRUSADER_1_3; + crusader[2] = NPC_CRUSADER_1_4; + break; + case 1: + crusader[3] = NPC_CRUSADER_1_3; + crusader[2] = NPC_CRUSADER_1_5; + break; + case 2: + crusader[3] = NPC_CRUSADER_1_3; + crusader[2] = NPC_CRUSADER_1_6; + break; + case 3: + crusader[3] = NPC_CRUSADER_1_4; + crusader[2] = NPC_CRUSADER_1_5; + break; + case 4: + crusader[3] = NPC_CRUSADER_1_4; + crusader[2] = NPC_CRUSADER_1_6; + break; + case 5: + crusader[3] = NPC_CRUSADER_1_5; + crusader[2] = NPC_CRUSADER_1_6; + break; + } + switch (urand(0,5)) + { // Random magic DD, 2 in 10-mode + case 0: + crusader[4] = NPC_CRUSADER_1_7; + crusader[5] = NPC_CRUSADER_1_8; + break; + case 1: + crusader[5] = NPC_CRUSADER_1_7; + crusader[4] = NPC_CRUSADER_1_14; + break; + case 2: + crusader[5] = NPC_CRUSADER_1_7; + crusader[4] = NPC_CRUSADER_1_11; + break; + case 3: + crusader[5] = NPC_CRUSADER_1_8; + crusader[4] = NPC_CRUSADER_1_11; + break; + case 4: + crusader[5] = NPC_CRUSADER_1_8; + crusader[4] = NPC_CRUSADER_1_14; + break; + case 5: + crusader[5] = NPC_CRUSADER_1_11; + crusader[4] = NPC_CRUSADER_1_14; + break; + } + } + for(uint8 i = 0; i < crusaderscount; ++i) + { + m_creature->SummonCreature(crusader[i], SpawnLoc[i+2].x, SpawnLoc[i+2].y, SpawnLoc[i+2].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(crusader[i])) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + } + } + m_pInstance->SetData(TYPE_CRUSADERS_COUNT,crusaderscount); + m_pInstance->SetData(TYPE_CRUSADERS_DEAD, 0); + m_pInstance->SetData(TYPE_CRUSADERS_ACHIEV_TIMER, 60000); + m_pInstance->SetData(TYPE_CRUSADERS_ACHIEV_FAIL, 0); + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_EVENT,0); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + m_pInstance->SetData(TYPE_CRUSADERS,IN_PROGRESS); + break; + //summoning crusaders + case 3090: + m_pInstance->SetData(TYPE_STAGE,6); + if (m_pInstance->GetData(TYPE_DIFFICULTY) == RAID_DIFFICULTY_25MAN_NORMAL || m_pInstance->GetData(TYPE_DIFFICULTY) == RAID_DIFFICULTY_25MAN_HEROIC) + { + crusaderscount = 12; + switch (urand(0,3)) + { // Healers, 3 in 25-mode + case 0: + crusader[0] = NPC_CRUSADER_2_1; + crusader[1] = NPC_CRUSADER_2_12; + crusader[2] = NPC_CRUSADER_2_13; + break; + case 1: + crusader[0] = NPC_CRUSADER_2_1; + crusader[1] = NPC_CRUSADER_2_2; + crusader[2] = NPC_CRUSADER_2_13; + break; + case 2: + crusader[0] = NPC_CRUSADER_2_1; + crusader[1] = NPC_CRUSADER_2_2; + crusader[2] = NPC_CRUSADER_2_12; + break; + case 3: + crusader[0] = NPC_CRUSADER_2_2; + crusader[1] = NPC_CRUSADER_2_12; + crusader[2] = NPC_CRUSADER_2_13; + break; + } + switch (urand(0,5)) + { // Random melee DD, 2 in 25-mode + case 0: + crusader[3] = NPC_CRUSADER_2_3; + crusader[4] = NPC_CRUSADER_2_4; + break; + case 1: + crusader[3] = NPC_CRUSADER_2_3; + crusader[4] = NPC_CRUSADER_2_5; + break; + case 2: + crusader[3] = NPC_CRUSADER_2_3; + crusader[4] = NPC_CRUSADER_2_6; + break; + case 3: + crusader[3] = NPC_CRUSADER_2_4; + crusader[4] = NPC_CRUSADER_2_5; + break; + case 4: crusader[3] = NPC_CRUSADER_2_4; + crusader[4] = NPC_CRUSADER_2_6; + break; + case 5: + crusader[3] = NPC_CRUSADER_2_5; + crusader[4] = NPC_CRUSADER_2_6; + break; + } + + switch (urand(0,3)) + { // Random magic DD, 3 in 25-mode + case 0: + crusader[5] = NPC_CRUSADER_2_7; + crusader[6] = NPC_CRUSADER_2_8; + crusader[7] = NPC_CRUSADER_2_11; + break; + case 1: + crusader[5] = NPC_CRUSADER_2_7; + crusader[6] = NPC_CRUSADER_2_8; + crusader[7] = NPC_CRUSADER_2_14; + break; + case 2: + crusader[5] = NPC_CRUSADER_2_8; + crusader[6] = NPC_CRUSADER_2_11; + crusader[7] = NPC_CRUSADER_2_14; + break; + case 3: + crusader[5] = NPC_CRUSADER_2_7; + crusader[6] = NPC_CRUSADER_2_11; + crusader[7] = NPC_CRUSADER_2_14; + break; + } + crusader[8] = NPC_CRUSADER_2_9; //Hunter+warlock + crusader[9] = NPC_CRUSADER_2_10; + crusader[10] = NPC_CRUSADER_0_1; + crusader[11] = NPC_CRUSADER_0_2; + } + else + { + crusaderscount = 6; + switch (urand(0,5)) + { // Healers, 2 in 10-mode + case 0: + crusader[0] = NPC_CRUSADER_2_1; + crusader[1] = NPC_CRUSADER_2_12; + break; + case 1: + crusader[0] = NPC_CRUSADER_2_1; + crusader[1] = NPC_CRUSADER_2_2; + break; + case 2: + crusader[0] = NPC_CRUSADER_2_2; + crusader[1] = NPC_CRUSADER_2_12; + break; + case 3: + crusader[0] = NPC_CRUSADER_2_1; + crusader[1] = NPC_CRUSADER_2_13; + break; + case 4: + crusader[0] = NPC_CRUSADER_2_2; + crusader[1] = NPC_CRUSADER_2_13; + break; + case 5: + crusader[0] = NPC_CRUSADER_2_12; + crusader[1] = NPC_CRUSADER_2_13; + break; + } + switch (urand(0,5)) + { // Random melee DD, 2 in 10-mode + case 0: + crusader[3] = NPC_CRUSADER_2_3; + crusader[2] = NPC_CRUSADER_2_4; + break; + case 1: + crusader[3] = NPC_CRUSADER_2_3; + crusader[2] = NPC_CRUSADER_2_5; + break; + case 2: + crusader[3] = NPC_CRUSADER_2_3; + crusader[2] = NPC_CRUSADER_2_6; + break; + case 3: + crusader[3] = NPC_CRUSADER_2_4; + crusader[2] = NPC_CRUSADER_2_5; + break; + case 4: + crusader[3] = NPC_CRUSADER_2_4; + crusader[2] = NPC_CRUSADER_2_6; + break; + case 5: + crusader[3] = NPC_CRUSADER_2_5; + crusader[2] = NPC_CRUSADER_2_6; + break; + } + switch (urand(0,5)) + { // Random magic DD, 2 in 10-mode + case 0: + crusader[4] = NPC_CRUSADER_2_7; + crusader[5] = NPC_CRUSADER_2_8; + break; + case 1: + crusader[5] = NPC_CRUSADER_2_7; + crusader[4] = NPC_CRUSADER_2_14; + break; + case 2: + crusader[5] = NPC_CRUSADER_2_7; + crusader[4] = NPC_CRUSADER_2_11; + break; + case 3: + crusader[5] = NPC_CRUSADER_2_8; + crusader[4] = NPC_CRUSADER_2_11; + break; + case 4: + crusader[5] = NPC_CRUSADER_2_8; + crusader[4] = NPC_CRUSADER_2_14; + break; + case 5: + crusader[5] = NPC_CRUSADER_2_11; + crusader[4] = NPC_CRUSADER_2_14; + break; + } + } + for(uint8 i = 0; i < crusaderscount; ++i) + { + m_creature->SummonCreature(crusader[i], SpawnLoc[i+2].x, SpawnLoc[i+2].y, SpawnLoc[i+2].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(crusader[i])) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + } + } + m_pInstance->SetData(TYPE_CRUSADERS_COUNT,crusaderscount); + m_pInstance->SetData(TYPE_CRUSADERS_DEAD, 0); + m_pInstance->SetData(TYPE_CRUSADERS_ACHIEV_TIMER, 60000); + m_pInstance->SetData(TYPE_CRUSADERS_ACHIEV_FAIL, 0); + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_EVENT,0); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + m_pInstance->SetData(TYPE_CRUSADERS, IN_PROGRESS); + break; + //Crusaders battle end + case 3100: + DoScriptText(SAY_TIRION_PVP_WIN, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT, 0); + break; + case 4000: + if (GameObject* pGO10N = m_pInstance->GetSingleGameObjectFromStorage(GO_CRUSADERS_CACHE_10)) + pGO10N->Delete(); + + if (GameObject* pGO10H = m_pInstance->GetSingleGameObjectFromStorage(GO_CRUSADERS_CACHE_25)) + pGO10H->Delete(); + + if (GameObject* pGO25N = m_pInstance->GetSingleGameObjectFromStorage(GO_CRUSADERS_CACHE_10_H)) + pGO25N->Delete(); + + if (GameObject* pGO25H = m_pInstance->GetSingleGameObjectFromStorage(GO_CRUSADERS_CACHE_25_H)) + pGO25H->Delete(); + + DoScriptText(SAY_TIRION_TWINS_INTRO, m_creature); + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_EVENT,4010); + break; + case 4010: + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,4015); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 4015: + m_pInstance->SetData(TYPE_STAGE,7); + m_pInstance->SetData(TYPE_VALKIRIES,IN_PROGRESS); + m_creature->SummonCreature(NPC_LIGHTBANE, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_LIGHTBANE)) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + pTemp->SetInCombatWithZone(); + } + m_creature->SummonCreature(NPC_DARKBANE, SpawnLoc[4].x, SpawnLoc[4].y, SpawnLoc[4].z, 5, TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME); + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_DARKBANE)) + { + pTemp->GetMotionMaster()->MovePoint(0, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + pTemp->SetWalk(true); + pTemp->SetInCombatWithZone(); + } + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, TIMER_ACHIEV_SALT_AND_PEPPER); + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,4016); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 4040: + UpdateTimer = 60000; + m_pInstance->SetData(TYPE_EVENT,5000); + break; + case 5000: + DoScriptText(SAY_TIRION_TWINS_WIN, m_creature); + UpdateTimer = 8000; + m_pInstance->SetData(TYPE_EVENT,5005); + break; + case 5005: + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,5010); + m_pInstance->SetData(TYPE_STAGE,8); + m_creature->SummonCreature(NPC_LICH_KING_1, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z, 5, TEMPSUMMON_MANUAL_DESPAWN, 0); + break; + case 5020: + DoScriptText(SAY_TIRION_ABUN_INTRO_1, m_creature); + UpdateTimer = 8000; + m_pInstance->SetData(TYPE_EVENT,5030); + break; + case 6000: + m_creature->NearTeleportTo(SpawnLoc[19].x, SpawnLoc[19].y, SpawnLoc[19].z, 3.15f); + UpdateTimer = 20000; + m_pInstance->SetData(TYPE_EVENT,6005); + break; + case 6005: + DoScriptText(TIRION_SAY_EPILOGUE, m_creature); + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); + m_creature->SummonGameobject(195682, 783.57f, 124.45f, 142.21f, 0, 0); + UpdateTimer = 20000; + m_pInstance->SetData(TYPE_EVENT,6010); + break; + case 6010: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + //if (m_pInstance->GetData(TYPE_DIFFICULTY) == RAID_DIFFICULTY_10MAN_HEROIC || m_pInstance->GetData(TYPE_DIFFICULTY) == RAID_DIFFICULTY_25MAN_HEROIC) + // DoScriptText(-1713566, m_creature); + + UpdateTimer = 60000; + m_pInstance->SetData(TYPE_EVENT,6020); + break; + case 6020: + m_pInstance->SetData(TYPE_STAGE,10); + m_creature->ForcedDespawn(); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,6030); + break; + } + } + else + UpdateTimer -= diff; + + m_pInstance->SetData(TYPE_EVENT_TIMER, UpdateTimer); + } +}; + +CreatureAI* GetAI_npc_tirion_toc(Creature* pCreature) +{ + return new npc_tirion_tocAI(pCreature); } +struct MANGOS_DLL_DECL npc_garrosh_tocAI : public ScriptedAI +{ + npc_garrosh_tocAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 UpdateTimer; + + void Reset() + { + } + + void AttackStart(Unit *who) + { + //ignore all attackstart commands + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EVENT_NPC) != NPC_GARROSH) + return; + + UpdateTimer = m_pInstance->GetData(TYPE_EVENT_TIMER); + + if (UpdateTimer <= diff) + { + switch (m_pInstance->GetData(TYPE_EVENT)) + { + case 120: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_TALK); + DoScriptText(SAY_GARROSH_BEAST_1, m_creature); + m_pInstance->SetData(TYPE_EVENT,121); + UpdateTimer = 5000; + break; + case 2010: + DoScriptText(SAY_GARROSH_JARAXXUS_EXIT_1, m_creature); + UpdateTimer = 10000; + m_pInstance->SetData(TYPE_EVENT,2020); + break; + case 3050: + DoScriptText(SAY_GARROSH_PVP_A_INTRO_1, m_creature); + UpdateTimer = 15000; + m_pInstance->SetData(TYPE_EVENT,3060); + break; + case 3070: + DoScriptText(SAY_GARROSH_PVP_A_INTRO_2, m_creature); + UpdateTimer = 6000; + m_pInstance->SetData(TYPE_EVENT,3080); + break; + case 3081: + DoScriptText(SAY_GARROSH_PVP_H_WIN, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,3091); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 4030: + DoScriptText(SAY_GARROSH_TWINS_H_WIN, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,4040); + break; + } + } + else + UpdateTimer -= diff; + + m_pInstance->SetData(TYPE_EVENT_TIMER, UpdateTimer); + } +}; + +CreatureAI* GetAI_npc_garrosh_toc(Creature* pCreature) +{ + return new npc_garrosh_tocAI(pCreature); +}; + +struct MANGOS_DLL_DECL npc_rinn_tocAI : public ScriptedAI +{ + npc_rinn_tocAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 UpdateTimer; + + void Reset() + { + } + + void AttackStart(Unit *who) + { + //ignore all attackstart commands + return; + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EVENT_NPC) != NPC_RINN) + return; + + UpdateTimer = m_pInstance->GetData(TYPE_EVENT_TIMER); + + if (UpdateTimer <= diff) + { + switch (m_pInstance->GetData(TYPE_EVENT)) + { + case 130: + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION)) + DoScriptText(SAY_RAID_INTRO_SHORT, pTemp); + + UpdateTimer = 3000; + m_pInstance->SetData(TYPE_EVENT,140); + break; + case 2020: + DoScriptText(SAY_VARIAN_JARAXXUS_SLAY, m_creature); + UpdateTimer = 7000; + m_pInstance->SetData(TYPE_EVENT,2030); + break; + case 3051: + DoScriptText(SAY_VARIAN_PVP_H_INTRO_1, m_creature); + UpdateTimer = 15000; + m_pInstance->SetData(TYPE_EVENT,3061); + break; + case 3071: + DoScriptText(SAY_VARIAN_PVP_H_INTRO_2, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,3081); + break; + case 3080: + DoScriptText(SAY_VARIAN_PVP_A_WIN, m_creature); + UpdateTimer = 5000; + m_pInstance->SetData(TYPE_EVENT,3090); + m_pInstance->DoUseDoorOrButton(GO_MAIN_GATE_DOOR); + break; + case 4020: + DoScriptText(SAY_VARIAN_TWINS_A_WIN, m_creature); + UpdateTimer = 7000; + if (Creature* pBarrent = m_pInstance->GetSingleCreatureFromStorage(NPC_BARRENT)) + pBarrent->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + m_pInstance->SetData(TYPE_EVENT,4030); + break; + } + } + else + UpdateTimer -= diff; + + m_pInstance->SetData(TYPE_EVENT_TIMER,UpdateTimer); + } +}; + +CreatureAI* GetAI_npc_rinn_toc(Creature* pCreature) +{ + return new npc_rinn_tocAI(pCreature); +}; + void AddSC_trial_of_the_crusader() { Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "npc_barrett_ramsey"; - pNewScript->GetAI = &GetAI_npc_barrett_ramsey; - pNewScript->pGossipHello = &GossipHello_npc_barrett_ramsey; - pNewScript->pGossipSelect = &GossipSelect_npc_barrett_ramsey; + pNewScript->Name = "npc_toc_announcer"; + pNewScript->GetAI = &GetAI_npc_toc_announcer; + pNewScript->pGossipHello = &GossipHello_npc_toc_announcer; + pNewScript->pGossipSelect = &GossipSelect_npc_toc_announcer; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_lich_king_toc"; + pNewScript->GetAI = &GetAI_boss_lich_king_toc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_fizzlebang_toc"; + pNewScript->GetAI = &GetAI_npc_fizzlebang_toc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tirion_toc"; + pNewScript->GetAI = &GetAI_npc_tirion_toc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_garrosh_toc"; + pNewScript->GetAI = &GetAI_npc_garrosh_toc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_rinn_toc"; + pNewScript->GetAI = &GetAI_npc_rinn_toc; pNewScript->RegisterSelf(); } 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 20ec79ffef..b2d0351616 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,29 +1,316 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ +/* Copyright (C) 2006 - 2013 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 + */ -#ifndef DEF_TRIAL_OF_THE_CRUSADER_H -#define DEF_TRIAL_OF_THE_CRUSADER_H +#ifndef DEF_CRUSADER_H +#define DEF_CRUSADER_H +#include "BSW_ai.h" +#include "BSW_instance.h" enum { - MAX_ENCOUNTER = 5, - - TYPE_NORTHREND_BEASTS = 1, - TYPE_JARAXXUS = 2, - TYPE_FACTION_CHAMPIONS = 3, - TYPE_TWIN_VALKYR = 4, - TYPE_ANUBARAK = 5, - - DATA_GORMOK = 6, - DATA_ACIDMAW = 7, - DATA_DREADSCALE = 8, - DATA_ICEHOWL = 9, - DATA_JARAXXUS = 10, - DATA_FACTION_CHAMPIONS = 11, - DATA_FJOLA = 12, - DATA_EYDIS = 13, - DATA_ANUBARAK = 14, + TYPE_STAGE = 0, + TYPE_BEASTS = 1, + TYPE_JARAXXUS = 2, + TYPE_CRUSADERS = 3, + TYPE_VALKIRIES = 4, + TYPE_LICH_KING = 5, + TYPE_ANUBARAK = 6, + TYPE_COUNTER = 7, + TYPE_DEATHS = 8, + TYPE_EVENT = 9, + MAX_ENCOUNTERS = 10, + + TYPE_UPPER_BACK_PAIN = 0, + TYPE_THREE_SIXTY_PAIN_SPIKE = 1, + TYPE_SKILL = 2, + TYPE_MAD_SKILL = 3, + TYPE_INSANITY = 4, + TYPE_DEDICATED_INSANITY = 5, + TYPE_IMMORTALITY = 6, + MAX_SPECIAL_ACHIEV_CRITS = 7, + + NPC_BARRENT = 34816, + NPC_TIRION = 34996, + NPC_FIZZLEBANG = 35458, + NPC_GARROSH = 34995, + NPC_RINN = 34990, + NPC_LICH_KING_0 = 16980, + NPC_LICH_KING_1 = 35877, + + NPC_THRALL = 34994, + NPC_PROUDMOORE = 34992, + NPC_TRIGGER = 22517, + NPC_WILFRED_PORTAL = 35651, + + NPC_ICEHOWL = 34797, + NPC_GORMOK = 34796, + NPC_DREADSCALE = 34799, + NPC_ACIDMAW = 35144, + + NPC_JARAXXUS = 34780, + + NPC_CRUSADER_1_1 = 34460, //Druid + NPC_CRUSADER_1_2 = 34463, //Shaman + NPC_CRUSADER_1_3 = 34461, //DK + NPC_CRUSADER_1_4 = 34472, //Rogue + NPC_CRUSADER_1_5 = 34475, //Warrior + NPC_CRUSADER_1_6 = 34471, //Retro pal + NPC_CRUSADER_1_7 = 34473, //Shadow priest + NPC_CRUSADER_1_8 = 34468, //Mage + NPC_CRUSADER_1_9 = 34467, //Hunter + NPC_CRUSADER_1_10 = 34474, //Warlock + NPC_CRUSADER_1_11 = 34470, //Enh shaman + NPC_CRUSADER_1_12 = 34466, //Priest + NPC_CRUSADER_1_13 = 34465, //Holy paladin + NPC_CRUSADER_1_14 = 34469, //Moonkin + + NPC_CRUSADER_2_1 = 34451, //Druid + NPC_CRUSADER_2_2 = 34455, //Shaman + NPC_CRUSADER_2_3 = 34458, //DK + NPC_CRUSADER_2_4 = 34454, //Rogue + NPC_CRUSADER_2_5 = 34453, //Warrior + NPC_CRUSADER_2_6 = 34456, //Retro pal + NPC_CRUSADER_2_7 = 34441, //Shadow Priest + NPC_CRUSADER_2_8 = 34449, //Mage + NPC_CRUSADER_2_9 = 34448, //Hunter + NPC_CRUSADER_2_10 = 34450, //Warlock + NPC_CRUSADER_2_11 = 34444, //Enh shaman + NPC_CRUSADER_2_12 = 34447, //Priest + NPC_CRUSADER_2_13 = 34445, //Holy paladin + NPC_CRUSADER_2_14 = 34459, //Moonkin + + NPC_CRUSADER_0_1 = 35465, + NPC_CRUSADER_0_2 = 35610, + + NPC_LIGHTBANE = 34497, + NPC_DARKBANE = 34496, + + NPC_ANUBARAK = 34564, + + GO_CRUSADERS_CACHE_10 = 195631, + GO_CRUSADERS_CACHE_25 = 195632, + GO_CRUSADERS_CACHE_10_H = 195633, + GO_CRUSADERS_CACHE_25_H = 195635, + + GO_TRIBUTE_CHEST_10H_25 = 195665, + GO_TRIBUTE_CHEST_10H_45 = 195666, + GO_TRIBUTE_CHEST_10H_50 = 195667, + GO_TRIBUTE_CHEST_10H_99 = 195668, + + GO_TRIBUTE_CHEST_25H_25 = 195669, + GO_TRIBUTE_CHEST_25H_45 = 195670, + GO_TRIBUTE_CHEST_25H_50 = 195671, + GO_TRIBUTE_CHEST_25H_99 = 195672, + + GO_ARGENT_COLISEUM_FLOOR = 195527, //20943 + GO_MAIN_GATE_DOOR = 195647, + GO_WEB_DOOR = 195485, + + GO_WEST_PORTCULLIS = 195589, + GO_SOUTH_PORTCULLIS = 195590, + GO_NORTH_PORTCULLIS = 195591, + + TYPE_DIFFICULTY = 101, + TYPE_EVENT_TIMER = 102, + TYPE_EVENT_NPC = 103, + TYPE_NORTHREND_BEASTS = 104, + TYPE_CRUSADERS_COUNT = 105, + TYPE_CRUSADERS_DEAD = 106, + TYPE_CRUSADERS_ACHIEV_TIMER = 107, + TYPE_CRUSADERS_ACHIEV_FAIL = 108, + + DATA_HEALTH_EYDIS = 201, + DATA_HEALTH_FJOLA = 202, + + DESPAWN_TIME = 300000, + + CRITERIA_ACHIEV_UPPER_BACK_PAIN_10N = 11779, + CRITERIA_ACHIEV_UPPER_BACK_PAIN_10H = 11802, + CRITERIA_ACHIEV_UPPER_BACK_PAIN_25N = 11780, + CRITERIA_ACHIEV_UPPER_BACK_PAIN_25H = 11801, + + CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_10N = 11838, + CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_10H = 11861, + CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_25N = 11839, + CRITERIA_ACHIEV_THREE_SIXTY_PAIN_SPIKE_25H = 11862, + + CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_10_1 = 12344, + CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_10_2 = 12345, +// CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_10_3 = 12346, // should be ignoring + CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_25_1 = 12338, + CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_25_2 = 12339, +// CRITERIA_ACHIEV_TRIBUTE_TO_SKILL_25_3 = 12340, // should be ignoring + + CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_10_1 = 12347, + CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_10_2 = 12348, + CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_25_1 = 12341, + CRITERIA_ACHIEV_TRIBUTE_TO_MAD_SKILL_25_2 = 12342, + + CRITERIA_ACHIEV_TRIBUTE_TO_INSANITY_10 = 12349, + CRITERIA_ACHIEV_TRIBUTE_TO_INSANITY_25 = 12343, + + CRITERIA_ACHIEV_TRIBUTE_TO_IMMORTALITY_HORDE = 12247, + CRITERIA_ACHIEV_TRIBUTE_TO_IMMORTALITY_ALLY = 12359, + CRITERIA_ACHIEV_TRIBUTE_TO_DEDICATED_INSANITY = 12360, + + SPELL_ACHIEV_FACTION_CHAMPIONS_DEFEAT = 68184, + SPELL_ACHIEV_NOT_ONE_BUT_TWO_JORMUNGARS = 68523, + SPELL_ACHIEV_RESILIENCE_WILL_FIX_IT = 68620, + + TIMER_ACHIEV_SALT_AND_PEPPER = 21853, +}; + +static LOCATION SpawnLoc[]= +{ + {559.257996f, 90.266197f, 395.122986f}, // 0 Barrent + {563.672974f, 139.571f, 393.837006f}, // 1 Center + {563.833008f, 187.244995f, 394.5f}, // 2 Backdoor + {577.347839f, 185.338888f, 395.14f}, // 3 - Right + {550.955933f, 185.338888f, 395.14f}, // 4 - Left + {575.042358f, 195.260727f, 395.137146f}, // 5 + {552.248901f, 195.331955f, 395.132658f}, // 6 + {573.342285f, 195.515823f, 395.135956f}, // 7 + {554.239929f, 195.825577f, 395.137909f}, // 8 + {571.042358f, 195.260727f, 395.137146f}, // 9 + {556.720581f, 195.015472f, 395.132658f}, // 10 + {569.534119f, 195.214478f, 395.139526f}, // 11 + {569.231201f, 195.941071f, 395.139526f}, // 12 + {558.811610f, 195.985779f, 394.671661f}, // 13 + {567.641724f, 195.351501f, 394.659943f}, // 14 + {560.633972f, 195.391708f, 395.137543f}, // 15 + {565.816956f, 195.477921f, 395.136810f}, // 16 + {563.549f, 152.474f, 394.393f}, // 17 - Lich king start + {563.547f, 141.613f, 393.908f}, // 18 - Lich king end + {787.932556f, 133.28978f, 142.612152f}, // 19 - Anub'arak start location + {618.157898f, 132.640869f, 139.559769f}, // 20 - Anub'arak move point location + {563.813660f, 182.842819f, 395.128052f}, // 21 - Fizzlebang start location + {586.060242f, 117.514809f, 394.314026f}, // 22 - Dark essence 1 + {541.602112f, 161.879837f, 394.587952f}, // 23 - Dark essence 2 + {541.021118f, 117.262932f, 395.314819f}, // 24 - Light essence 1 + {586.200562f, 162.145523f, 394.626129f}, // 25 - Light essence 2 + {563.833008f, 195.244995f, 394.585561f}, // 26 - outdoor + {563.938477f, 149.210571f, 394.321838f}, // 27 - Fizzlebang end + {563.710999f, 131.058319f, 394.321838f}, // 28 - Jaraxxus + {750.78f, 158.48f, 142.68f }, // 29 - Frost Sphere 1 + {749.69f, 129.47f, 142.68f }, // 30 - Frost Sphere 2 + {702.69f, 126.47f, 142.68f }, // 31 - Frost Sphere 3 + {702.53f, 154.69f, 142.68f }, // 32 - Frost Sphere 4 + {530.80f, 108.18f, 395.14f }, // 33 - Unleashed light 1 + {530.49f, 172.75f, 395.14f }, // 34 - Unleashed light 2 + {591.52f, 167.06f, 395.14f }, // 35 - Unleashed light 3 + {589.40f, 114.05f, 395.14f }, // 36 - Unleashed light 4 + {516.64f, 139.74f, 395.14f }, // 37 - Unleashed dark 1 + {563.88f, 169.17f, 395.14f }, // 38 - Unleashed dark 2 + {604.99f, 139.63f, 395.14f }, // 39 - Unleashed dark 3 + {563.65f, 103.28f, 395.14f }, // 40 - Unleashed dark 4 + {519.75f, 119.29f, 395.14f }, // 41 - Unleashed light 1 extra (25) + {548.70f, 170.04f, 395.14f }, // 42 - Unleashed light 2 extra (25) + {575.52f, 144.13f, 395.14f }, // 43 - Unleashed light 3 extra (25) + {570.38f, 122.28f, 395.14f }, // 44 - Unleashed light 4 extra (25) + {550.53f, 145.74f, 395.14f }, // 45 - Unleashed dark 1 extra (25) + {577.57f, 174.08f, 395.14f }, // 46 - Unleashed dark 2 extra (25) + {605.72f, 119.60f, 395.14f }, // 47 - Unleashed dark 3 extra (25) + {554.94f, 123.42f, 395.14f }, // 48 - Unleashed dark 4 extra (25) + {697.73f, 118.48f, 142.68f }, // 49 - Frost Sphere 5 + {733.33f, 153.44f, 142.68f }, // 50 - Frost Sphere 6 + {731.40f, 90.90f, 142.68f }, // 51 - Frost Sphere 7 + {794.34f, 150.48f, 142.68f }, // 52 - Frost Sphere 8 +}; + +enum uiWorldStates +{ + UPDATE_STATE_UI_SHOW = 4390, + UPDATE_STATE_UI_COUNT = 4389, +}; + +enum NorthrendBeasts +{ + GORMOK_IN_PROGRESS = 1000, + GORMOK_DONE = 1001, + SNAKES_IN_PROGRESS = 2000, + DREADSCALE_SUBMERGED = 2001, + ACIDMAW_SUBMERGED = 2002, + SNAKES_SPECIAL = 2003, + SNAKES_DONE = 2004, + ICEHOWL_IN_PROGRESS = 3000, + ICEHOWL_DONE = 3001, +}; + +enum AnnounserMessages +{ + MSG_BEASTS = 724001, + MSG_JARAXXUS = 724002, + MSG_CRUSADERS = 724003, + MSG_VALKIRIES = 724004, + MSG_LICH_KING = 724005, + MSG_ANUBARAK = 724006, +}; + +class MANGOS_DLL_DECL instance_trial_of_the_crusader : public BSWScriptedInstance +{ +public: + instance_trial_of_the_crusader(Map* pMap); + ~instance_trial_of_the_crusader() {} + + void Initialize() override; + + bool IsEncounterInProgress() const override; + void OnPlayerEnter(Player *m_player); + void OnPlayerDeath(Player *m_player); + + bool IsRaidWiped(); + void UpdateWorldState(); + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType); + + const char* Save() const override { return m_strInstData.c_str(); } + + void Load(const char* chrIn) override; + +private: + + uint32 m_auiEncounter[MAX_ENCOUNTERS+1]; + uint32 m_auiEventTimer; + uint32 m_auiEventNPCId; + uint32 m_auiNorthrendBeasts; + uint8 Difficulty; + std::string m_strInstData; + bool needsave; + + bool m_bAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; + + uint32 m_uiDataDamageFjola; + uint32 m_uiDataDamageEydis; + + uint32 m_uiTributeChest1; + uint32 m_uiTributeChest2; + uint32 m_uiTributeChest3; + uint32 m_uiTributeChest4; + + uint32 m_auiCrusadersCount; + uint32 m_auiCrusadersDead; + uint32 m_auiCrusadersAchievTimer; + uint32 m_auiCrusadersAchievFail; }; #endif diff --git a/scripts/northrend/dalaran.cpp b/scripts/northrend/dalaran.cpp index eaa9ff7777..92ae174bb5 100644 --- a/scripts/northrend/dalaran.cpp +++ b/scripts/northrend/dalaran.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,103 +23,364 @@ EndScriptData */ /* ContentData npc_dalaran_guardian_mage -npc_zirdomi +npc_minigob_manabonk +npc_dalaran_vendor EndContentData */ #include "precompiled.h" +#include "Mail.h" + +/*##### +# npc_dalaran_guardian_mage +#####*/ enum { - SPELL_TRESPASSER_H = 54029, SPELL_TRESPASSER_A = 54028, + SPELL_TRESPASSER_H = 54029, + + // 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 + AREA_ID_SUNREAVER = 4616, + AREA_ID_SILVER_ENCLAVE = 4740 }; struct MANGOS_DLL_DECL npc_dalaran_guardian_mageAI : public ScriptedAI { npc_dalaran_guardian_mageAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void MoveInLineOfSight(Unit* pWho) + void Reset() override {} + void AttackedBy(Unit* /*pAttacker*/) override {} + + void MoveInLineOfSight(Unit* pWho) override { - if (m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) + if (self->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) return; - if (pWho->isTargetableForAttack() && m_creature->IsHostileTo(pWho)) + if (pWho->isTargetableForAttack() && self->IsHostileTo(pWho)) { - if (m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho)) + if (self->IsWithinDistInMap(pWho, self->GetAttackDistance(pWho)) && self->IsWithinLOSInMap(pWho)) { if (Player* pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself()) { - // it's mentioned that pet may also be teleported, if so, we need to tune script to apply to those in addition. + // exception for quests 20439 and 24451 + if (pPlayer->HasAura(SPELL_COVENANT_DISGUISE_1) || pPlayer->HasAura(SPELL_COVENANT_DISGUISE_2) || + pPlayer->HasAura(SPELL_SUNREAVER_DISGUISE_1) || pPlayer->HasAura(SPELL_SUNREAVER_DISGUISE_2)) + { + return; + } - if (pPlayer->GetAreaId() == AREA_ID_SILVER_ENCLAVE) - DoCastSpellIfCan(pPlayer, SPELL_TRESPASSER_A); - else if (pPlayer->GetAreaId() == AREA_ID_SUNREAVER) - DoCastSpellIfCan(pPlayer, SPELL_TRESPASSER_H); + uint32 spellId; + switch (pPlayer->GetAreaId()) + { + case AREA_ID_SUNREAVER: spellId = SPELL_TRESPASSER_H; break; + case AREA_ID_SILVER_ENCLAVE: spellId = SPELL_TRESPASSER_A; break; + default: + return; + } + DoCastSpellIfCan(pPlayer, spellId); } } } } - void AttackedBy(Unit* /*pAttacker*/) {} + void UpdateAI(uint32 const /*uiDiff*/) override {} + + static CreatureAI* GetAI(Creature* pCreature) + { + return new npc_dalaran_guardian_mageAI(pCreature); + } +}; + +/*##### +# npc_minigob_manabonk +#####*/ - void Reset() {} +enum +{ + ZONE_DALARAN = 4395, + + SPELL_MANABONKED = 61834, + SPELL_TELEPORT_VISUAL = 51347, + SPELL_IMPROVED_BLINK = 61995, - void UpdateAI(const uint32 /*uiDiff*/) {} + MAIL_MINIGOB_ENTRY = 264, }; -CreatureAI* GetAI_npc_dalaran_guardian_mage(Creature* pCreature) +struct MANGOS_DLL_DECL npc_minigob_manabonkAI : public ScriptedAI { - return new npc_dalaran_guardian_mageAI(pCreature); -} + npc_minigob_manabonkAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + TTimer m_eventTimer; + uint32 m_eventStage; + + void Reset() override + { + self->SetVisibility(VISIBILITY_OFF); + + m_eventTimer.Reset(1000); + m_eventStage = 0; + } + + Player* SelectPlayerInDalaran() + { + std::list lPlayers; + + Map::PlayerList const& players = self->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + if (pPlayer->GetZoneId() == ZONE_DALARAN && !pPlayer->IsFlying() && + !pPlayer->IsMounted() && !pPlayer->isGameMaster()) + { + lPlayers.push_back(pPlayer); + } + } + } -/*###### -## npc_zidormi -######*/ + if (lPlayers.empty()) + return NULL; + + std::list::iterator itr = lPlayers.begin(); + std::advance(itr, urand(0, lPlayers.size() - 1)); + + return *itr; + } + + void SendMailToPlayer(Player* pPlayer) + { + MailDraft(MAIL_MINIGOB_ENTRY) + .SendMailTo(pPlayer, MailSender(MAIL_CREATURE, self->GetEntry())); + } + + void EnterCombat(Unit* /*pEnemy*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + + void UpdateAI(uint32 const uiDiff) override + { + if (!m_eventTimer.IsSet() || !m_eventTimer.Expired(uiDiff)) + return; + + switch (m_eventStage) + { + case 0: + if (Player* pPlayer = SelectPlayerInDalaran()) + { + self->SetVisibility(VISIBILITY_ON); + self->CastSpell(self, SPELL_TELEPORT_VISUAL, false); + + float x, y, z; + pPlayer->GetClosePoint(x, y, z, 0.0f, 5.0f); + self->NearTeleportTo(x, y, z, -pPlayer->GetOrientation()); + + self->CastSpell(pPlayer, SPELL_MANABONKED, false); + SendMailToPlayer(pPlayer); + } + else + { + m_eventTimer.Reset(0); + self->ForcedDespawn(); + return; + } + + m_eventTimer.Reset(3000); + m_eventStage++; + break; + case 1: + self->CastSpell(self, SPELL_IMPROVED_BLINK, false); + + float x, y, z; + self->GetClosePoint(x, y, z, 0.0f, frand(15.0f, 40.0f)); + self->GetMotionMaster()->MovePoint(0, x, y, z); + + m_eventTimer.Reset(3000); + m_eventStage++; + break; + case 2: + self->CastSpell(self, SPELL_TELEPORT_VISUAL, false); + + m_eventTimer.Reset(500); + m_eventStage++; + break; + case 3: + m_eventTimer.Reset(0); + + self->SetVisibility(VISIBILITY_OFF); + self->ForcedDespawn(); + break; + } + } + + static CreatureAI* GetAI(Creature* pCreature) + { + return new npc_minigob_manabonkAI(pCreature); + } +}; -#define GOSSIP_ITEM_ZIDORMI1 "Take me to the Caverns of Time." +/*##### +# npc_dalaran_vendor +#####*/ enum { - SPELL_TELEPORT_COT = 46343, - GOSSIP_TEXTID_ZIDORMI1 = 14066 + SAY_VENDOR_1 = -1020384, + SAY_VENDOR_2 = -1020385, + SAY_VENDOR_3 = -1020386, + SAY_VENDOR_4 = -1020387, + SAY_VENDOR_5 = -1020388, + SAY_VENDOR_6 = -1020389, + SAY_VENDOR_7 = -1020390, }; -bool GossipHello_npc_zidormi(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_dalaran_vendorAI : public ScriptedAI { - if (pPlayer->getLevel() >= 65) + npc_dalaran_vendorAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + TTimer m_delayTimer; + ObjectGuid m_lastPlayerGuid; + + void Reset() override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ZIDORMI1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + m_delayTimer.Reset(1000); + m_lastPlayerGuid.Clear(); } - else - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ZIDORMI1, pCreature->GetGUID()); - return true; -} + void MoveInLineOfSight(Unit* pWho) override + { + if (!pWho || pWho->GetTypeId() != TYPEID_PLAYER || ((Player*)pWho)->isGameMaster()) + return; -bool GossipSelect_npc_zidormi(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - pPlayer->CastSpell(pPlayer,SPELL_TELEPORT_COT,false); + if (m_delayTimer.IsSet()) + return; - return true; -} + if (m_lastPlayerGuid == pWho->GetObjectGuid()) + return; + + if (!self->IsWithinDistInMap(pWho, 10.0f) || !self->IsWithinLOSInMap(pWho)) + return; + + m_delayTimer.Reset(30000, 120000); + m_lastPlayerGuid = pWho->GetObjectGuid(); + + int32 sayMsgId; + switch (self->GetEntry()) + { + case 28714: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_4, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28715: + { + int32 sayId[] = {SAY_VENDOR_2, SAY_VENDOR_5, SAY_VENDOR_6}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28718: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_2, SAY_VENDOR_3, SAY_VENDOR_4, SAY_VENDOR_5, SAY_VENDOR_6, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28721: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_3, SAY_VENDOR_4, SAY_VENDOR_5, SAY_VENDOR_6, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28723: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_4, SAY_VENDOR_5}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28725: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_2, SAY_VENDOR_3, SAY_VENDOR_6}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28726: + { + int32 sayId[] = {SAY_VENDOR_2, SAY_VENDOR_3, SAY_VENDOR_4, SAY_VENDOR_5, SAY_VENDOR_6, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28727: + { + int32 sayId[] = {SAY_VENDOR_2, SAY_VENDOR_3, SAY_VENDOR_4, SAY_VENDOR_6}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28989: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_3, SAY_VENDOR_4, SAY_VENDOR_5, SAY_VENDOR_6, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28994: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_3, SAY_VENDOR_4, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 28997: + { + int32 sayId[] = {SAY_VENDOR_2, SAY_VENDOR_4, SAY_VENDOR_5, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 29491: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_3}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 29523: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_2, SAY_VENDOR_6, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + case 33027: + { + int32 sayId[] = {SAY_VENDOR_1, SAY_VENDOR_3, SAY_VENDOR_5, SAY_VENDOR_6, SAY_VENDOR_7}; + sayMsgId = sayId[urand(0, countof(sayId) - 1)]; + break; + } + default: + return; + } + + DoScriptText(sayMsgId, self, pWho); + } + + void UpdateAI(uint32 const uiDiff) override + { + if (m_delayTimer.IsSet() && m_delayTimer.Expired(uiDiff)) + m_delayTimer.Reset(0); + } + + static CreatureAI* GetAI(Creature* pCreature) + { + return new npc_dalaran_vendorAI(pCreature); + } +}; + +/*##### +# Register scripts +#####*/ void AddSC_dalaran() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_dalaran_guardian_mage"; - newscript->GetAI = &GetAI_npc_dalaran_guardian_mage; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_zidormi"; - newscript->pGossipHello = &GossipHello_npc_zidormi; - newscript->pGossipSelect = &GossipSelect_npc_zidormi; - newscript->RegisterSelf(); + AutoScript s; + s.newScript("npc_dalaran_guardian_mage", &npc_dalaran_guardian_mageAI::GetAI); + s.newScript("npc_minigob_manabonk", &npc_minigob_manabonkAI::GetAI); + s.newScript("npc_dalaran_vendor", &npc_dalaran_vendorAI::GetAI); } diff --git a/scripts/northrend/dragonblight.cpp b/scripts/northrend/dragonblight.cpp index 545d56d262..a6600b587d 100644 --- a/scripts/northrend/dragonblight.cpp +++ b/scripts/northrend/dragonblight.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,203 +17,282 @@ /* ScriptData SDName: Dragonblight SD%Complete: 100 -SDComment: Quest support: 12166, 12499/12500(end sequenze). Taxi paths Wyrmrest temple. +SDComment: Quest support: 12075, 12166, 12261. SDCategory: Dragonblight EndScriptData */ /* ContentData -npc_afrasastrasz -npc_alexstrasza_wr_gate -npc_liquid_fire_of_elune -npc_tariolstrasz -npc_torastrasza +npc_destructive_ward +npc_crystalline_ice_giant +npc_hourglass_of_eternity EndContentData */ #include "precompiled.h" /*###### -## npc_afrasastrasz -######*/ +# npc_destructive_ward +#####*/ enum { - TAXI_PATH_ID_MIDDLE_DOWN = 882, - TAXI_PATH_ID_MIDDLE_TOP = 881 -}; + SAY_WARD_POWERUP = -1000664, + SAY_WARD_CHARGED = -1000665, -#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." + SPELL_DESTRUCTIVE_PULSE = 48733, + SPELL_DESTRUCTIVE_BARRAGE = 48734, + SPELL_DESTRUCTIVE_WARD_POWERUP = 48735, -bool GossipHello_npc_afrasastrasz(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + SPELL_SUMMON_SMOLDERING_SKELETON = 48715, + SPELL_SUMMON_SMOLDERING_CONSTRUCT = 48718, + SPELL_DESTRUCTIVE_WARD_KILL_CREDIT = 52409, + + MAX_STACK = 1, +}; - 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); +// Script is based on real event from you-know-where. +// Some sources show the event in a bit different way, for unknown reason. +// Devs decided to add it in the below way, until more details can be obtained. - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} +// It will be only two power-up's, where other sources has a different count (2-4 stacks has been observed) +// 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) -bool GossipSelect_npc_afrasastrasz(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +struct MANGOS_DLL_DECL npc_destructive_wardAI : public Scripted_NoMovementAI { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + npc_destructive_wardAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_MIDDLE_DOWN); + m_uiPowerTimer = 30000; + m_uiStack = 0; + m_uiSummonTimer = 2000; + m_bCanPulse = false; + m_bFirst = true; + Reset(); } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_MIDDLE_TOP); - } - return true; -} -/*###### -## npc_alexstrasza_wr_gate -######*/ + uint32 m_uiPowerTimer; + uint32 m_uiStack; + uint32 m_uiSummonTimer; + bool m_bFirst; + bool m_bCanPulse; -enum -{ - QUEST_RETURN_TO_AG_A = 12499, - QUEST_RETURN_TO_AG_H = 12500, - MOVIE_ID_GATES = 14 -}; - -#define GOSSIP_ITEM_WHAT_HAPPENED "Alexstrasza, can you show me what happened here?" - -bool GossipHello_npc_alexstrasza_wr_gate(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + void Reset() override { } - if (pPlayer->GetQuestRewardStatus(QUEST_RETURN_TO_AG_A) || pPlayer->GetQuestRewardStatus(QUEST_RETURN_TO_AG_H)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WHAT_HAPPENED, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + void JustSummoned(Creature* pSummoned) override + { + pSummoned->AI()->AttackStart(m_creature); + } -bool GossipSelect_npc_alexstrasza_wr_gate(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + void UpdateAI(const uint32 uiDiff) override { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->SendMovieStart(MOVIE_ID_GATES); + if (m_bCanPulse) + { + if (DoCastSpellIfCan(m_creature, m_uiStack > MAX_STACK ? SPELL_DESTRUCTIVE_BARRAGE : SPELL_DESTRUCTIVE_PULSE) == CAST_OK) + m_bCanPulse = false; + } + + if (m_uiSummonTimer) + { + if (m_uiSummonTimer <= uiDiff) + { + if (m_bFirst) + m_uiSummonTimer = 25000; + else + m_uiSummonTimer = 0; + + switch (m_uiStack) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_SKELETON, CAST_TRIGGERED); + break; + case 1: + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_CONSTRUCT, CAST_TRIGGERED); + + if (m_bFirst) + break; + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_CONSTRUCT, CAST_TRIGGERED); + break; + case 2: + if (m_bFirst) + break; + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_SKELETON, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_SKELETON, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_CONSTRUCT, CAST_TRIGGERED); + break; + } + + m_bFirst = !m_bFirst; + } + else + m_uiSummonTimer -= uiDiff; + } + + if (!m_uiPowerTimer) + return; + + if (m_uiPowerTimer <= uiDiff) + { + if (m_uiStack > MAX_STACK) + { + if (DoCastSpellIfCan(m_creature, SPELL_DESTRUCTIVE_WARD_KILL_CREDIT) == CAST_OK) + { + DoScriptText(SAY_WARD_CHARGED, m_creature, m_creature->GetOwner()); + m_uiPowerTimer = 0; + m_uiSummonTimer = 0; + m_bCanPulse = true; + } + } + else if (DoCastSpellIfCan(m_creature, SPELL_DESTRUCTIVE_WARD_POWERUP) == CAST_OK) + { + DoScriptText(SAY_WARD_POWERUP, m_creature, m_creature->GetOwner()); + + m_uiPowerTimer = 30000; + m_uiSummonTimer = 2000; + + m_bFirst = true; + m_bCanPulse = true; // pulse right after each charge + + ++m_uiStack; + } + } + else + m_uiPowerTimer -= uiDiff; } +}; - return true; +CreatureAI* GetAI_npc_destructive_ward(Creature* pCreature) +{ + return new npc_destructive_wardAI(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->GetGUID()); - - 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->GetGUID()); - 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); + if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_ID_SAMPLE_ROCKFLESH, 1)) + { + pPlayer->SendNewItem(pItem, 1, true, false); + pClickedCreature->ForcedDespawn(); + + // always return true when handled special npc spell click + return true; + } } + 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->GetGUID()); - - 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); +/*###### +## npc_hourglass_of_eternity +######*/ +/*Support for 'Future you' is currently missing*/ +enum +{ + + NPC_INFINITE_CHRONO_MAGUS = 27898, + NPC_INFINITE_ASSAILANT = 27896, + NPC_INFINITE_DESTROYER = 27897, + NPC_INFINITE_TIMERENDER = 27900, + QUEST_MYSTERY_OF_INFINITE = 12470 +}; + +struct MANGOS_DLL_DECL npc_hourglassAI : public ScriptedAI +{ + npc_hourglassAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); SetCombatMovement(false); } + + uint32 uiWaveTimer; + uint32 uiWaveCounter; + + void Reset() override + { + uiWaveTimer = 5000; + uiWaveCounter = 0; + } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + void JustSummoned(Creature* pSummoned) override + { + pSummoned->AI()->AttackStart(m_creature); + } -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); + void JustDied(Unit* pKiller) override + { + if(Player *pPlayer = m_creature->GetMap()->GetPlayer(m_creature->GetOwnerGuid())) + { + pPlayer->FailQuest(QUEST_MYSTERY_OF_INFINITE); + } } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_TOP_BOTTOM); + + void SummonWave() + { + switch (uiWaveCounter) + { + case 0: m_creature->SummonCreature(NPC_INFINITE_CHRONO_MAGUS, m_creature->GetPositionX()+5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_ASSAILANT, m_creature->GetPositionX()-5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + case 1: m_creature->SummonCreature(NPC_INFINITE_CHRONO_MAGUS, m_creature->GetPositionX()+5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_CHRONO_MAGUS, m_creature->GetPositionX()-5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + case 2: m_creature->SummonCreature(NPC_INFINITE_CHRONO_MAGUS, m_creature->GetPositionX()+5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_ASSAILANT, m_creature->GetPositionX()-5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_DESTROYER, m_creature->GetPositionX()+5,m_creature->GetPositionY()+5 ,m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + case 3: m_creature->SummonCreature(NPC_INFINITE_CHRONO_MAGUS, m_creature->GetPositionX()+5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_ASSAILANT, m_creature->GetPositionX()-5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_DESTROYER, m_creature->GetPositionX()+5,m_creature->GetPositionY()+5 ,m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + case 4: m_creature->SummonCreature(NPC_INFINITE_TIMERENDER, m_creature->GetPositionX()+5,m_creature->GetPositionY(),m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); + break; + } } - return true; + + void UpdateAI(const uint32 uiDiff) override + { + if (uiWaveTimer <= uiDiff) + { + if(uiWaveCounter<=4) + { + SummonWave(); + uiWaveTimer = 15000; + uiWaveCounter++; + } + else m_creature->ForcedDespawn(); + } else uiWaveTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_hourglass(Creature* pCreature) +{ + return new npc_hourglassAI(pCreature); } void AddSC_dragonblight() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_afrasastrasz"; - newscript->pGossipHello = &GossipHello_npc_afrasastrasz; - newscript->pGossipSelect = &GossipSelect_npc_afrasastrasz; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_alexstrasza_wr_gate"; - newscript->pGossipHello = &GossipHello_npc_alexstrasza_wr_gate; - newscript->pGossipSelect = &GossipSelect_npc_alexstrasza_wr_gate; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tariolstrasz"; - newscript->pGossipHello = &GossipHello_npc_tariolstrasz; - newscript->pGossipSelect = &GossipSelect_npc_tariolstrasz; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_torastrasza"; - newscript->pGossipHello = &GossipHello_npc_torastrasza; - newscript->pGossipSelect = &GossipSelect_npc_torastrasza; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_destructive_ward"; + pNewScript->GetAI = &GetAI_npc_destructive_ward; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_crystalline_ice_giant"; + pNewScript->pNpcSpellClick = &NpcSpellClick_npc_crystalline_ice_giant; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_hourglass"; + pNewScript->GetAI = &GetAI_npc_hourglass; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/draktharon_keep/boss_dred.cpp b/scripts/northrend/draktharon_keep/boss_dred.cpp new file mode 100644 index 0000000000..021e43ef88 --- /dev/null +++ b/scripts/northrend/draktharon_keep/boss_dred.cpp @@ -0,0 +1,190 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for 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_Tharonja +SD%Complete: 80% +SDComment: Timers +SDCategory: Drak'Tharon Keep +EndScriptData */ + +#include "precompiled.h" +#include "draktharon_keep.h" + +enum +{ + SAY_KING_DRED_TALON = -1600020, + SAY_CALL_FOR_RAPTOR = -1600021, + + SPELL_BELLOWING_ROAR = 22686, + SPELL_FEARSOME_ROAR = 48849, + SPELL_FEARSOME_ROAR_H = 59422, + SPELL_GRIEVOUS_BITE = 48920, + SPELL_MANGLING_SLASH = 48873, + SPELL_PIERCING_SLASH = 48878, + SPELL_RAPTOR_CALL = 59416, //not yet implemented + +}; + +const float PosSummon1[3] = {-528.8f, -690.58f, 30.25f}; +/*###### +## boss_dred +######*/ + +struct MANGOS_DLL_DECL boss_dredAI : public ScriptedAI +{ + boss_dredAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_draktharon_keep*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_draktharon_keep* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiFearsomeRoar; + uint32 m_uiManglingSlash; + uint32 m_uiPiercingSlash; + uint32 m_uiGrievousBite; + uint32 m_uiBellowingRoar; + uint32 m_uiCallForRaptor; + uint32 m_uiCallForRaptorSpawn; + + bool m_bCallForRaptorSpawn; + + void Reset() + { + m_uiFearsomeRoar = 15000; + m_uiManglingSlash = urand(5000, 10000); + m_uiPiercingSlash = urand(10000, 15000); + m_uiGrievousBite = urand(15000, 20000); + m_uiBellowingRoar = 60000; + m_uiCallForRaptor = 25000; + m_bCallForRaptorSpawn = false; + } + + void CallForRaptorSpawnCheck() + { + m_uiCallForRaptorSpawn = 1000; + m_uiCallForRaptorSpawn = true; + } + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + //Fearsome Roar + if (m_uiFearsomeRoar < uiDiff) + { + if (DoCastSpellIfCan (m_creature, m_bIsRegularMode ? SPELL_FEARSOME_ROAR : SPELL_FEARSOME_ROAR_H) == CAST_OK) + m_uiFearsomeRoar = 15000; + } + else + m_uiFearsomeRoar -= uiDiff; + + //Piercing Slash + if (m_uiPiercingSlash < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PIERCING_SLASH) == CAST_OK) + m_uiPiercingSlash = urand(20000, 25000); + } + else + m_uiPiercingSlash -= uiDiff; + + //Mangling Slash + if (m_uiManglingSlash < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLING_SLASH) == CAST_OK) + m_uiManglingSlash = urand(20000, 25000); + } + else + m_uiManglingSlash -= uiDiff; + + //Grievous Bite + if (m_uiGrievousBite < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GRIEVOUS_BITE) == CAST_OK) + m_uiGrievousBite = urand(20000, 25000); + } + else + m_uiGrievousBite -= uiDiff; + + //Bellowing Roar + if (m_uiBellowingRoar < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BELLOWING_ROAR) == CAST_OK) + m_uiBellowingRoar = 60000; + } + else + m_uiBellowingRoar -= uiDiff; + + //Call For Raptor - spell + if (m_uiCallForRaptor < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RAPTOR_CALL) == CAST_OK) + { + DoScriptText(SAY_CALL_FOR_RAPTOR, m_creature); + m_uiCallForRaptor = 25000; + CallForRaptorSpawnCheck(); + } + } + else + m_uiCallForRaptor -= uiDiff; + + //Call For Raptor - spawn + if (m_uiCallForRaptorSpawn < uiDiff && m_bCallForRaptorSpawn) + { + switch(urand(0, 1)) + { + case 0: + { + if (Creature* pRaptor1 = m_creature->SummonCreature(NPC_DRAKKARI_GUTRIPPER, PosSummon1[0], PosSummon1[1], PosSummon1[2], 0 , TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 240000)) + pRaptor1->SetInCombatWithZone(); + break; + } + case 1: + { + if (Creature* pRaptor2 = m_creature->SummonCreature(NPC_DRAKKARI_SCYTHECLAW, PosSummon1[0], PosSummon1[1], PosSummon1[2], 0 , TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 240000)) + pRaptor2->SetInCombatWithZone(); + break; + } + default: + break; + } + m_bCallForRaptorSpawn = false; + } + else + m_uiCallForRaptorSpawn -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_dred(Creature* pCreature) +{ + return new boss_dredAI(pCreature); +} + +void AddSC_boss_dred() +{ + Script *pNewscript; + + pNewscript = new Script; + pNewscript->Name = "boss_dred"; + pNewscript->GetAI = &GetAI_boss_dred; + pNewscript->RegisterSelf(); +} diff --git a/scripts/northrend/draktharon_keep/boss_novos.cpp b/scripts/northrend/draktharon_keep/boss_novos.cpp index 3b238860f0..7e96f4c69f 100644 --- a/scripts/northrend/draktharon_keep/boss_novos.cpp +++ b/scripts/northrend/draktharon_keep/boss_novos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Novos -SD%Complete: 20% -SDComment: +SD%Complete: 90% +SDComment: Summon Timers are vague SDCategory: Drak'Tharon Keep EndScriptData */ @@ -35,33 +35,106 @@ enum EMOTE_ASSISTANCE = -1600011, + SPELL_ARCANE_FIELD = 47346, + SPELL_IMMUNITY = 34098, + SPELL_SUMMON_MINIONS_H = 59910, + SPELL_FROSTBOLT = 49037, + SPELL_FROSTBOLT_H = 59855, + SPELL_ARCANE_BLAST = 49198, + SPELL_ARCANE_BLAST_H = 59909, + SPELL_BLIZZARD = 49034, + SPELL_BLIZZARD_H = 59854, + SPELL_TOUCH_OF_MISERY = 50090, // TODO - purpose of this spell (triggers SPELL_WRATH_OF_MISERY) unknown + SPELL_WRATH_OF_MISERY = 50089, + SPELL_WRATH_OF_MISERY_H = 59856, + + // SPELL_SUMMON_CRYSTAL_HANDLER = 49179, // Spell seems to be unused, perhaps only server-side, and especially no suitable positioned caster are found for this spell + SPELL_SUMMON_FETID_TROLL_CORPSE = 49103, + SPELL_SUMMON_HULKING_CORPSE = 49104, + SPELL_SUMMON_RISON_SHADOWCASTER = 49105, + + // Spells 'Crystal Handler Death' 47336, 55801, 55803, 55805 (defined in instance script) + NPC_CRYSTAL_HANDLER = 26627, NPC_HULKING_CORPSE = 27597, NPC_FETID_TROLL_CORPSE = 27598, - NPC_RISON_SHADOWCASTER = 27600 + NPC_RISON_SHADOWCASTER = 27600, + NPC_ROTTED_TROLL_CORPSE = 32786, // On heroic as effect of SPELL_SUMMON_MINIONS_H +}; + +// 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} }; /*###### ## boss_novos ######*/ -struct MANGOS_DLL_DECL boss_novosAI : public ScriptedAI +enum Phases { - boss_novosAI(Creature* pCreature) : ScriptedAI(pCreature) + PHASE_SHIELDED = 0, + PHASE_WAITING = 1, + PHASE_NORMAL = 2, +}; + +struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI +{ + boss_novosAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_draktharon_keep*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_draktharon_keep* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiSummonHandlerTimer; // TODO the summoning timers are weak + uint32 m_uiSummonShadowcasterTimer; + uint32 m_uiSummonFetidTrollTimer; + uint32 m_uiSummonHulkingCorpseTimer; + uint32 m_uiPhaseTimer; + uint32 m_uiArcaneBlastTimer; + uint32 m_uiBlizzardTimer; + uint32 m_uiWrathTimer; + + uint8 m_uiSummonedHandlers; + uint8 m_uiLostCrystals; + Phases m_uiPhase; + + void Reset() override { + m_uiSummonHandlerTimer = 25000; + m_uiSummonShadowcasterTimer = 3000; + m_uiSummonFetidTrollTimer = 10000; + m_uiSummonHulkingCorpseTimer = 30000; + m_uiPhaseTimer = 3000; + m_uiArcaneBlastTimer = urand(6000, 8000); + m_uiBlizzardTimer = urand(8000, 12000); + m_uiWrathTimer = urand(12000, 15000); + + m_uiSummonedHandlers = 0; + m_uiLostCrystals = 0; + // This ensures that in the shield phase m_pInstance is valid + m_uiPhase = m_pInstance ? PHASE_SHIELDED : PHASE_NORMAL; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void LostOneCrystal() + { + ++m_uiLostCrystals; + + DoScriptText(urand(0, 1) ? SAY_BUBBLE_1 : SAY_BUBBLE_2, m_creature); + + if (m_uiLostCrystals == MAX_CRYSTALS) // Enter Phase 2 + 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) @@ -75,20 +148,27 @@ struct MANGOS_DLL_DECL boss_novosAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_BLAST : SPELL_ARCANE_BLAST_H, CAST_TRIGGERED); + + DoCastSpellIfCan(m_creature, SPELL_IMMUNITY, CAST_TRIGGERED); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoCastSpellIfCan(m_creature, SPELL_ARCANE_FIELD); + if (m_pInstance) 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); @@ -96,18 +176,141 @@ struct MANGOS_DLL_DECL boss_novosAI : public ScriptedAI m_pInstance->SetData(TYPE_NOVOS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NOVOS, FAIL); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_CRYSTAL_HANDLER: + case NPC_ROTTED_TROLL_CORPSE: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_CRYSTAL_HANDLER) + { + uint8 uiIndex = 0; + if (m_pInstance) + { + if (Creature* pTarget = m_pInstance->GetNextCrystalTarget(pSummoned, uiIndex)) + pSummoned->CastSpell(pTarget, aCrystalHandlerDeathSpells[uiIndex], true, NULL, NULL, m_creature->GetObjectGuid()); + } + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); + switch (m_uiPhase) + { + case PHASE_SHIELDED: // Event Phase, only summoning of mobs + if (m_uiSummonHandlerTimer < uiDiff) + { + float fX, fY, fZ; + ++m_uiSummonedHandlers; + m_creature->GetRandomPoint(aHandlerSummonPos[m_uiSummonedHandlers % 2][0], aHandlerSummonPos[m_uiSummonedHandlers % 2][1], aHandlerSummonPos[m_uiSummonedHandlers % 2][2], 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_CRYSTAL_HANDLER, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + + DoScriptText(SAY_ADDS, m_creature); + DoScriptText(EMOTE_ASSISTANCE, m_creature); + + m_uiSummonHandlerTimer = 40000; + } + else + m_uiSummonHandlerTimer -= uiDiff; + + if (m_uiSummonShadowcasterTimer < uiDiff) + { + if (Creature* pSummoner = m_pInstance->GetSummonDummy()) + pSummoner->CastSpell(pSummoner, SPELL_SUMMON_RISON_SHADOWCASTER, false, NULL, NULL, m_creature->GetObjectGuid()); + m_uiSummonShadowcasterTimer = 25000; + } + else + m_uiSummonShadowcasterTimer -= uiDiff; + + if (m_uiSummonFetidTrollTimer < uiDiff) + { + if (Creature* pSummoner = m_pInstance->GetSummonDummy()) + pSummoner->CastSpell(pSummoner, SPELL_SUMMON_FETID_TROLL_CORPSE, false, NULL, NULL, m_creature->GetObjectGuid()); + m_uiSummonFetidTrollTimer = 5000; + } + else + m_uiSummonFetidTrollTimer -= uiDiff; + + if (m_uiSummonHulkingCorpseTimer < uiDiff) + { + if (Creature* pSummoner = m_pInstance->GetSummonDummy()) + pSummoner->CastSpell(pSummoner, SPELL_SUMMON_HULKING_CORPSE, false, NULL, NULL, m_creature->GetObjectGuid()); + m_uiSummonHulkingCorpseTimer = 30000; + } + else + m_uiSummonHulkingCorpseTimer -= uiDiff; + + break; + + case PHASE_WAITING: // Short delay between last destroyed crystal and entering combat + if (m_uiPhaseTimer < uiDiff) + { + m_uiPhase = PHASE_NORMAL; + // Remove Immunity and Shield Aura + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAllAuras(); + + if (!m_bIsRegularMode) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MINIONS_H, CAST_INTERRUPT_PREVIOUS); + else + m_creature->InterruptNonMeleeSpells(true); + } + else + m_uiPhaseTimer -= uiDiff; + + break; + + case PHASE_NORMAL: // Normal Phase, attack enemies + if (m_uiArcaneBlastTimer < uiDiff) + { + // TODO - might be possible that this spell is only casted, when there is an enemy in range + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_BLAST : SPELL_ARCANE_BLAST_H) == CAST_OK) + m_uiArcaneBlastTimer = urand(7000, 9000); + } + else + m_uiArcaneBlastTimer -= uiDiff; + + if (m_uiBlizzardTimer < uiDiff) + { + 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(9000, 13500); + } + else + m_uiBlizzardTimer -= uiDiff; + + if (m_uiWrathTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_WRATH_OF_MISERY : SPELL_WRATH_OF_MISERY_H) == CAST_OK) + m_uiWrathTimer = urand(12500, 17200); + } + else + m_uiWrathTimer -= uiDiff; + + if (!m_creature->IsNonMeleeSpellCasted(true)) // TODO Use this additional check, because might want to change the random target to be a target that is in LoS (which then is expensive) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FROSTBOLT : SPELL_FROSTBOLT_H); + + break; + } } }; @@ -116,6 +319,91 @@ CreatureAI* GetAI_boss_novos(Creature* pCreature) return new boss_novosAI(pCreature); } +// Small helper script to handle summoned adds for Novos +struct MANGOS_DLL_DECL npc_crystal_channel_targetAI : public ScriptedAI +{ + npc_crystal_channel_targetAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_draktharon_keep*)pCreature->GetInstanceData(); + } + + instance_draktharon_keep* m_pInstance; + + void Reset() override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_HULKING_CORPSE || pSummoned->GetEntry() == NPC_FETID_TROLL_CORPSE || pSummoned->GetEntry() == NPC_RISON_SHADOWCASTER) + { + // Let them move down the stairs + float fX, fY, fZ; + + // 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); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ, true, true); + } + } + } + + 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; + + if (!pSummoned->isInCombat() && m_pInstance) + { + if (Creature* pNovos = m_pInstance->GetSingleCreatureFromStorage(NPC_NOVOS)) + { + if (Unit* pTarget = pNovos->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + } +}; + +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) +{ + for (uint8 i = 0; i < MAX_CRYSTALS; ++i) + { + if (pAura->GetId() == aCrystalHandlerDeathSpells[i]) + { + if (pAura->GetEffIndex() == EFFECT_INDEX_0 && !bApply) + { + if (Creature* pCreature = (Creature*)pAura->GetTarget()) + { + if (instance_draktharon_keep* pInstance = (instance_draktharon_keep*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_NOVOS) == NOT_STARTED || pInstance->GetData(TYPE_NOVOS) == FAIL) + return true; + + pInstance->DoHandleCrystal(i); + + // Inform Novos about removed + if (Creature* pNovos = pInstance->GetSingleCreatureFromStorage(NPC_NOVOS)) + if (boss_novosAI* pNovosAI = dynamic_cast(pNovos->AI())) + pNovosAI->LostOneCrystal(); + } + } + } + + return true; + } + } + + return false; +} + void AddSC_boss_novos() { Script* pNewScript; @@ -124,4 +412,10 @@ void AddSC_boss_novos() pNewScript->Name = "boss_novos"; pNewScript->GetAI = &GetAI_boss_novos; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_crystal_channel_target"; + pNewScript->GetAI = &GetAI_npc_crystal_channel_target; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_crystal_channel_target; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/draktharon_keep/boss_tharonja.cpp b/scripts/northrend/draktharon_keep/boss_tharonja.cpp index 1295ac7aab..a241373bdc 100644 --- a/scripts/northrend/draktharon_keep/boss_tharonja.cpp +++ b/scripts/northrend/draktharon_keep/boss_tharonja.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss_Tharonja -SD%Complete: 20% -SDComment: +SD%Complete: 80% +SDComment: Encounter mechanic is not verified, spell CLEAR_GIFT_OF_THARONJA need core support SDCategory: Drak'Tharon Keep EndScriptData */ #include "precompiled.h" +#include "ObjectMgr.h" #include "draktharon_keep.h" enum @@ -33,7 +34,39 @@ enum SAY_FLESH_2 = -1600016, SAY_SKELETON_1 = -1600017, SAY_SKELETON_2 = -1600018, - SAY_DEATH = -1600019 + SAY_DEATH = -1600019, + + SPELL_CURSE_OF_LIFE = 49527, + SPELL_CURSE_OF_LIFE_H = 59972, + SPELL_RAIN_OF_FIRE = 49518, + SPELL_RAIN_OF_FIRE_H = 59971, + SPELL_SHADOW_VOLLEY = 49528, + SPELL_SHADOW_VOLLEY_H = 59973, + SPELL_LIGHTNING_BREATH = 49537, + SPELL_LIGHTNING_BREATH_H = 59963, + SPELL_EYE_BEAM = 49544, + SPELL_EYE_BEAM_H = 59965, + SPELL_POISON_CLOUD = 49548, + SPELL_POISON_CLOUD_H = 59969, + SPELL_DECAY_FLESH = 49356, // Has also unknown dummy aura onto all players while transforming + SPELL_GIFT_OF_THARONJA = 52509, + SPELL_RETURN_FLESH = 53463, // Has also unknown dummy aura onto all players while transforming + SPELL_CLEAR_GIFT_OF_THARONJA = 53242, + + SPELL_ACHIEVEMENT_CHECK = 61863, // Exact Purpose unknown, but is criteria (BE_SPELL_TARGET(28) and BE_SPELL_TARGET2(69)) + + // Only used to change display ID, might infact be some sort of UpdateEntry - TODO, research! + NPC_THARONJA_SKELETAL = 26632, + NPC_THARONJA_FLESH = 27696, +}; + +enum Phases +{ + PHASE_SKELETAL = 0, + PHASE_TAKE_FLESH = 1, + PHASE_FLESH = 2, + PHASE_RETURN_FLESH = 3, + PHASE_SKELETAL_END = 4, }; /*###### @@ -52,11 +85,30 @@ struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + Phases m_uiPhase; + + uint32 m_uiCurseLifeTimer; + uint32 m_uiRainFireTimer; + uint32 m_uiShadowVolleyTimer; + uint32 m_uiLightningBreathTimer; + uint32 m_uiEyeBeamTimer; + uint32 m_uiPoisonCloudTimer; + uint32 m_uiReturnFleshTimer; + + void Reset() override { + m_uiPhase = PHASE_SKELETAL; + + m_uiCurseLifeTimer = urand(15000, 20000); + m_uiRainFireTimer = urand(16000, 23000); // This timer is not very accurate + m_uiShadowVolleyTimer = urand(8000, 10000); + m_uiLightningBreathTimer = urand(3000, 4000); + m_uiEyeBeamTimer = urand(15000, 18000); // This timer is not very accurate + m_uiPoisonCloudTimer = urand(9000, 11000); // This timer is not very accurate + m_uiReturnFleshTimer = 26000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -64,31 +116,164 @@ 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); + DoCastSpellIfCan(m_creature, SPELL_ACHIEVEMENT_CHECK, CAST_TRIGGERED | CAST_FORCE_CAST); + + // TODO check if this spell casting is infact also needed on phase-switch or only here (possible that there is also some sort of hp% dependency + if (m_uiPhase == PHASE_FLESH) + DoCastSpellIfCan(m_creature, SPELL_CLEAR_GIFT_OF_THARONJA, CAST_TRIGGERED | CAST_FORCE_CAST); + if (m_pInstance) m_pInstance->SetData(TYPE_THARONJA, DONE); } - void JustReachedHome() + void JustReachedHome() override { + // Reset Display ID + if (CreatureInfo const* pCreatureInfo = GetCreatureTemplateStore(NPC_THARONJA_SKELETAL)) + { + uint32 uiDisplayId = Creature::ChooseDisplayId(pCreatureInfo); + if (m_creature->GetDisplayId() != uiDisplayId) + m_creature->SetDisplayId(uiDisplayId); + } + if (m_pInstance) 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; - DoMeleeAttackIfReady(); + switch (m_uiPhase) + { + case PHASE_SKELETAL: + // Phase switching at 50% (was in older patch versions multiple times, but from 335 on only once) + if (m_creature->GetHealthPercent() < 50) + { + if (DoCastSpellIfCan(m_creature, SPELL_DECAY_FLESH, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_FLESH_1 : SAY_FLESH_2, m_creature); + m_uiPhase = PHASE_TAKE_FLESH; + + return; // return here, as there is nothing more to be done in this phase + } + } + + // No break here, the last phase is exactly like the first, but he doesn't change anymore + case PHASE_SKELETAL_END: + if (m_uiCurseLifeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CURSE_OF_LIFE : SPELL_CURSE_OF_LIFE_H) == CAST_OK) + m_uiCurseLifeTimer = urand(12000, 18000); + } + else + m_uiCurseLifeTimer -= uiDiff; + + if (m_uiRainFireTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_RAIN_OF_FIRE : SPELL_RAIN_OF_FIRE_H) == CAST_OK) + m_uiRainFireTimer = urand(22000, 29000); + } + else + m_uiRainFireTimer -= uiDiff; + + if (m_uiShadowVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_VOLLEY : SPELL_SHADOW_VOLLEY_H) == CAST_OK) + m_uiShadowVolleyTimer = urand(6000, 12000); + } + else + m_uiShadowVolleyTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + + case PHASE_FLESH: + // This is not entirely clear if this _might_ also be triggered HP-dependend + if (m_uiReturnFleshTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RETURN_FLESH, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SKELETON_1 : SAY_SKELETON_2, m_creature); + m_uiReturnFleshTimer = 26000; + m_uiPhase = PHASE_RETURN_FLESH; + + return; // return here, as there is nothing more to be done in this phase + } + } + else + m_uiReturnFleshTimer -= uiDiff; + + if (m_uiPoisonCloudTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_POISON_CLOUD : SPELL_POISON_CLOUD_H) == CAST_OK) + m_uiPoisonCloudTimer = urand(7000, 12000); + } + else + m_uiPoisonCloudTimer -= uiDiff; + + if (m_uiLightningBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_LIGHTNING_BREATH : SPELL_LIGHTNING_BREATH_H) == CAST_OK) + m_uiLightningBreathTimer = urand(5000, 8000); + } + else + m_uiLightningBreathTimer -= uiDiff; + + if (m_uiEyeBeamTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_EYE_BEAM : SPELL_EYE_BEAM_H) == CAST_OK) + m_uiEyeBeamTimer = urand(12000, 15000); + } + else + m_uiEyeBeamTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + + case PHASE_TAKE_FLESH: + // Turn players into skeletons + if (DoCastSpellIfCan(m_creature, SPELL_GIFT_OF_THARONJA) == CAST_OK) + { + // Change modell - might be UpdateEntry + if (CreatureInfo const* pCreatureInfo = GetCreatureTemplateStore(NPC_THARONJA_FLESH)) + { + uint32 uiDisplayId = Creature::ChooseDisplayId(pCreatureInfo); + m_creature->SetDisplayId(uiDisplayId); + } + + m_uiPhase = PHASE_FLESH; + } + break; + + case PHASE_RETURN_FLESH: + // Turn players into normal + if (DoCastSpellIfCan(m_creature, SPELL_CLEAR_GIFT_OF_THARONJA) == CAST_OK) + { + // Change modell - might be UpdateEntry + if (CreatureInfo const* pCreatureInfo = GetCreatureTemplateStore(NPC_THARONJA_SKELETAL)) + { + uint32 uiDisplayId = Creature::ChooseDisplayId(pCreatureInfo); + m_creature->SetDisplayId(uiDisplayId); + } + + m_uiPhase = PHASE_SKELETAL_END; + } + break; + } } }; diff --git a/scripts/northrend/draktharon_keep/boss_trollgore.cpp b/scripts/northrend/draktharon_keep/boss_trollgore.cpp index 046917dc25..d558f4c072 100644 --- a/scripts/northrend/draktharon_keep/boss_trollgore.cpp +++ b/scripts/northrend/draktharon_keep/boss_trollgore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Trollgore -SD%Complete: 20% -SDComment: +SD%Complete: 80% +SDComment: Some details related to the summoned creatures need more adjustments SDCategory: Drak'Tharon Keep EndScriptData */ @@ -30,7 +30,23 @@ enum SAY_CONSUME = -1600001, SAY_DEATH = -1600002, SAY_EXPLODE = -1600003, - SAY_KILL = -1600004 + SAY_KILL = -1600004, + + SPELL_CRUSH = 49639, + SPELL_INFECTED_WOUND = 49637, + SPELL_CORPSE_EXPLODE = 49555, + SPELL_CORPSE_EXPLODE_H = 59807, + SPELL_CONSUME = 49380, + SPELL_CONSUME_H = 59803, + SPELL_CONSUME_BUFF = 49381, // used to measure the achiev + SPELL_CONSUME_BUFF_H = 59805, + + SPELL_SUMMON_INVADER_1 = 49456, // summon 27709 + SPELL_SUMMON_INVADER_2 = 49457, // summon 27753 + // SPELL_SUMMON_INVADER_3 = 49458, // summon 27754 + SPELL_INVADER_TAUNT = 49405, // triggers 49406 + + MAX_CONSOME_STACKS = 10, }; /*###### @@ -41,33 +57,52 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI { boss_trollgoreAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_draktharon_keep*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_draktharon_keep* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint8 m_uiConsumeStacks; + + uint32 m_uiConsumeTimer; + uint32 m_uiCrushTimer; + uint32 m_uiInfectedWoundTimer; + uint32 m_uiWaveTimer; + uint32 m_uiCorpseExplodeTimer; + + GuidVector m_vTriggers; + + void Reset() override { + m_uiCorpseExplodeTimer = 20000; + m_uiConsumeTimer = 15000; + m_uiCrushTimer = 10000; + m_uiInfectedWoundTimer = 5000; + m_uiWaveTimer = 0; + m_uiConsumeStacks = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) + { m_pInstance->SetData(TYPE_TROLLGORE, IN_PROGRESS); + m_pInstance->GetTrollgoreOutsideTriggers(m_vTriggers); + } } - 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); @@ -75,17 +110,121 @@ 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 UpdateAI(const uint32 uiDiff) + void SpellHit(Unit* /*pTarget*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_CONSUME_BUFF || pSpell->Id == SPELL_CONSUME_BUFF_H) + { + ++m_uiConsumeStacks; + + // if the boss has 10 stacks then set the achiev to fail + if (m_uiConsumeStacks == MAX_CONSOME_STACKS) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_TROLLGORE, SPECIAL); + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + // This spell taunts the boss and the boss taunts back + pSummoned->CastSpell(m_creature, SPELL_INVADER_TAUNT, true); + } + + // Wrapper to handle the drakkari invaders summon + void DoSummonDrakkariInvaders() + { + if (!m_pInstance) + return; + + // check if there are there are at least 2 triggers in the vector + if (m_vTriggers.size() < 2) + return; + + if (roll_chance_i(30)) + { + // Summon a troll in the corner and 2 trolls in the air + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetTrollgoreCornerTrigger())) + pTrigger->CastSpell(pTrigger, roll_chance_i(20) ? SPELL_SUMMON_INVADER_1 : SPELL_SUMMON_INVADER_2, true, NULL, NULL, m_creature->GetObjectGuid()); + + // get two random outside triggers + uint8 uiMaxTriggers = m_vTriggers.size(); + uint8 uiPos1 = urand(0, uiMaxTriggers - 1); + uint8 uiPos2 = (uiPos1 + urand(1, uiMaxTriggers - 1)) % uiMaxTriggers; + + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_vTriggers[uiPos1])) + pTrigger->CastSpell(pTrigger, roll_chance_i(30) ? SPELL_SUMMON_INVADER_1 : SPELL_SUMMON_INVADER_2, true, NULL, NULL, m_creature->GetObjectGuid()); + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_vTriggers[uiPos2])) + pTrigger->CastSpell(pTrigger, roll_chance_i(30) ? SPELL_SUMMON_INVADER_1 : SPELL_SUMMON_INVADER_2, true, NULL, NULL, m_creature->GetObjectGuid()); + } + else + { + // Summon 3 trolls in the air + 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()); + } + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiCrushTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSH) == CAST_OK) + m_uiCrushTimer = 10000; + } + else + m_uiCrushTimer -= uiDiff; + + if (m_uiInfectedWoundTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INFECTED_WOUND) == CAST_OK) + m_uiInfectedWoundTimer = urand(20000, 30000); + } + else + m_uiInfectedWoundTimer -= uiDiff; + + if (m_uiWaveTimer < uiDiff) + { + DoSummonDrakkariInvaders(); + m_uiWaveTimer = 30000; + } + else + m_uiWaveTimer -= uiDiff; + + if (m_uiConsumeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CONSUME : SPELL_CONSUME_H) == CAST_OK) + { + DoScriptText(SAY_CONSUME, m_creature); + m_uiConsumeTimer = 15000; + } + } + else + m_uiConsumeTimer -= uiDiff; + + if (m_uiCorpseExplodeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CORPSE_EXPLODE : SPELL_CORPSE_EXPLODE_H) == CAST_OK) + { + DoScriptText(SAY_EXPLODE, m_creature); + m_uiCorpseExplodeTimer = 10000; + } + } + else + m_uiCorpseExplodeTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; diff --git a/scripts/northrend/draktharon_keep/draktharon_keep.h b/scripts/northrend/draktharon_keep/draktharon_keep.h index 67093b4eb5..f3ab031b2d 100644 --- a/scripts/northrend/draktharon_keep/draktharon_keep.h +++ b/scripts/northrend/draktharon_keep/draktharon_keep.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -14,11 +14,27 @@ enum TYPE_KING_DRED = 2, TYPE_THARONJA = 3, + NPC_NOVOS = 26631, NPC_KING_DRED = 27483, // Adds of King Dred Encounter - deaths counted for achievement NPC_DRAKKARI_GUTRIPPER = 26641, NPC_DRAKKARI_SCYTHECLAW = 26628, + NPC_WORLD_TRIGGER = 22515, + + // Novos Encounter + SPELL_BEAM_CHANNEL = 52106, + SPELL_CRYSTAL_HANDLER_DEATH_1 = 47336, + SPELL_CRYSTAL_HANDLER_DEATH_2 = 55801, + SPELL_CRYSTAL_HANDLER_DEATH_3 = 55803, + SPELL_CRYSTAL_HANDLER_DEATH_4 = 55805, + + MAX_CRYSTALS = 4, + NPC_CRYSTAL_CHANNEL_TARGET = 26712, + GO_CRYSTAL_SW = 189299, + GO_CRYSTAL_NE = 189300, + GO_CRYSTAL_NW = 189301, + GO_CRYSTAL_SE = 189302, // Achievement Criterias to be handled with SD2 ACHIEV_CRIT_BETTER_OFF_DREAD = 7318, @@ -26,33 +42,64 @@ enum ACHIEV_CRIT_OH_NOVOS = 7361, }; +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}; + +struct NovosCrystalInfo +{ + ObjectGuid m_crystalGuid; + ObjectGuid m_channelGuid; + bool m_bWasUsed; +}; + class MANGOS_DLL_DECL 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) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - void OnCreatureEnterCombat(Creature* pCreature); - void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + void GetTrollgoreOutsideTriggers(GuidVector& vTriggers) { vTriggers = m_vTriggerGuids; } + ObjectGuid GetTrollgoreCornerTrigger() { return m_trollgoreCornerTriggerGuid; } - const char* Save() { return 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; + + Creature* GetNextCrystalTarget(Creature* pCrystalHandler, uint8& uiIndex); + void DoHandleCrystal(uint8 uiIndex); + Creature* GetSummonDummy(); protected: + void DoSortNovosDummies(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; + std::string m_strInstData; uint32 m_uiDreadAddsKilled; bool m_bNovosAddGrounded; bool m_bTrollgoreConsume; + + ObjectGuid m_novosChannelGuid; + ObjectGuid m_trollgoreCornerTriggerGuid; + + NovosCrystalInfo m_aNovosCrystalInfo[MAX_CRYSTALS]; + + 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 e25f823d3e..bf792ba32d 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -52,13 +52,165 @@ void instance_draktharon_keep::OnCreatureEvade(Creature* pCreature) void instance_draktharon_keep::OnCreatureDeath(Creature* pCreature) { if ((pCreature->GetEntry() == NPC_DRAKKARI_GUTRIPPER || pCreature->GetEntry() == NPC_DRAKKARI_SCYTHECLAW) && m_auiEncounter[TYPE_KING_DRED] == IN_PROGRESS) - m_uiDreadAddsKilled++; + ++m_uiDreadAddsKilled; if (pCreature->GetEntry() == NPC_KING_DRED) SetData(TYPE_KING_DRED, DONE); } -bool instance_draktharon_keep::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +void instance_draktharon_keep::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_NOVOS: + m_mNpcEntryGuidStore[NPC_NOVOS] = pCreature->GetObjectGuid(); + break; + case NPC_CRYSTAL_CHANNEL_TARGET: + m_lNovosDummyGuids.push_back(pCreature->GetObjectGuid()); + break; + case NPC_WORLD_TRIGGER: + if (pCreature->GetPositionZ() > 30.0f) + m_vTriggerGuids.push_back(pCreature->GetObjectGuid()); + else + m_trollgoreCornerTriggerGuid = pCreature->GetObjectGuid(); + break; + } +} + +void instance_draktharon_keep::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_CRYSTAL_SW: m_aNovosCrystalInfo[0].m_crystalGuid = pGo->GetObjectGuid(); break; + case GO_CRYSTAL_NW: m_aNovosCrystalInfo[1].m_crystalGuid = pGo->GetObjectGuid(); break; + case GO_CRYSTAL_SE: m_aNovosCrystalInfo[2].m_crystalGuid = pGo->GetObjectGuid(); break; + case GO_CRYSTAL_NE: m_aNovosCrystalInfo[3].m_crystalGuid = pGo->GetObjectGuid(); break; + } +} + +void instance_draktharon_keep::DoSortNovosDummies() +{ + // Sorting once is good enough + if (m_lNovosDummyGuids.empty()) + return; + + Creature* pNovos = GetSingleCreatureFromStorage(NPC_NOVOS); + if (!pNovos) + return; + + // First sort the Dummies to the Crystals + for (uint8 i = 0; i < MAX_CRYSTALS; ++i) + { + GameObject* pCrystal = instance->GetGameObject(m_aNovosCrystalInfo[i].m_crystalGuid); + if (!pCrystal) + continue; + + for (GuidList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) + { + Creature* pDummy = instance->GetCreature(*itr); + if (!pDummy) + { + m_lNovosDummyGuids.erase(itr++); + continue; + } + + // Check if dummy fits to crystal + if (pCrystal->IsWithinDistInMap(pDummy, INTERACTION_DISTANCE, false)) + { + m_aNovosCrystalInfo[i].m_channelGuid = pDummy->GetObjectGuid(); + m_lNovosDummyGuids.erase(itr); + break; + } + + ++itr; + } + } + + // 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();) + { + Creature* pDummy = instance->GetCreature(*itr); + if (!pDummy) + { + m_lNovosDummyGuids.erase(itr++); + continue; + } + + // As the wanted dummy is exactly above Novos, check small range, and only 2d + if (pDummy->IsWithinDist2d(fNovosX, fNovosY, 5.0f)) + { + m_novosChannelGuid = pDummy->GetObjectGuid(); + itr = m_lNovosDummyGuids.erase(itr); + } + else + ++itr; + } + + // Summon positions (at end of stairs) + for (GuidList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) + { + Creature* pDummy = instance->GetCreature(*itr); + if (!pDummy) + { + m_lNovosDummyGuids.erase(itr++); + continue; + } + + // The wanted dummies are quite above Novos + if (pDummy->GetPositionZ() > fNovosZ + 20.0f) + { + m_vSummonDummyGuids.push_back(pDummy->GetObjectGuid()); + itr = m_lNovosDummyGuids.erase(itr); + } + else + ++itr; + } + + // Clear remaining (unused) dummies + m_lNovosDummyGuids.clear(); +} + +Creature* instance_draktharon_keep::GetNextCrystalTarget(Creature* pCrystalHandler, uint8& uiIndex) +{ + Creature* pTarget = NULL; + uiIndex = 0; + + for (uint8 i = 0; i < MAX_CRYSTALS; ++i) + { + Creature* pDummy = instance->GetCreature(m_aNovosCrystalInfo[i].m_channelGuid); + // Return the nearest 'unused' crystal dummy + // unused means, that the crystal was not already used, and the dummy-npc doesn't have the aura that will trigger the use on remove + if (pDummy && !m_aNovosCrystalInfo[i].m_bWasUsed && (!pTarget || pCrystalHandler->GetDistanceOrder(pDummy, pTarget)) && !pDummy->HasAura(aCrystalHandlerDeathSpells[i])) + { + pTarget = pDummy; + uiIndex = i; + } + } + + return pTarget; +} + +void instance_draktharon_keep::DoHandleCrystal(uint8 uiIndex) +{ + m_aNovosCrystalInfo[uiIndex].m_bWasUsed = true; + + DoUseDoorOrButton(m_aNovosCrystalInfo[uiIndex].m_crystalGuid); + + if (Creature* pDummy = instance->GetCreature(m_aNovosCrystalInfo[uiIndex].m_channelGuid)) + pDummy->InterruptNonMeleeSpells(false); +} + +Creature* instance_draktharon_keep::GetSummonDummy() +{ + if (m_vSummonDummyGuids.empty()) + return NULL; + + 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*/) const { switch (uiCriteriaId) { @@ -72,7 +224,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) @@ -82,10 +234,43 @@ void instance_draktharon_keep::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; case TYPE_NOVOS: - if (uiData == IN_PROGRESS) + if (uiData == IN_PROGRESS && m_auiEncounter[uiType] != IN_PROGRESS) + { + // Sort the dummies + DoSortNovosDummies(); + + // Cast some visual spells + Creature* pTarget = instance->GetCreature(m_novosChannelGuid); + for (uint8 i = 0; i < MAX_CRYSTALS; ++i) + { + Creature* pCaster = instance->GetCreature(m_aNovosCrystalInfo[i].m_channelGuid); + if (pCaster && pTarget) + pCaster->CastSpell(pTarget, SPELL_BEAM_CHANNEL, false); + + m_aNovosCrystalInfo[i].m_bWasUsed = false; + } + + // Achievement related m_bNovosAddGrounded = false; - if (uiData == SPECIAL) + } + else if (uiData == SPECIAL) + { + // Achievement related m_bNovosAddGrounded = true; + } + else if (uiData == FAIL) + { + // Interrupt casted spells + for (uint8 i = 0; i < MAX_CRYSTALS; ++i) + { + Creature* pDummy = instance->GetCreature(m_aNovosCrystalInfo[i].m_channelGuid); + if (pDummy) + pDummy->InterruptNonMeleeSpells(false); + // And reset used crystals + if (m_aNovosCrystalInfo[i].m_bWasUsed) + DoUseDoorOrButton(m_aNovosCrystalInfo[i].m_crystalGuid); + } + } m_auiEncounter[uiType] = uiData; break; case TYPE_KING_DRED: @@ -96,6 +281,8 @@ void instance_draktharon_keep::SetData(uint32 uiType, uint32 uiData) case TYPE_THARONJA: m_auiEncounter[uiType] = uiData; break; + default: + return; } if (uiData == DONE) @@ -105,7 +292,7 @@ void instance_draktharon_keep::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -125,7 +312,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; @@ -134,9 +321,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 e5c1c67f92..df147c0688 100644 --- a/scripts/northrend/grizzly_hills.cpp +++ b/scripts/northrend/grizzly_hills.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,8 +17,365 @@ /* ScriptData SDName: Grizzly_Hills SD%Complete: -SDComment: +SDComment: Quest support: 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" + +/*###### +## npc_depleted_war_golem +######*/ + +enum +{ + SAY_GOLEM_CHARGE = -1000626, + SAY_GOLEM_COMPLETE = -1000627, + + NPC_LIGHTNING_SENTRY = 26407, + + SPELL_CHARGE_GOLEM = 47799, + SPELL_GOLEM_CHARGE_CREDIT = 47797, +}; + +struct MANGOS_DLL_DECL npc_depleted_war_golemAI : public ScriptedPetAI +{ + npc_depleted_war_golemAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + void Reset() override { } + + void OwnerKilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetEntry() == NPC_LIGHTNING_SENTRY) + { + // Is distance expected? + if (m_creature->IsWithinDistInMap(pVictim, 10.0f)) + m_creature->CastSpell(m_creature, SPELL_CHARGE_GOLEM, true); + } + } +}; + +CreatureAI* GetAI_npc_depleted_war_golem(Creature* pCreature) +{ + return new npc_depleted_war_golemAI(pCreature); +} + +bool EffectAuraDummy_npc_depleted_war_golem(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() != SPELL_CHARGE_GOLEM) + return true; + + Creature* pCreature = (Creature*)pAura->GetTarget(); + + if (!pCreature) + return true; + + if (pAura->GetEffIndex() == EFFECT_INDEX_0) + { + if (bApply) + { + DoScriptText(SAY_GOLEM_CHARGE, pCreature); + pCreature->addUnitState(UNIT_STAT_STUNNED); + } + else + { + DoScriptText(SAY_GOLEM_COMPLETE, pCreature); + pCreature->clearUnitState(UNIT_STAT_STUNNED); + + // targets master + pCreature->CastSpell(pCreature, SPELL_GOLEM_CHARGE_CREDIT, true); + } + } + + 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 MANGOS_DLL_DECL 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; +} + +void AddSC_grizzly_hills() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_depleted_war_golem"; + 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(); +} diff --git a/scripts/northrend/gundrak/boss_colossus.cpp b/scripts/northrend/gundrak/boss_colossus.cpp index e10df4f2f7..c00e70ed92 100644 --- a/scripts/northrend/gundrak/boss_colossus.cpp +++ b/scripts/northrend/gundrak/boss_colossus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 e6c17ef55b..07223fcb41 100644 --- a/scripts/northrend/gundrak/boss_eck.cpp +++ b/scripts/northrend/gundrak/boss_eck.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 436aee65fb..b7a60be752 100644 --- a/scripts/northrend/gundrak/boss_galdarah.cpp +++ b/scripts/northrend/gundrak/boss_galdarah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -61,7 +61,7 @@ enum SPELL_IMPALING_CHARGE = 54956, SPELL_IMPALING_CHARGE_H = 59827, SPELL_STOMP = 55292, - SPELL_STOMP_H = 59826, + SPELL_STOMP_H = 59829, }; /*###### @@ -89,7 +89,7 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI uint32 m_uiEnrageTimer; uint8 m_uiAbilityCount; - void Reset() + void Reset() override { m_bIsTrollPhase = true; @@ -100,17 +100,18 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI m_uiAbilityCount = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { + m_creature->SetInCombatWithZone(); DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) 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,27 +119,39 @@ 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); if (m_pInstance) m_pInstance->SetData(TYPE_GALDARAH, DONE); + + if (pKiller->HasAura(55817)) + m_pInstance->DoCompleteAchievement(ACHIEVEMENT_WHAT_THE_ECK); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { + pSummoned->setFaction(m_creature->getFaction()); + if (pSummoned->GetEntry() == NPC_RHINO_SPIRIT) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - pSummoned->CastSpell(pTarget, m_bIsRegularMode ? SPELL_STAMPEDE_RHINO : SPELL_STAMPEDE_RHINO_H, false); + 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()); + } } + pSummoned->ForcedDespawn(1000); } void DoPhaseSwitch() @@ -164,12 +177,12 @@ 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; - if (m_uiAbilityCount == 2) + if (m_uiAbilityCount >= 2) { if (m_uiPhaseChangeTimer < uiDiff) DoPhaseSwitch(); @@ -189,7 +202,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 +224,6 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI } else m_uiSpecialAbilityTimer -= uiDiff; - } else { @@ -234,8 +246,10 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI if (m_uiSpecialAbilityTimer < uiDiff) { Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - if (DoCastSpellIfCan(pTarget ? pTarget : m_creature->getVictim(), m_bIsRegularMode ? SPELL_IMPALING_CHARGE : SPELL_IMPALING_CHARGE_H) == CAST_OK) + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_IMPALING_CHARGE : SPELL_IMPALING_CHARGE_H) == CAST_OK) { DoScriptText(EMOTE_IMPALED, m_creature, pTarget); m_uiSpecialAbilityTimer = 12000; diff --git a/scripts/northrend/gundrak/boss_moorabi.cpp b/scripts/northrend/gundrak/boss_moorabi.cpp index 05cb78e821..3cc1fc0bfb 100644 --- a/scripts/northrend/gundrak/boss_moorabi.cpp +++ b/scripts/northrend/gundrak/boss_moorabi.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -66,7 +66,6 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI instance_gundrak* m_pInstance; bool m_bIsRegularMode; - uint32 m_uiStabTimer; // used for stab and gore uint32 m_uiQuakeTimer; // used for quake and ground tremor uint32 m_uiRoarTimer; // both roars on it @@ -75,7 +74,7 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI bool m_bMammothPhase; - void Reset() + void Reset() override { m_bMammothPhase = false; @@ -86,18 +85,25 @@ 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); + m_creature->SetInCombatWithZone(); if (m_pInstance) m_pInstance->SetData(TYPE_MOORABI, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void JustReachedHome() override { - switch(urand(0, 2)) + if(m_pInstance) + m_pInstance->SetData(TYPE_MOORABI, NOT_STARTED); + } + + 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; @@ -105,15 +111,23 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_MOORABI, DONE); + + if (!m_bIsRegularMode) + { + if (m_bMammothPhase) + return; + else + m_pInstance->DoCompleteAchievement(2040); + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -122,6 +136,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) @@ -179,10 +197,10 @@ CreatureAI* GetAI_boss_moorabi(Creature* pCreature) void AddSC_boss_moorabi() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_moorabi"; - newscript->GetAI = &GetAI_boss_moorabi; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_moorabi"; + pNewScript->GetAI = &GetAI_boss_moorabi; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/gundrak/boss_sladran.cpp b/scripts/northrend/gundrak/boss_sladran.cpp index a472c65eaa..594245f028 100644 --- a/scripts/northrend/gundrak/boss_sladran.cpp +++ b/scripts/northrend/gundrak/boss_sladran.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -47,18 +47,115 @@ 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_constrictor +######*/ + +struct MANGOS_DLL_DECL mob_sladran_constrictorAI : public ScriptedAI +{ + mob_sladran_constrictorAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_gundrak* m_pInstance; + bool m_bIsRegularMode; + uint32 m_uiWrapTimer; + + void Reset() + { + m_uiWrapTimer = 5000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiWrapTimer <= uiDiff) + { + if (m_pInstance) + if (Creature* pSladran = m_pInstance->GetSingleCreatureFromStorage(NPC_SLADRAN)) + m_creature->CastSpell(m_creature->getVictim(), m_bIsRegularMode ? SPELL_GRIP_OF_SLADRAN : SPELL_GRIP_OF_SLADRAN_H, false, 0, 0, pSladran->GetObjectGuid()); + m_uiWrapTimer = 5000; + } + else m_uiWrapTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_sladran_constrictor(Creature* pCreature) +{ + return new mob_sladran_constrictorAI(pCreature); +} + +/*###### +## mob_sladran_snake_wrap +######*/ + +struct MANGOS_DLL_DECL mob_sladran_snake_wrapAI : public ScriptedAI +{ + mob_sladran_snake_wrapAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); + Reset(); + } + + instance_gundrak* m_pInstance; + + void Reset() + { + m_creature->setFaction(14); + SetCombatMovement(false); + } + void MoveInLineOfSight(Unit* pWho) override { } + void AttackStart(Unit* pWho) override {} + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + if (Unit *pTarget = m_pInstance->instance->GetUnit(m_creature->GetCreatorGuid())) + { + pTarget->RemoveAurasDueToSpell(SPELL_SNAKE_WRAP_SUMMON); + pTarget->RemoveAurasDueToSpell(SPELL_SNAKE_WRAP_SUMMON_H); + } + } + + void UpdateAI(const uint32 diff) {} +}; + +CreatureAI* GetAI_mob_sladran_snake_wrap(Creature* pCreature) +{ + return new mob_sladran_snake_wrapAI(pCreature); +} + /*###### ## mob_sladran_summon_target ######*/ + struct MANGOS_DLL_DECL mob_sladran_summon_targetAI : public ScriptedAI { mob_sladran_summon_targetAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -70,19 +167,19 @@ struct MANGOS_DLL_DECL mob_sladran_summon_targetAI : public ScriptedAI instance_gundrak* m_pInstance; void Reset() {} - void MoveInLineOfSight(Unit* pWho) {} - void AttackStart(Unit* pWho) {} + void MoveInLineOfSight(Unit* pWho) override { } + void AttackStart(Unit* pWho) override {} - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (!m_pInstance) return; - if (Creature* pSladran = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(NPC_SLADRAN))) + if (Creature* pSladran = m_pInstance->GetSingleCreatureFromStorage(NPC_SLADRAN)) { - float fPosX, fPosY, fPosZ; - pSladran->GetPosition(fPosX, fPosY, fPosZ); - pSummoned->GetMotionMaster()->MovePoint(0, fPosX, fPosY, fPosZ); + pSummoned->setFaction(pSladran->getFaction()); + if (Unit *pTarget = pSladran->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } } @@ -97,16 +194,17 @@ CreatureAI* GetAI_mob_sladran_summon_target(Creature* pCreature) /*###### ## boss_sladran ######*/ + struct MANGOS_DLL_DECL 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 +212,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,17 +220,17 @@ 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); - + m_creature->SetInCombatWithZone(); if (m_pInstance) 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 +238,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 +246,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 +290,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 +298,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 +309,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 +318,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; @@ -232,15 +337,25 @@ CreatureAI* GetAI_boss_sladran(Creature* pCreature) void AddSC_boss_sladran() { - Script* newscript; - - newscript = new Script; - newscript->Name = "boss_sladran"; - newscript->GetAI = &GetAI_boss_sladran; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_sladran_summon_target"; - newscript->GetAI = &GetAI_mob_sladran_summon_target; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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(); + + pNewScript = new Script; + pNewScript->Name = "mob_sladran_snake_wrap"; + pNewScript->GetAI = &GetAI_mob_sladran_snake_wrap; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_sladran_constrictor"; + pNewScript->GetAI = &GetAI_mob_sladran_constrictor; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/gundrak/gundrak.h b/scripts/northrend/gundrak/gundrak.h index 7f4ac4b314..11d20c0314 100644 --- a/scripts/northrend/gundrak/gundrak.h +++ b/scripts/northrend/gundrak/gundrak.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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,13 +22,20 @@ 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, NPC_ELEMENTAL = 29573, - NPC_LIVIN_MOJO = 29830, + NPC_LIVING_MOJO = 29830, NPC_GALDARAH = 29306, NPC_ECK = 29932, + NPC_INVISIBLE_STALKER = 30298, // Caster and Target for visual spells on altar use + NPC_SLADRAN_SUMMON_T = 29682, + NPC_RUIN_DWELLER = 29920, GO_ECK_DOOR = 192632, GO_ECK_UNDERWATER_DOOR = 192569, @@ -45,47 +53,69 @@ enum GO_RHINO_KEY = 192566, GO_BRIDGE = 193188, - GO_COLLISION = 192633 + GO_COLLISION = 192633, + + SPELL_BEAM_MAMMOTH = 57068, + SPELL_BEAM_SNAKE = 57071, + SPELL_BEAM_ELEMENTAL = 57072, + + 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 { 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); - uint64 GetData64(uint32 uiData); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); + ObjectGuid SelectRandomSladranTargetGuid(); + + 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); uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiEckDoorGUID; - uint64 m_uiEckUnderwaterDoorGUID; - uint64 m_uiGaldarahDoorGUID; - uint64 m_uiExitDoorLeftGUID; - uint64 m_uiExitDoorRightGUID; - uint64 m_uiSnakeKeyGUID; - uint64 m_uiMammothKeyGUID; - uint64 m_uiTrollKeyGUID; - uint64 m_uiAltarOfSladranGUID; - uint64 m_uiAltarOfMoorabiGUID; - uint64 m_uiAltarOfColossusGUID; - uint64 m_uiBridgeGUID; - - uint64 m_uiSladranGUID; - uint64 m_uiElementalGUID; - uint64 m_uiColossusGUID; + std::string m_strInstData; + + TypeTimerMap m_mAltarInProgress; + TypeTimerMap m_mBeamInProgress; + TypeTimerMap m_mKeyInProgress; + + 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 63be2a2f9e..927530ec9d 100644 --- a/scripts/northrend/gundrak/instance_gundrak.cpp +++ b/scripts/northrend/gundrak/instance_gundrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,49 +16,34 @@ /* ScriptData SDName: instance_gundrak -SD%Complete: 0 -SDComment: +SD%Complete: 80 +SDComment: Reload case for bridge support is missing, achievement support is missing SDCategory: Gundrak EndScriptData */ #include "precompiled.h" #include "gundrak.h" -bool GOHello_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; case GO_ALTAR_OF_COLOSSUS: pInstance->SetData(TYPE_COLOSSUS, SPECIAL); break; } - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGo->UseDoorOrButton(0, true); return true; } instance_gundrak::instance_gundrak(Map* pMap) : ScriptedInstance(pMap), - m_uiEckDoorGUID(0), - m_uiEckUnderwaterDoorGUID(0), - m_uiGaldarahDoorGUID(0), - m_uiExitDoorLeftGUID(0), - m_uiExitDoorRightGUID(0), - m_uiSnakeKeyGUID(0), - m_uiMammothKeyGUID(0), - m_uiTrollKeyGUID(0), - m_uiAltarOfSladranGUID(0), - m_uiAltarOfMoorabiGUID(0), - m_uiAltarOfColossusGUID(0), - m_uiBridgeGUID(0), - - m_uiSladranGUID(0), - m_uiElementalGUID(0), - m_uiColossusGUID(0) + m_bLessRabi(false) { Initialize(); } @@ -66,81 +51,99 @@ instance_gundrak::instance_gundrak(Map* pMap) : ScriptedInstance(pMap), void instance_gundrak::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + m_vStalkerCasterGuids.reserve(3); + m_vStalkerTargetGuids.reserve(3); } void instance_gundrak::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - case NPC_SLADRAN: m_uiSladranGUID = pCreature->GetGUID(); break; - case NPC_ELEMENTAL: m_uiElementalGUID = pCreature->GetGUID(); break; - case NPC_COLOSSUS: m_uiColossusGUID = pCreature->GetGUID(); break; + case NPC_ECK: + case NPC_SLADRAN: + case NPC_ELEMENTAL: + case NPC_COLOSSUS: + case NPC_MOORABI: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + 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_LIVING_MOJO: + // Store only the Mojos used to activate the Colossus + if (pCreature->GetPositionX() > 1650.0f) + m_sColossusMojosGuids.insert(pCreature->GetObjectGuid()); + break; } } +/* TODO: Reload case need some love! +* Problem is to get the bridge/ collision work correct in relaod case. +* To provide correct functionality(expecting testers to activate all altars in reload case), the Keys aren't loaded, too +* TODO: When fixed, also remove the SPECIAL->DONE data translation in Load(). +* +* For the Keys should be used something like this, and for bridge and collision similar +* +* if (m_auiEncounter[0] == SPECIAL && m_auiEncounter[1] == SPECIAL && m_auiEncounter[2] == SPECIAL) +* pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); +* else +* pGo->SetGoState(GO_STATE_READY); +*/ + void instance_gundrak::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_ECK_DOOR: - m_uiEckDoorGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_MOORABI] == DONE && !instance->IsRegularDifficulty()) - DoUseDoorOrButton(m_uiEckDoorGUID); + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ECK_UNDERWATER_DOOR: - m_uiEckUnderwaterDoorGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_ECK] == DONE) - DoUseDoorOrButton(m_uiEckUnderwaterDoorGUID); + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_GALDARAH_DOOR: - m_uiGaldarahDoorGUID = pGo->GetGUID(); - DoUseDoorOrButton(m_uiGaldarahDoorGUID); + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_EXIT_DOOR_L: - m_uiExitDoorLeftGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_GALDARAH] == DONE) - DoUseDoorOrButton(m_uiExitDoorLeftGUID); + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_EXIT_DOOR_R: - m_uiExitDoorRightGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_GALDARAH] == DONE) - DoUseDoorOrButton(m_uiExitDoorRightGUID); + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ALTAR_OF_SLADRAN: - m_uiAltarOfSladranGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_SLADRAN] == DONE) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; case GO_ALTAR_OF_MOORABI: - m_uiAltarOfMoorabiGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_MOORABI] == DONE) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; case GO_ALTAR_OF_COLOSSUS: - m_uiAltarOfColossusGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_COLOSSUS] == DONE) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - case GO_SNAKE_KEY: - m_uiSnakeKeyGUID = pGo->GetGUID(); - if (m_auiEncounter[TYPE_SLADRAN] == SPECIAL) - DoUseDoorOrButton(m_uiSnakeKeyGUID); + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; + case GO_SNAKE_KEY: case GO_TROLL_KEY: - m_uiTrollKeyGUID = pGo->GetGUID(); - if (m_auiEncounter[TYPE_COLOSSUS] == SPECIAL) - DoUseDoorOrButton(m_uiTrollKeyGUID); - break; case GO_MAMMOTH_KEY: - m_uiMammothKeyGUID = pGo->GetGUID(); - if (m_auiEncounter[TYPE_MOORABI] == SPECIAL) - DoUseDoorOrButton(m_uiMammothKeyGUID); - break; + case GO_RHINO_KEY: case GO_BRIDGE: - m_uiBridgeGUID = pGo->GetGUID(); + case GO_COLLISION: break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } + void instance_gundrak::Load(const char* chrIn) { if (!chrIn) @@ -154,10 +157,14 @@ 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; + + // TODO: REMOVE when bridge/ collision reloading correctly working + if (m_auiEncounter[i] == SPECIAL) + m_auiEncounter[i] = DONE; } OUT_LOAD_INST_DATA_COMPLETE; @@ -165,102 +172,300 @@ void instance_gundrak::Load(const char* chrIn) void instance_gundrak::SetData(uint32 uiType, uint32 uiData) { - debug_log("SD2: Instance Gundrak: SetData received for type %u with data %u",uiType,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 = instance->GetGameObject(m_uiAltarOfSladranGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + 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) - DoUseDoorOrButton(m_uiSnakeKeyGUID); + m_mAltarInProgress.insert(TypeTimerPair(TYPE_SLADRAN, TIMER_VISUAL_ALTAR)); break; case TYPE_MOORABI: m_auiEncounter[TYPE_MOORABI] = uiData; if (uiData == DONE) { if (!instance->IsRegularDifficulty()) - DoUseDoorOrButton(m_uiEckDoorGUID); - if (GameObject* pGo = instance->GetGameObject(m_uiAltarOfMoorabiGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + DoUseDoorOrButton(GO_ECK_DOOR); + 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) - DoUseDoorOrButton(m_uiMammothKeyGUID); + m_mAltarInProgress.insert(TypeTimerPair(TYPE_MOORABI, TIMER_VISUAL_ALTAR)); break; case TYPE_COLOSSUS: m_auiEncounter[TYPE_COLOSSUS] = uiData; if (uiData == DONE) - if (GameObject* pGo = instance->GetGameObject(m_uiAltarOfColossusGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + 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) - DoUseDoorOrButton(m_uiTrollKeyGUID); + m_mAltarInProgress.insert(TypeTimerPair(TYPE_COLOSSUS, TIMER_VISUAL_ALTAR)); break; case TYPE_GALDARAH: m_auiEncounter[TYPE_GALDARAH] = uiData; - DoUseDoorOrButton(m_uiGaldarahDoorGUID); + DoUseDoorOrButton(GO_GALDARAH_DOOR); if (uiData == DONE) { - DoUseDoorOrButton(m_uiExitDoorLeftGUID); - DoUseDoorOrButton(m_uiExitDoorRightGUID); + 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(m_uiEckUnderwaterDoorGUID); + DoUseDoorOrButton(GO_ECK_UNDERWATER_DOOR); break; - default: - error_log("SD2: Instance Gundrak: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + 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: + script_error_log("Instance Gundrak: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; } - if (uiData == DONE) + if (uiData == DONE || uiData == SPECIAL) // Save activated altars, too { OUT_SAVE_INST_DATA; 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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; } } -uint32 instance_gundrak::GetData(uint32 uiType) +uint32 instance_gundrak::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +bool instance_gundrak::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { - switch(uiType) + switch (uiCriteriaId) { - case TYPE_SLADRAN: - return m_auiEncounter[TYPE_SLADRAN]; - case TYPE_MOORABI: - return m_auiEncounter[TYPE_MOORABI]; - case TYPE_COLOSSUS: - return m_auiEncounter[TYPE_COLOSSUS]; - case TYPE_GALDARAH: - return m_auiEncounter[TYPE_GALDARAH]; - case TYPE_ECK: - return m_auiEncounter[TYPE_ECK]; + 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; } - return 0; } -uint64 instance_gundrak::GetData64(uint32 uiType) +void instance_gundrak::OnCreatureEnterCombat(Creature* pCreature) { - switch(uiType) + if (pCreature->GetEntry() == NPC_LIVING_MOJO) { - case NPC_SLADRAN: - return m_uiSladranGUID; - case NPC_ELEMENTAL: - return m_uiElementalGUID; - case NPC_COLOSSUS: - return m_uiColossusGUID; + // 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(); +} + +void instance_gundrak::DoAltarVisualEffect(uint8 uiType) +{ + // Sort the lists if not yet done + if (!m_luiStalkerGUIDs.empty()) + { + float fHeight = 10.0f; // A bit higher than the altar is needed + if (GameObject* pCollusAltar = GetSingleGameObjectFromStorage(GO_ALTAR_OF_COLOSSUS)) + fHeight += pCollusAltar->GetPositionZ(); + + std::list lStalkerTargets, lStalkerCasters; + for (GuidList::const_iterator itr = m_luiStalkerGUIDs.begin(); itr != m_luiStalkerGUIDs.end(); ++itr) + { + if (Creature* pStalker = instance->GetCreature(*itr)) + { + if (pStalker->GetPositionZ() > fHeight) + lStalkerTargets.push_back(pStalker); + else + lStalkerCasters.push_back(pStalker); + } + } + m_luiStalkerGUIDs.clear(); + + lStalkerTargets.sort(sortFromEastToWest); + lStalkerCasters.sort(sortFromEastToWest); + + for (std::list::const_iterator itr = lStalkerTargets.begin(); itr != lStalkerTargets.end(); ++itr) + m_vStalkerTargetGuids.push_back((*itr)->GetObjectGuid()); + for (std::list::const_iterator itr = lStalkerCasters.begin(); itr != lStalkerCasters.end(); ++itr) + m_vStalkerCasterGuids.push_back((*itr)->GetObjectGuid()); + } + + // Verify that the DB has enough trigger spawned + if (m_vStalkerTargetGuids.size() < 3 || m_vStalkerCasterGuids.size() < 3) + return; + + // Get the Index from the bosses + uint8 uiIndex = 0; + switch (uiType) + { + case TYPE_SLADRAN: uiIndex = 0; break; + case TYPE_COLOSSUS: uiIndex = 1; break; + case TYPE_MOORABI: uiIndex = 2; break; + default: + return; + } + + Creature* pTarget = instance->GetCreature(m_vStalkerTargetGuids[uiIndex]); + Creature* pCaster = instance->GetCreature(m_vStalkerCasterGuids[uiIndex]); + + if (!pTarget || !pCaster) + return; + + uint32 auiFireBeamSpells[3] = {SPELL_BEAM_SNAKE, SPELL_BEAM_ELEMENTAL, SPELL_BEAM_MAMMOTH}; + + // Cast from Caster to Target + pCaster->CastSpell(pTarget, auiFireBeamSpells[uiIndex], false); +} + +void instance_gundrak::Update(uint32 uiDiff) +{ + // Possible multible altars used at the same time, process their timers + if (!m_mAltarInProgress.empty()) + { + for (TypeTimerMap::iterator itr = m_mAltarInProgress.begin(); itr != m_mAltarInProgress.end();) + { + if (itr->second < uiDiff) + { + // Do Visual Effect + DoAltarVisualEffect(itr->first); + // Set Timer for Beam-Duration + m_mBeamInProgress.insert(TypeTimerPair(itr->first, TIMER_VISUAL_BEAM)); + // Remove this timer, as processed + m_mAltarInProgress.erase(itr++); + } + else + { + itr->second -= uiDiff; + ++itr; + } + } + } + + // Possible multible beams used at the same time, process their timers + if (!m_mBeamInProgress.empty()) + { + for (TypeTimerMap::iterator itr = m_mBeamInProgress.begin(); itr != m_mBeamInProgress.end();) + { + if (itr->second < uiDiff) + { + // Use Key + switch (itr->first) + { + case TYPE_SLADRAN: DoUseDoorOrButton(GO_SNAKE_KEY); break; + case TYPE_MOORABI: DoUseDoorOrButton(GO_MAMMOTH_KEY); break; + case TYPE_COLOSSUS: DoUseDoorOrButton(GO_TROLL_KEY); break; + } + // Set Timer for Beam-Duration + m_mKeyInProgress.insert(TypeTimerPair(itr->first, TIMER_VISUAL_KEY)); + m_mBeamInProgress.erase(itr++); + } + else + { + itr->second -= uiDiff; + ++itr; + } + } + } + + // Activate Bridge if all Three Encounters are used + if (!m_mKeyInProgress.empty()) + { + for (TypeTimerMap::iterator itr = m_mKeyInProgress.begin(); itr != m_mKeyInProgress.end();) + { + if (itr->second < 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) + { + DoUseDoorOrButton(GO_COLLISION); + DoUseDoorOrButton(GO_RHINO_KEY, 0, true); + + // The already closed keys cannot be done with DoUseDoorOrButton + if (GameObject* pTrollKey = GetSingleGameObjectFromStorage(GO_TROLL_KEY)) + pTrollKey->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + if (GameObject* pMammothKey = GetSingleGameObjectFromStorage(GO_MAMMOTH_KEY)) + pMammothKey->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + if (GameObject* pSnakeKey = GetSingleGameObjectFromStorage(GO_SNAKE_KEY)) + pSnakeKey->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + + // GO_BRIDGE is type 35 (TRAP_DOOR) and needs to be handled directly + // Real Use of this GO is unknown, but this change of state is expected + DoUseDoorOrButton(GO_BRIDGE); + } + // Remove this timer, as processed + m_mKeyInProgress.erase(itr++); + } + else + { + itr->second -= uiDiff; + ++itr; + } + } } - return 0; } InstanceData* GetInstanceData_instance_gundrak(Map* pMap) @@ -274,7 +479,7 @@ void AddSC_instance_gundrak() pNewScript = new Script; pNewScript->Name = "go_gundrak_altar"; - pNewScript->pGOHello = &GOHello_go_gundrak_altar; + pNewScript->pGOUse = &GOUse_go_gundrak_altar; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/northrend/howling_fjord.cpp b/scripts/northrend/howling_fjord.cpp index 3ab3e90be2..ae9e187cf2 100644 --- a/scripts/northrend/howling_fjord.cpp +++ b/scripts/northrend/howling_fjord.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,19 +17,133 @@ /* ScriptData SDName: Howling_Fjord SD%Complete: ? -SDComment: Quest support: 11221, 11483, 11300, 11464 +SDComment: Quest support: 11154, 11241, 11300, 11343, 11344, 11464, 11476. SDCategory: Howling Fjord EndScriptData */ /* ContentData +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_mcgoyver - 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_WYRMSKULL = 43458, + QUEST_ECHO_OF_YMIRON = 11343, + NPC_MALE_VRYKUL = 24314, + NPC_FEMALE_VRYKUL = 24315, + + SAY_VRYKUL_CURSED = -1000635, + EMOTE_VRYKUL_POINT = -1000636, + EMOTE_VRYKUL_SOB = -1000637, + SAY_VRYKUL_DISPOSE = -1000638, + SAY_VRYKUL_BEG = -1000639, + SAY_VRYKUL_WHAT = -1000640, + SAY_VRYKUL_HIDE = -1000641, +}; + +struct MANGOS_DLL_DECL npc_ancient_male_vrykulAI : public ScriptedAI +{ + npc_ancient_male_vrykulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bEventInProgress; + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + + void Reset() override + { + m_bEventInProgress = false; + m_uiPhase = 0; + m_uiPhaseTimer = 0; + } + + void StartEvent() + { + if (m_bEventInProgress) + return; + + m_bEventInProgress = true; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bEventInProgress) + return; + + if (m_uiPhaseTimer < uiDiff) + m_uiPhaseTimer = 5000; + else + { + m_uiPhaseTimer -= uiDiff; + return; + } + + Creature* pFemale = GetClosestCreatureWithEntry(m_creature, NPC_FEMALE_VRYKUL, 10.0f); + + switch (m_uiPhase) + { + case 0: + DoScriptText(SAY_VRYKUL_CURSED, m_creature); + DoScriptText(EMOTE_VRYKUL_POINT, m_creature); + break; + case 1: + if (pFemale) + DoScriptText(EMOTE_VRYKUL_SOB, pFemale); + DoScriptText(SAY_VRYKUL_DISPOSE, m_creature); + break; + case 2: + if (pFemale) + DoScriptText(SAY_VRYKUL_BEG, pFemale); + break; + case 3: + DoScriptText(SAY_VRYKUL_WHAT, m_creature); + break; + case 4: + if (pFemale) + DoScriptText(SAY_VRYKUL_HIDE, pFemale); + break; + case 5: + DoCastSpellIfCan(m_creature, SPELL_SECRET_OF_WYRMSKULL); + break; + case 6: + Reset(); + return; + } + + ++m_uiPhase; + } +}; + +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*/) +{ + if (pPlayer->isAlive() && pPlayer->GetQuestStatus(QUEST_ECHO_OF_YMIRON) == QUEST_STATUS_INCOMPLETE && + pPlayer->HasAura(SPELL_ECHO_OF_YMIRON)) + { + if (Creature* pCreature = GetClosestCreatureWithEntry(pPlayer, NPC_MALE_VRYKUL, 20.0f)) + { + if (npc_ancient_male_vrykulAI* pVrykulAI = dynamic_cast(pCreature->AI())) + pVrykulAI->StartEvent(); + } + } + + return true; +} /*###### ## npc_daegarn @@ -58,12 +172,12 @@ struct MANGOS_DLL_DECL npc_daegarnAI : public ScriptedAI npc_daegarnAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } bool m_bEventInProgress; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; - void Reset() + void Reset() override { m_bEventInProgress = false; - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); } void StartEvent(Player* pPlayer) @@ -71,18 +185,18 @@ struct MANGOS_DLL_DECL npc_daegarnAI : public ScriptedAI if (m_bEventInProgress) return; - m_uiPlayerGUID = pPlayer->GetGUID(); + m_playerGuid = pPlayer->GetObjectGuid(); SummonGladiator(NPC_FIRJUS); } - void JustSummoned(Creature* pSummon) + void JustSummoned(Creature* pSummon) override { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { if (pPlayer->isAlive()) { - pSummon->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + pSummon->SetWalk(false); pSummon->GetMotionMaster()->MovePoint(0, afCenter[0], afCenter[1], afCenter[2]); return; } @@ -93,12 +207,12 @@ 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, 30*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_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); // could be group, so need additional here. if (!pPlayer || !pPlayer->isAlive()) @@ -111,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; @@ -144,155 +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->GetGUID()); - - 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->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - 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->GetGUID()); - 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->GetGUID()); - - 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->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - 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->GetGUID()); - pCreature->CastSpell(pPlayer, SPELL_DARK_RANGER_LYANA_KILL_CREDIT, true); - break; - } - - return true; -} - -/*###### -## npc_mcgoyver - TODO, can be moved to database -######*/ - -#define GOSSIP_ITEM_MCGOYVER1 "Walt sent me to pick up some dark iron ingots." -#define GOSSIP_ITEM_MCGOYVER2 "Yarp." - -enum -{ - QUEST_WE_CAN_REBUILD_IT = 11483, - GOSSIP_TEXTID_MCGOYVER = 12193, - ITEM_DARK_IRON_INGOTS = 34135, - SPELL_MCGOYVER_TAXI_EXPLORERSLEAGUE = 44280, - SPELL_MCGOYVER_CREATE_DARK_IRON_INGOTS = 44512 -}; - -bool GossipHello_npc_mcgoyver(Player* pPlayer, Creature* pCreature) -{ - switch(pPlayer->GetQuestStatus(QUEST_WE_CAN_REBUILD_IT)) - { - case QUEST_STATUS_INCOMPLETE: - if (!pPlayer->HasItemCount(ITEM_DARK_IRON_INGOTS, 1, true)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MCGOYVER1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - } - else - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MCGOYVER2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_MCGOYVER, pCreature->GetGUID()); - } - break; - case QUEST_STATUS_COMPLETE: - if (!pPlayer->GetQuestRewardStatus(QUEST_WE_CAN_REBUILD_IT)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MCGOYVER2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_MCGOYVER, pCreature->GetGUID()); - break; - } - default: - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - } - - return true; -} - -bool GossipSelect_npc_mcgoyver(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pCreature->CastSpell(pPlayer, SPELL_MCGOYVER_CREATE_DARK_IRON_INGOTS, true); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MCGOYVER2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_MCGOYVER, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, SPELL_MCGOYVER_TAXI_EXPLORERSLEAGUE, true); - break; - } - - return true; -} - /*###### ## npc_silvermoon_harry ######*/ @@ -323,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; @@ -346,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()) { @@ -356,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; } @@ -375,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()) @@ -391,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; @@ -399,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; @@ -416,7 +375,7 @@ CreatureAI* GetAI_npc_silvermoon_harry(Creature* pCreature) bool GossipHello_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pCreature->isVendor()) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); @@ -432,23 +391,23 @@ bool GossipHello_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature) } } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); 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->GetGUID()); + pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+1: 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: @@ -467,38 +426,868 @@ bool GossipSelect_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature, uin return true; } +/*###### +## quest_jack_likes_his_drink +######*/ + +enum +{ + SAY_OLGA_0 = -1999818, // whisper + SAY_OLGA_1 = -1999817, + SAY_JACK_ADAMS_2 = -1999816, + SAY_OLGA_3 = -1999815, + SAY_JACK_ADAMS_4 = -1999814, + SAY_JACK_ADAMS_5 = -1999813, // faint + SAY_JACK_ADAMS_6 = -1999812, // wakeup + + NPC_TEXT_OLGA_1 = 12180, + NPC_JACK_ADAMS = 24788, + + SPELL_VOMIT = 41995, + ITEM_JACK_ADAMS_DEBT = 34116, + QUEST_JACK_LIKES_HIS_DRINK = 11466, +}; + +float OlgaWaypoints[2][4] = +{ + {0.0f, -91.81f, -3532.70f, 7.71f}, + {1.0f, -87.23f, -3544.23f, 7.71f} +}; + +#define GOSSIP_ITEM_OLGA_1 "I'd like to buy Jack a drink. Perhaps something... extra strong." +#define GOSSIP_ITEM_OLGA_2 "Here's a gold, buy yourself something nice." +#define GOSSIP_ITEM_OLGA_3 "Do you really want to bribe Olga?" +#define GOSSIP_ITEM_JACK_ADAMS_1 "" + +struct MANGOS_DLL_DECL npc_olgaAI : public ScriptedAI +{ + npc_olgaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + bool bEventInProgress; + bool bInRightPoint; + + uint8 subevent; + uint32 m_uiEventTimer; + uint32 m_uiResetJackTimer; + ObjectGuid JackAdamsGUID; + + void Reset() + { + bEventInProgress = false; + bInRightPoint = true; + subevent = 0; + m_uiEventTimer = 5000; + m_uiResetJackTimer = 30000; + // restore DB flags (GOSSIP) + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, m_creature->GetCreatureInfo()->NpcFlags); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (uiPointId == OlgaWaypoints[1][0] || uiPointId == OlgaWaypoints[0][0]) + bInRightPoint = true; + } + + void UpdateAI(const uint32 uiDiff) override + { + // if not event in progress and Jack is unconscous lets awake him after certain amount of time + if (!bEventInProgress) + { + if (m_uiResetJackTimer <= uiDiff) + { + Creature* pJack = m_creature->GetMap()->GetCreature(JackAdamsGUID); + if (pJack && pJack->isAlive() && pJack->GetByteValue(UNIT_FIELD_BYTES_1,0) == UNIT_STAND_STATE_DEAD) + pJack->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_STAND); + m_uiResetJackTimer = 30000; + }else m_uiResetJackTimer -= uiDiff; + } + + if(bEventInProgress && bInRightPoint) + { + if (m_uiEventTimer <= uiDiff) + { + // if there is no Jack around or he is dead there is no point to continue + Creature* pJack = m_creature->GetMap()->GetCreature(JackAdamsGUID); + if (!pJack || !pJack->isAlive()) + { + m_creature->AI()->EnterEvadeMode(); + return; + } + + switch(subevent) + { + case 0: + DoScriptText(SAY_OLGA_1,m_creature); + m_creature->GetMotionMaster()->MovePoint(OlgaWaypoints[1][0],OlgaWaypoints[1][1],OlgaWaypoints[1][2],OlgaWaypoints[1][3]); + m_uiEventTimer = 3000; + break; + case 1: + DoScriptText(SAY_JACK_ADAMS_2,pJack,m_creature); + m_uiEventTimer = 1000; + bInRightPoint = false; + break; + case 2: + m_creature->SetFacingToObject(pJack); + m_uiEventTimer = 2000; + break; + case 3: + DoScriptText(SAY_OLGA_3,m_creature,pJack); + m_uiEventTimer = 7000; + break; + case 4: + pJack->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_KNEEL); + DoScriptText(SAY_JACK_ADAMS_4,pJack,m_creature); + m_uiEventTimer = 5000; + break; + case 5: + pJack->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_STAND); + m_uiEventTimer = 3000; + break; + case 6: + pJack->CastSpell(pJack,SPELL_VOMIT,false); + m_uiEventTimer = 3000; + break; + case 7: + DoScriptText(SAY_JACK_ADAMS_5,pJack,m_creature); + pJack->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_DEAD); + pJack->SetUInt32Value(UNIT_NPC_FLAGS, m_creature->GetCreatureInfo()->NpcFlags); + m_uiEventTimer = 3000; + case 8: + m_creature->GetMotionMaster()->MovePoint(OlgaWaypoints[0][0],OlgaWaypoints[0][1],OlgaWaypoints[0][2],OlgaWaypoints[0][3]); + bInRightPoint = false; + break; + case 9: + m_creature->SetFacingToObject(pJack); + Reset(); + return; + default: break; + } + ++ subevent; + }else m_uiEventTimer -= uiDiff; + } + } +}; + + +bool GossipHello_npc_olga(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_JACK_LIKES_HIS_DRINK) == QUEST_STATUS_INCOMPLETE && pPlayer->GetMoney() >= 10000) + { + Creature* pJack = GetClosestCreatureWithEntry(pCreature,NPC_JACK_ADAMS,20.0f); + if (pJack && pJack->isAlive() && pJack->GetByteValue(UNIT_FIELD_BYTES_1,0) == UNIT_STAND_STATE_STAND) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_OLGA_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + ((npc_olgaAI*)pCreature->AI())->JackAdamsGUID = pJack->GetObjectGuid(); + } + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_olga(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_CHAT, GOSSIP_ITEM_OLGA_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2,GOSSIP_ITEM_OLGA_3, 10000,false); + pPlayer->SEND_GOSSIP_MENU(NPC_TEXT_OLGA_1, pCreature->GetObjectGuid()); + break; + + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->CLOSE_GOSSIP_MENU(); + DoScriptText(SAY_OLGA_0,pCreature,pPlayer); + pCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + pPlayer->ModifyMoney(-10000); + ((npc_olgaAI*)pCreature->AI())->bEventInProgress = true; + break; + } + return true; +} + +bool GossipHello_npc_jack_adams(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_JACK_LIKES_HIS_DRINK) == QUEST_STATUS_INCOMPLETE && pPlayer->GetItemCount(ITEM_JACK_ADAMS_DEBT,false) < 1) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JACK_ADAMS_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_jack_adams(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + ItemPosCountVec dest; + uint8 msg = pPlayer->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_JACK_ADAMS_DEBT, 1); + if (msg == EQUIP_ERR_OK) + pPlayer->StoreNewItem(dest, ITEM_JACK_ADAMS_DEBT, 1, true); + pCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + // 50% chance that jack standup immediately + if (urand(0, 1) == 0) + { + pCreature->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_STAND); + DoScriptText(SAY_JACK_ADAMS_6,pCreature,pPlayer); + } + } + return true; +} + +CreatureAI* GetAI_npc_olga(Creature* pCreature) +{ + return new npc_olgaAI(pCreature); +} + +/*###### +## 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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; + pNewScript = new Script; + pNewScript->Name = "npc_ancient_male_vrykul"; + pNewScript->GetAI = &GetAI_npc_ancient_male_vrykul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_ancient_male_vrykul"; + pNewScript->pAreaTrigger = &AreaTrigger_at_ancient_male_vrykul; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "npc_daegarn"; pNewScript->GetAI = &GetAI_npc_daegarn; - pNewScript->pQuestAccept = &QuestAccept_npc_daegarn; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_daegarn; 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_olga"; + pNewScript->GetAI = &GetAI_npc_olga; + pNewScript->pGossipHello = &GossipHello_npc_olga; + pNewScript->pGossipSelect = &GossipSelect_npc_olga; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_mcgoyver"; - pNewScript->pGossipHello = &GossipHello_npc_mcgoyver; - pNewScript->pGossipSelect = &GossipSelect_npc_mcgoyver; + pNewScript->Name = "npc_jack_adams"; + pNewScript->pGossipHello = &GossipHello_npc_jack_adams; + pNewScript->pGossipSelect = &GossipSelect_npc_jack_adams; 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 = "npc_lich_king_village"; + pNewScript->GetAI = &GetAI_npc_lich_king_village; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_king_ymiron"; + pNewScript->GetAI = &GetAI_npc_king_ymiron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 e85c1ae25b..454f5afaa1 100644 --- a/scripts/northrend/icecrown.cpp +++ b/scripts/northrend/icecrown.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,133 +17,692 @@ /* ScriptData SDName: Icecrown SD%Complete: 100 -SDComment: Quest support: 12807, Vendor support: 34885 +Quest Support: 13663, 13665, 13745, 13750, 13756, 13761, 13767, 13772, 13777, 13782, 13787, 14107 SDCategory: Icecrown EndScriptData */ /* ContentData -npc_arete npc_dame_evniki_kapsalis +npc_scourge_conventor +npc_fallen_hero_spirit +npc_valiants +npc_champions +npc_black_knights_gryphon +npc_saronite_mine_slave EndContentData */ #include "precompiled.h" +#include "escort_ai.h" +#include "TemporarySummon.h" /*###### -## npc_arete +## npc_melee_target //quests 13828,13829,13625,13677 ######*/ -#define GOSSIP_ARETE_ITEM1 "Lord-Commander, I would hear your tale." -#define GOSSIP_ARETE_ITEM2 "" -#define GOSSIP_ARETE_ITEM3 "I thought that they now called themselves the Scarlet Onslaught?" -#define GOSSIP_ARETE_ITEM4 "Where did the grand admiral go?" -#define GOSSIP_ARETE_ITEM5 "That's fine. When do I start?" -#define GOSSIP_ARETE_ITEM6 "Let's finish this!" -#define GOSSIP_ARETE_ITEM7 "That's quite a tale, Lord-Commander." +struct MANGOS_DLL_DECL npc_melee_targetAI : public ScriptedAI +{ + npc_melee_targetAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiEvade_Timer; + + void Reset() + { + m_uiEvade_Timer = 5000; + SetCombatMovement(false); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + uiDamage = 0; + m_uiEvade_Timer = 5000; + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pSpell->Id == 62544) + { + DoCastSpellIfCan(pCaster, 62709); + if (Player* pPlayer = pCaster->GetCharmerOrOwnerPlayerOrPlayerItself()) + pPlayer->KilledMonsterCredit(33341); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEvade_Timer < uiDiff) + { + m_uiEvade_Timer = 5000; + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + } + else + m_uiEvade_Timer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_melee_target(Creature* pCreature) +{ + return new npc_melee_targetAI(pCreature); +} + +/*###### +## npc_ranged_target //quests 13835,13838,13625,13677 +######*/ + +struct MANGOS_DLL_DECL npc_ranged_targetAI : public ScriptedAI +{ + npc_ranged_targetAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiEvade_Timer; + uint32 m_uiDefend_Timer; + + void Reset() + { + m_uiEvade_Timer = 5000; + m_uiDefend_Timer = 5000; + + SetCombatMovement(false); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + uiDamage = 0; + m_uiEvade_Timer = 5000; + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + switch(pSpell->Id) + { + case 64342: + if (!m_creature->HasAura(62719)) + { + if (Player* pPlayer = pCaster->GetCharmerOrOwnerPlayerOrPlayerItself()) + pPlayer->KilledMonsterCredit(33339); + return; + } + case 63010: + if (SpellAuraHolderPtr holder = m_creature->GetSpellAuraHolder(62719)) + { + if (holder->ModStackAmount(-1)) + m_creature->RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_SHIELD_BREAK); + + m_uiDefend_Timer = 5000; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDefend_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature, 62719); + Aura* pAura = m_creature->GetAura(62719, EFFECT_INDEX_0); + if (pAura && pAura->GetStackAmount() > 2) + m_uiDefend_Timer = 50000; + else + m_uiDefend_Timer = 5000; + } + else + m_uiDefend_Timer -= uiDiff; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEvade_Timer < uiDiff) + { + m_uiEvade_Timer = 5000; + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + } + else + m_uiEvade_Timer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_ranged_target(Creature* pCreature) +{ + return new npc_ranged_targetAI(pCreature); +} + +/*###### +## npc_charge_target //quests 13837,13839,13625,13677 +######*/ + +struct MANGOS_DLL_DECL npc_charge_targetAI : public ScriptedAI +{ + npc_charge_targetAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiEvade_Timer; + uint32 m_uiDefend_Timer; + + void Reset() + { + m_uiEvade_Timer = 5000; + m_uiDefend_Timer = 5000; + + SetCombatMovement(false); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + uiDamage = 0; + m_uiEvade_Timer = 5000; + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + switch(pSpell->Id) + { + case 63010: + if (!m_creature->HasAura(64100)) + { + if (Player* pPlayer = pCaster->GetCharmerOrOwnerPlayerOrPlayerItself()) + pPlayer->KilledMonsterCredit(33340); + return; + } + case 64342: + if (m_creature->HasAura(64100)) + { + m_creature->RemoveAurasDueToSpell(64100); + m_uiDefend_Timer = 5000; + } + + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDefend_Timer < uiDiff) + { + if (!m_creature->HasAura(64100)) + DoCastSpellIfCan(m_creature, 64100); + m_uiDefend_Timer = 5000; + } + else + m_uiDefend_Timer -= uiDiff; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEvade_Timer < uiDiff) + { + m_uiEvade_Timer = 5000; + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + } + else + m_uiEvade_Timer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_charge_target(Creature* pCreature) +{ + return new npc_charge_targetAI(pCreature); +} + +/*##### +## npc_black_knights_gryphon +#####*/ + +struct MANGOS_DLL_DECL npc_black_knights_gryphonAI : public npc_escortAI +{ + npc_black_knights_gryphonAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + void Reset() { } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (m_creature->IsTemporarySummon()) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(((TemporarySummon*)m_creature)->GetSummonerGuid())) + pPlayer->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetSpeedRate(MOVE_RUN, 3.0f); + Start(true, ((Player*)pCaster)); + } + + void WaypointReached(uint32 uiPointId) override + { + switch(uiPointId) + { + case 0: + SetRun(); + break; + case 10: + m_creature->SetLevitate(true); + m_creature->SetSpeedRate(MOVE_RUN, 6.0f); + break; + case 15: + //if (Player* pPlayer = GetPlayerForEscort()) + //hack to prevent Player's death + // pPlayer->CastSpell(pPlayer, 64505, true); + break; + case 16: + m_creature->ForcedDespawn(2000); + return; + default: + break; + } + } +}; + +CreatureAI* GetAI_npc_black_knights_gryphon(Creature* pCreature) +{ + return new npc_black_knights_gryphonAI(pCreature); +} + +/*###### +## npc_scourge_conventor //quest 14107 +######*/ + +// grip of scourge still needs implented and used + +enum QuestFate // shared enum by conventor mob and fallen hero mob +{ + QUEST_THE_FATE_OF_THE_FALLEN = 14107, + NPC_FALLEN_HERO_SPIRIT = 32149, + NPC_FALLEN_HERO_SPIRIT_PROXY = 35055, +}; + +enum +{ + SPELL_CONE_OF_COLD = 20828, + SPELL_FORST_NOVA = 11831, + SPELL_FROSTBOLT = 20822, + SPELL_GRIP_OF_THE_SCOURGE = 60212, // spell casted by mob +}; + +struct MANGOS_DLL_DECL npc_scourge_conventorAI : public ScriptedAI +{ + npc_scourge_conventorAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiConeofCold_Timer; + uint32 m_uiFrostNova_Timer; + uint32 m_uiFrostBolt_Timer; + //uint32 m_uiGrip_Timer; + + void Reset() + { + m_uiConeofCold_Timer = 10000; + m_uiFrostNova_Timer = 11000; + m_uiFrostBolt_Timer = 9000; + //m_uiGrip_Timer = 10000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiConeofCold_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(),SPELL_CONE_OF_COLD); + m_uiConeofCold_Timer = 10000; + } + else + m_uiConeofCold_Timer -= uiDiff; + + if (m_uiFrostNova_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(),SPELL_FORST_NOVA); + m_uiFrostNova_Timer = 11000; + } + else + m_uiFrostNova_Timer -= uiDiff; + + if (m_uiFrostBolt_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLT); + m_uiFrostBolt_Timer = 9000; + } + else + m_uiFrostBolt_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + +}; + +CreatureAI* GetAI_npc_scourge_conventor(Creature* pCreature) +{ + return new npc_scourge_conventorAI(pCreature); +} + +/*###### +## npc_fallen_hero_spirit //quest 14107 +######*/ enum { - GOSSIP_TEXTID_ARETE1 = 13525, - GOSSIP_TEXTID_ARETE2 = 13526, - GOSSIP_TEXTID_ARETE3 = 13527, - GOSSIP_TEXTID_ARETE4 = 13528, - GOSSIP_TEXTID_ARETE5 = 13529, - GOSSIP_TEXTID_ARETE6 = 13530, - GOSSIP_TEXTID_ARETE7 = 13531, + SAY_BLESS_1 = -1999819, + SAY_BLESS_2 = -1999820, + SAY_BLESS_3 = -1999821, + SAY_BLESS_4 = -1999822, + SAY_BLESS_5 = -1999823, - QUEST_THE_STORY_THUS_FAR = 12807 + SPELL_STRIKE = 11976, + SPELL_BLESSING_OF_PEACE = 66719, //spell casted from relic of light + GRIP_OF_THE_SCOURGE_AURA = 60231 //might need server side spell script support (when mob has this spell it's immune to fate of light spell) }; -bool GossipHello_npc_arete(Player* pPlayer, Creature* pCreature) + +struct MANGOS_DLL_DECL npc_fallen_hero_spiritAI : public ScriptedAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_fallen_hero_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - if (pPlayer->GetQuestStatus(QUEST_THE_STORY_THUS_FAR) == QUEST_STATUS_INCOMPLETE) + uint32 m_uiStrike_Timer; + + void Reset() { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE1, pCreature->GetGUID()); - return true; + m_uiStrike_Timer = 10000; } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // if (m_creature->HasAura(GRIP_OF_THE_SCOURGE_AURA)) + // return fasle; + + if (pCaster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && ((pSpell->Id == SPELL_BLESSING_OF_PEACE))) + { + if (((Player*)pCaster)->GetQuestStatus(QUEST_THE_FATE_OF_THE_FALLEN) == QUEST_STATUS_INCOMPLETE) + { + ((Player*)pCaster)->KilledMonsterCredit(NPC_FALLEN_HERO_SPIRIT_PROXY); + m_creature->ForcedDespawn(); + switch(urand(0, 4)) + { + case 0: DoScriptText(SAY_BLESS_1, m_creature); break; + case 1: DoScriptText(SAY_BLESS_2, m_creature); break; + case 2: DoScriptText(SAY_BLESS_3, m_creature); break; + case 3: DoScriptText(SAY_BLESS_4, m_creature); break; + case 4: DoScriptText(SAY_BLESS_5, m_creature); break; + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiStrike_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(),SPELL_STRIKE); + m_uiStrike_Timer = 10000; + } + else + m_uiStrike_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + +}; + +CreatureAI* GetAI_npc_fallen_hero_spirit(Creature* pCreature) +{ + return new npc_fallen_hero_spiritAI(pCreature); } -bool GossipSelect_npc_arete(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +/*##### +## npc_valiants +#####*/ + +enum { - switch(uiAction) + SAY_DEFEATED = -1999824, + SPELL_VCHARGE = 63010, + SPELL_VSHIELDBREAKER = 65147, + + SPELL_MOUNTED_MELEE_VICTORY = 62724, +}; + +struct MANGOS_DLL_DECL npc_valiantsAI : public ScriptedAI +{ + npc_valiantsAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + //uint32 m_uiVCHARGE_Timer; + //uint32 m_uiVSHIELDBREAKER_Timer; + + void Reset() { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE4, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE5, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE6, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARETE_ITEM7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ARETE7, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(QUEST_THE_STORY_THUS_FAR); - break; + //m_uiVCHARGE_Timer = 2000; need correct timers + //m_uiVSHIELDBREAKER_Timer = 5000; need correct timers } - return true; + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + { + uiDamage = 5; + + if (Unit* pPlayer = pDoneBy->GetCharmerOrOwnerPlayerOrPlayerItself()) + pPlayer->CastSpell(pPlayer, SPELL_MOUNTED_MELEE_VICTORY, true); + + DoScriptText(SAY_DEFEATED, m_creature); + EnterEvadeMode(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + /* { STILL HAVE ATTACK SPELLS TO DO + }*/ + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_valiants(Creature* pCreature) +{ + return new npc_valiantsAI(pCreature); +} + +/*##### +## npc_champions +#####*/ + +enum +{ + // spells are defined above + SPELL_CHAMP_MOUNTED_MELEE_VICTORY = 63596, +}; + +struct MANGOS_DLL_DECL npc_championsAI : public ScriptedAI +{ + npc_championsAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + //uint32 m_uiVCHARGE_Timer; + //uint32 m_uiVSHIELDBREAKER_Timer; + + void Reset() + { + //m_uiVCHARGE_Timer = 2000; need correct timers + //m_uiVSHIELDBREAKER_Timer = 5000; need correct timers + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + { + uiDamage = 5; + + if (Unit* pPlayer = pDoneBy->GetCharmerOrOwnerPlayerOrPlayerItself()) + pPlayer->CastSpell(pPlayer, SPELL_CHAMP_MOUNTED_MELEE_VICTORY, true); + + DoScriptText(SAY_DEFEATED, m_creature); + EnterEvadeMode(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + /* { STILL HAVE ATTACK SPELLS TO DO + }*/ + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_champions(Creature* pCreature) +{ + return new npc_championsAI(pCreature); } /*###### -## npc_dame_evniki_kapsalis +## npc_saronite_mine_slave ######*/ enum { - TITLE_CRUSADER = 123 + 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, }; -bool GossipHello_npc_dame_evniki_kapsalis(Player* pPlayer, Creature* pCreature) +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->HasTitle(TITLE_CRUSADER)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + 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(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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->GetGUID()); + 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; } void AddSC_icecrown() { - Script* newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_melee_target"; + pNewScript->GetAI = &GetAI_npc_melee_target; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ranged_target"; + pNewScript->GetAI = &GetAI_npc_ranged_target; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_charge_target"; + pNewScript->GetAI = &GetAI_npc_charge_target; + 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_black_knights_gryphon"; + pNewScript->GetAI = &GetAI_npc_black_knights_gryphon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scourge_conventor"; + pNewScript->GetAI = &GetAI_npc_scourge_conventor; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_fallen_hero_spirit"; + pNewScript->GetAI = &GetAI_npc_fallen_hero_spirit; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_arete"; - newscript->pGossipHello = &GossipHello_npc_arete; - newscript->pGossipSelect = &GossipSelect_npc_arete; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_valiants"; + pNewScript->GetAI = &GetAI_npc_valiants; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_dame_evniki_kapsalis"; - newscript->pGossipHello = &GossipHello_npc_dame_evniki_kapsalis; - newscript->pGossipSelect = &GossipSelect_npc_dame_evniki_kapsalis; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_champions"; + pNewScript->GetAI = &GetAI_npc_champions; + 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 83c387875c..7b8dea5124 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,70 +16,216 @@ /* ScriptData SDName: boss_bronjahm -SD%Complete: 0% -SDComment: Placeholder +SD%Complete: 90% +SDComment: Small unknown behaviour for his Shadow Bold use in phase 1; Soulstorm needs additional handling in core SDCategory: The Forge of Souls EndScriptData */ #include "precompiled.h" #include "forge_of_souls.h" -enum +enum BossSpells { - SAY_AGGRO_1 = -1632000, // without sound, really correct? - SAY_AGGRO_2 = -1632001, - SAY_SLAY_1 = -1632002, - SAY_SLAY_2 = -1632003, - SAY_DEATH = -1632004, - SAY_SOULSTORM = -1632005, - SAY_CORRUPT_SOUL = -1632006, + //common + SPELL_BERSERK = 47008, + //yells + //summons + NPC_SOUL_FRAGMENT = 36535, + //Abilities + SPELL_MAGIC_BANE = 68793, + SPELL_CORRUPT_SOUL = 68839, + SPELL_CONSUME_SOUL = 68858, + SPELL_TELEPORT = 68988, + SPELL_SOULSTORM = 68872, + SPELL_SOULSTORM_2 = 68921, + SPELL_FEAR = 68950, + SPELL_SHADOW_BOLT = 70043, + + /*Music*/ + Battle01 = 6077, + Battle02 = 6078, + Battle03 = 6079, + }; -struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI +struct MANGOS_DLL_DECL boss_bronjahmAI : public BSWScriptedAI { - boss_bronjahmAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_bronjahmAI(Creature* pCreature) : BSWScriptedAI(pCreature) { - m_pInstance = (instance_forge_of_souls*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - instance_forge_of_souls* m_pInstance; - bool m_bIsRegularMode; + ScriptedInstance *pInstance; + uint8 stage; + uint32 BattleMusicTimer; + uint32 Music; void Reset() { + if(pInstance) pInstance->SetData(TYPE_BRONJAHM, NOT_STARTED); + resetTimers(); + stage = 0; + } + + void Aggro(Unit *who) + { + Music = (urand(0, 2)); + switch(Music) + { + case 0: + m_creature->PlayDirectSound(Battle01); + BattleMusicTimer = 48000; + break; + case 1: + m_creature->PlayDirectSound(Battle02); + BattleMusicTimer = 27000; + break; + case 2: + m_creature->PlayDirectSound(Battle03); + BattleMusicTimer = 36000; + break; + } + + if(pInstance) pInstance->SetData(TYPE_BRONJAHM, IN_PROGRESS); + DoScriptText(-1632001,m_creature,who); + SetCombatMovement(true); + } + + void JustDied(Unit *killer) + { + if(pInstance) pInstance->SetData(TYPE_BRONJAHM, DONE); + doRemove(SPELL_SOULSTORM); + DoScriptText(-1632004,m_creature,killer); } - void Aggro(Unit* pWho) + void KilledUnit(Unit* pVictim) override { - DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature); - if (m_pInstance) - m_pInstance->SetData(TYPE_BRONJAHM, IN_PROGRESS); + switch (urand(0,1)) { + case 0: + DoScriptText(-1632002,m_creature,pVictim); + break; + case 1: + DoScriptText(-1632003,m_creature,pVictim); + break; + }; } - void KilledUnit(Unit* pVictim) + void UpdateAI(const uint32 diff) { - if (pVictim->GetTypeId() != TYPEID_PLAYER) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (urand(0, 1)) - DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + switch(stage) + { + case 0: + if (timedQuery(SPELL_CORRUPT_SOUL, diff)) + { + if (Unit* pTarget= m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (doCast(SPELL_CORRUPT_SOUL, pTarget) == CAST_OK) + { + DoScriptText(-1632006,m_creature,pTarget); + float fPosX, fPosY, fPosZ; + pTarget->GetPosition(fPosX, fPosY, fPosZ); + doSummon(NPC_SOUL_FRAGMENT,fPosX, fPosY, fPosZ); + } + } + } + break; + case 1: + if (timedCast(SPELL_TELEPORT, diff) == CAST_OK) stage = 2; + break; + case 2: + if (timedCast(SPELL_SOULSTORM, diff) == CAST_OK) { + DoScriptText(-1632005,m_creature); + SetCombatMovement(false); + stage = 3; + } + break; + case 3: + timedCast(SPELL_FEAR, diff); + break; + } + + timedCast(SPELL_SHADOW_BOLT, diff); + + timedCast(SPELL_MAGIC_BANE, diff); + + if (m_creature->GetHealthPercent() <= 30.0f && stage == 0) stage = 1; + + DoMeleeAttackIfReady(); + + if (BattleMusicTimer < diff && m_creature->isAlive()) + { + switch(Music) + { + case 0: + m_creature->PlayDirectSound(Battle01); + BattleMusicTimer = 49000; + break; + case 1: + m_creature->PlayDirectSound(Battle02); + BattleMusicTimer = 28000; + break; + case 2: + m_creature->PlayDirectSound(Battle03); + BattleMusicTimer = 37000; + break; + } + } else BattleMusicTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL npc_corrupted_soul_fragmentAI : public ScriptedAI +{ + npc_corrupted_soul_fragmentAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); } - void JustDied(Unit* pKiller) + ScriptedInstance *m_pInstance; + uint32 m_uiRangeCheck_Timer; + + void Reset() { - DoScriptText(SAY_DEATH, m_creature); + m_uiRangeCheck_Timer = 1000; + if (!m_pInstance) return; + Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(NPC_BRONJAHM); + m_creature->SetSpeedRate(MOVE_RUN, 0.2f); + if (Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(NPC_BRONJAHM)) + m_creature->GetMotionMaster()->MoveChase(pBoss); + m_creature->SetRespawnDelay(DAY); + } - if (m_pInstance) - m_pInstance->SetData(TYPE_BRONJAHM, DONE); + void AttackStart(Unit* pWho) override + { + return; } - void JustReachedHome() + void UpdateAI(const uint32 uiDiff) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_BRONJAHM, NOT_STARTED); + if (!m_pInstance || m_pInstance->GetData(TYPE_BRONJAHM) != IN_PROGRESS ) m_creature->ForcedDespawn(); + + if (m_uiRangeCheck_Timer < uiDiff) + { + if (Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(NPC_BRONJAHM)) + { + if (pBoss->IsWithinDistInMap(m_creature, 2.0f)) + { + pBoss->CastSpell(pBoss, SPELL_CONSUME_SOUL, false); + m_creature->ForcedDespawn(); + } else m_creature->GetMotionMaster()->MoveChase(pBoss); + } + else + m_creature->ForcedDespawn(); + + m_uiRangeCheck_Timer = 1000; + } + else m_uiRangeCheck_Timer -= uiDiff; } + }; CreatureAI* GetAI_boss_bronjahm(Creature* pCreature) @@ -87,12 +233,23 @@ CreatureAI* GetAI_boss_bronjahm(Creature* pCreature) return new boss_bronjahmAI(pCreature); } +CreatureAI* GetAI_npc_corrupted_soul_fragment(Creature* pCreature) +{ + return new npc_corrupted_soul_fragmentAI (pCreature); +} + + void AddSC_boss_bronjahm() { - Script* pNewScript; + Script *newscript; + newscript = new Script; + newscript->Name = "boss_bronjahm"; + newscript->GetAI = &GetAI_boss_bronjahm; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_corrupted_soul_fragment"; + newscript->GetAI = &GetAI_npc_corrupted_soul_fragment; + newscript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "boss_bronjahm"; - pNewScript->GetAI = &GetAI_boss_bronjahm; - pNewScript->RegisterSelf(); } 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 2f54fa51bd..f1d4799209 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_devourer_of_souls -SD%Complete: 0% -SDComment: Placeholder +SD%Complete: 90% +SDComment: Timers need more love, NPC_UNLEASHED_SOUL are not handled proper SDCategory: The Forge of Souls EndScriptData */ @@ -26,7 +26,6 @@ EndScriptData */ enum { - // TODO, how to change the face on random?, how to know which face is shown, to use the additional entries SAY_MALE_1_AGGRO = -1632007, SAY_FEMALE_AGGRO = -1632008, SAY_MALE_1_SLAY_1 = -1632009, @@ -49,8 +48,28 @@ enum EMOTE_WAILING_SOULS = -1632025, FACE_NORMAL = 0, - FACE_UNLEASHING = 1, - FACE_WAILING = 2, + FACE_WAILING = 1, + FACE_UNLEASHING = 2, + + SPELL_PHANTOM_BLAST = 68982, + SPELL_PHANTOM_BLAST_H = 70322, + SPELL_WELL_OF_SOULS = 68820, // spawns 36536, this one should cast 68854 (triggers normal dmg spell 68863 ) - 68855(visual) - 72630 (visual) + SPELL_WELL_OF_SOULS_TRIGGER = 68854, + SPELL_WELL_OF_SOULS_VISUAL1 = 68855, + SPELL_WELL_OF_SOULS_VISUAL2 = 72630, + + SPELL_MIRRORED_SOUL = 69048, // selecting target, applying aura 69023 to pass on dmg, dmg triggers 69034 with right amount + SPELL_UNLEASHED_SOULS = 68939, // trigger (68967, select nearby target trigger 68979(summon 36595)), transform, root + SPELL_WAILING_SOULS = 68899, + SPELL_WALIING_SOULS_TARGETS = 68912, + + SPELL_DRUID_MORPH_1_5 = 68931, // delayed visual, 1.5s delay - used before wailing souls + SPELL_DRUID_MORPH_0_5 = 68977, // delayed visual, .5s delay - used before unleash souls + SPELL_SUBMERGE_VISUAL = 68909, // visual used to 'whirl' the heads, used by SPELL_DRUID_MORPH if spell DRUID_MORPH is used to "end" a phase + SPELL_DRUID_MORPH = 68929, // used after wailing and unleashed souls, also triggered by DRUIT_MORPH_* + + NPC_WELL_OF_SOULS = 36536, + NPC_UNLEASHED_SOUL = 36595, }; static const int aTexts[6][3] = @@ -59,7 +78,7 @@ static const int aTexts[6][3] = {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 - soul + {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 }; @@ -76,19 +95,35 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI uint8 m_uiFace; bool m_bIsRegularMode; - void Reset() + uint32 m_uiPhantomBlastTimer; + uint32 m_uiWellTimer; + uint32 m_uiMirrorTimer; + uint32 m_uiUnleashTimer; + uint32 m_uiWailingTimer; + uint32 m_uiEndPhaseTimer; + + GuidList m_lWellGuids; + + void Reset() override { m_uiFace = FACE_NORMAL; + + m_uiPhantomBlastTimer = urand(5000, 10000); + m_uiWellTimer = urand(10000, 15000); + m_uiMirrorTimer = urand(10000, 15000); + m_uiUnleashTimer = urand(15000, 20000); + m_uiWailingTimer = urand(40000, 60000); + 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_DECOURER_OF_SOULS, IN_PROGRESS); + m_pInstance->SetData(TYPE_DEVOURER_OF_SOULS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -97,24 +132,189 @@ 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) { - m_pInstance->SetData(TYPE_DECOURER_OF_SOULS, DONE); + if (Creature* pWell = m_creature->GetMap()->GetCreature(*itr)) + pWell->ForcedDespawn(); } + m_lWellGuids.clear(); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { - m_pInstance->SetData(NPC_DEVOURER_OF_SOULS, NOT_STARTED); + m_pInstance->SetData(NPC_DEVOURER_OF_SOULS, FAIL); // If we previously failed, set such that possible to try again m_pInstance->SetData(TYPE_ACHIEV_PHANTOM_BLAST, IN_PROGRESS); } + + for (GuidList::const_iterator itr = m_lWellGuids.begin(); itr != m_lWellGuids.end(); ++itr) + { + if (Creature* pWell = m_creature->GetMap()->GetCreature(*itr)) + pWell->ForcedDespawn(); + } + m_lWellGuids.clear(); + } + + 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); + } + else if (pSummoned->GetEntry() == NPC_UNLEASHED_SOUL) + { + if (Unit* pEnemy = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + // It seems the summoned should rather walk towards the boss, but this results in them attacking the healer + pSummoned->AI()->AttackStart(pEnemy); + pSummoned->AddThreat(pEnemy, 10000.0f); + } + pSummoned->ForcedDespawn(15000); // Note that this is sort of a hack, the more correct fix however would require to toggle the interpretation of summon properties in mangos + } + } + + void SpellHitTarget(Unit* /*pTarget*/, SpellEntry const* pSpellEntry) override + { + switch (pSpellEntry->Id) + { + // 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 + case SPELL_WAILING_SOULS: + DoScriptText(aTexts[5][m_uiFace], m_creature); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->isInCombat()) + return; + + // Ending a phase + if (m_uiEndPhaseTimer) + { + if (m_uiEndPhaseTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_DRUID_MORPH, CAST_INTERRUPT_PREVIOUS); + // Sumberge visual might be cast as effect of the above spell. + DoCastSpellIfCan(m_creature, SPELL_SUBMERGE_VISUAL, CAST_TRIGGERED); + m_uiEndPhaseTimer = 0; + + m_uiFace = FACE_NORMAL; + } + else + m_uiEndPhaseTimer -= uiDiff; + } + + // No additional spells, no target selection for wailing souls + if (m_uiFace == FACE_WAILING) + { + // Some special handling in case of starting phase of wailings + if (ObjectGuid targetGuid = m_creature->GetTargetGuid()) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit(targetGuid)) + m_creature->SetFacingTo(m_creature->GetAngle(pTarget)); + } + + if (m_creature->getThreatManager().isThreatListEmpty() || !m_creature->getThreatManager().getHostileTarget()) + m_creature->SelectHostileTarget(); // Most likely must evade, use additional checks in case evading would be prevented + return; + } + + // Update Target and do Combat Spells + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // No additional abilities while unleashing + if (m_uiFace == FACE_UNLEASHING) + return; + + // Phantom Blast + if (m_uiPhantomBlastTimer < uiDiff) + { + 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; + + // Jump towards random enemy + if (m_uiWellTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_WELL_OF_SOULS) == CAST_OK) + m_uiWellTimer = urand(15000, 25000); // TODO + } + } + else + m_uiWellTimer -= uiDiff; + + // DMG reflection + if (m_uiMirrorTimer < uiDiff) + { + if (!m_creature->IsNonMeleeSpellCasted(true)) + { + DoCastSpellIfCan(m_creature, SPELL_MIRRORED_SOUL, CAST_TRIGGERED); + m_uiMirrorTimer = urand(25000, 35000); // TODO + DoScriptText(EMOTE_MIRRORED_SOUL, m_creature); + } + } + else + m_uiMirrorTimer -= uiDiff; + + // Spawning of Adds + if (m_uiUnleashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNLEASHED_SOULS) == CAST_OK && DoCastSpellIfCan(m_creature, SPELL_DRUID_MORPH_0_5, CAST_TRIGGERED) == CAST_OK) + { + DoScriptText(EMOTE_UNLEASH_SOULS, m_creature); + m_uiUnleashTimer = urand(30000, 60000); // TODO + + m_uiFace = FACE_UNLEASHING; + DoScriptText(aTexts[4][m_uiFace], m_creature); + m_uiEndPhaseTimer = 4500; // 5000 (Duration of Unleasing) + 850(Cast time for unleashing) - 1000(duration of whirl) - a bit air + } + } + else + m_uiUnleashTimer -= uiDiff; + + if (m_uiWailingTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WALIING_SOULS_TARGETS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_DRUID_MORPH_1_5, CAST_TRIGGERED); + DoScriptText(EMOTE_WAILING_SOULS, m_creature); + m_uiFace = FACE_WAILING; + m_uiEndPhaseTimer = 12500; // 100000 (Duration of Wailing) + 3000(casting time) - 1000 (duration of whirl) + 500 (some add. time) + m_uiWailingTimer = urand(25000, 35000); // TODO + } + } + else + m_uiWailingTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.cpp new file mode 100644 index 0000000000..4ffd47f0d3 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.cpp @@ -0,0 +1,337 @@ +/* Copyright (C) 2006 - 2013 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: Forge Of The Souls +SD%Complete: 90% +SDComment: event script! Need Add 6 Coliseum Champion after devourer death. +SDCategory: forge_of_the_souls +SDAuthor: MaxXx2021 aka Mioka +EndScriptData */ + +#include "precompiled.h" +#include "forge_of_souls.h" + +enum +{ + SAY_JAINA_FS01 = -1632040, + SAY_JAINA_FS02 = -1632041, + SAY_JAINA_FS03 = -1632042, + SAY_JAINA_FS04 = -1632043, + SAY_JAINA_FS05 = -1632044, + SAY_JAINA_FS06 = -1632045, + SAY_JAINA_FS07 = -1632046, + SAY_JAINA_FS08 = -1632047, + SAY_JAINA_FS09_EXTRO = -1632029, + + SAY_SYLVANA_FS01 = -1632050, + SAY_SYLVANA_FS02 = -1632051, + SAY_SYLVANA_FS03 = -1632052, + SAY_SYLVANA_FS04 = -1632053, + SAY_SYLVANA_FS05 = -1632054, + SAY_SYLVANA_FS06 = -1632055, + SAY_SYLVANA_FS07_EXTRO = -1632030, + + GOSSIP_SPEECHINTRO = 13525, +}; + +struct MANGOS_DLL_DECL npc_jaina_and_sylvana_FSintroAI : public ScriptedAI +{ + npc_jaina_and_sylvana_FSintroAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + +ScriptedInstance* m_pInstance; + +uint32 StepTimer; +uint32 Step; +bool StartEvent; + + void Reset() + { + if(m_pInstance) + if(m_pInstance->GetData(TYPE_DEVOURER_OF_SOULS) == DONE) + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + Step = 0; + StepTimer = 100; + StartEvent = false; + if(m_pInstance->GetData(TYPE_INTRO) == DONE) + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + Step = 8; + } + } + + void UpdateAI(const uint32 diff) + { + DoMeleeAttackIfReady(); + + if(!m_pInstance) return; + + if(StartEvent != true) return; + + if(StepTimer < diff) + { + switch(Step) + { + case 0: + m_pInstance->SetData(TYPE_INTRO, DONE); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS01, m_creature); + StepTimer = 7000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + StepTimer = 100; + ++Step; + break; + case 1: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS02, m_creature); + StepTimer = 9000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + { + DoScriptText(SAY_SYLVANA_FS01, m_creature); + StepTimer = 12000; + } + ++Step; + break; + case 2: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS03, m_creature); + StepTimer = 8000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + { + DoScriptText(SAY_SYLVANA_FS02, m_creature); + StepTimer = 11000; + } + ++Step; + break; + case 3: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS04, m_creature); + StepTimer = 10000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + { + DoScriptText(SAY_SYLVANA_FS03, m_creature); + StepTimer = 11000; + } + ++Step; + break; + case 4: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS05, m_creature); + StepTimer = 8000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + { + DoScriptText(SAY_SYLVANA_FS04, m_creature); + StepTimer = 12000; + } + ++Step; + break; + case 5: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS06, m_creature); + StepTimer = 12000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + { + DoScriptText(SAY_SYLVANA_FS05, m_creature); + StepTimer = 7000; + } + ++Step; + break; + case 6: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS07, m_creature); + StepTimer = 7000; + } + if(m_creature->GetEntry() == NPC_SILVANA_BEGIN) + { + DoScriptText(SAY_SYLVANA_FS06, m_creature); + StepTimer = 4000; + } + ++Step; + break; + case 7: + if(m_creature->GetEntry() == NPC_JAINA_BEGIN ) + { + DoScriptText(SAY_JAINA_FS08, m_creature); + StepTimer = 5000; + } + ++Step; + break; + } + } else StepTimer -= diff; + } +}; + +bool GossipHello_npc_jaina_and_sylvana_FSintro(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu( pCreature->GetObjectGuid()); + switch(pCreature->GetEntry()) + { + case 37597: + if(((npc_jaina_and_sylvana_FSintroAI*)pCreature->AI())->StartEvent != true) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What would you have of me, My Lady?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + break; + case 37596: + if(((npc_jaina_and_sylvana_FSintroAI*)pCreature->AI())->StartEvent != true) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What would you have of me, Banshee Queen?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + break; + } + + pPlayer->PlayerTalkClass->SendGossipMenu(907,pCreature->GetObjectGuid()); //907 + return true; +} + +bool GossipSelect_npc_jaina_and_sylvana_FSintro(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + pPlayer->CLOSE_GOSSIP_MENU(); + ((npc_jaina_and_sylvana_FSintroAI*)pCreature->AI())->StartEvent = true; + + return true; +} + +struct MANGOS_DLL_DECL npc_jaina_and_sylvana_FSextroAI : public ScriptedAI +{ + npc_jaina_and_sylvana_FSextroAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetActiveObjectState(true); + Reset(); + } + +ScriptedInstance* m_pInstance; + +uint32 StepTimer; +uint32 Step; +uint64 m_uiLiderGUID; +uint32 uiSummon_counter; + + void Reset() + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_DEVOURER_OF_SOULS) != DONE) + { + m_pInstance->SetData(TYPE_DEVOURER_OF_SOULS, NOT_STARTED); + Step = 0; + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + else Step = 10; + StepTimer = 100; + m_creature->SetVisibility(VISIBILITY_ON); + } + } + + void UpdateAI(const uint32 diff) + { + DoMeleeAttackIfReady(); + + if (!m_pInstance) return; + + if (m_pInstance->GetData(TYPE_DEVOURER_OF_SOULS) == DONE) + { + + if(StepTimer < diff) + { + switch(Step) + { + case 0: + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(0, 5653.337f, 2496.407f, 708.829f); + uiSummon_counter = 0; + StepTimer = 400; + ++Step; + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + if(m_creature->GetEntry() == NPC_JAINA_END) + { + DoScriptText(SAY_JAINA_FS09_EXTRO, m_creature); + StepTimer = 6000; + } + if(m_creature->GetEntry() == NPC_SILVANA_END) + { + DoScriptText(SAY_SYLVANA_FS07_EXTRO, m_creature); + StepTimer = 3000; + } + ++Step; + break; + case 5: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + ++Step; + break; + } + } else StepTimer -= diff; + } + return; + } +}; + +CreatureAI* GetAI_npc_jaina_and_sylvana_FSintro(Creature* pCreature) +{ + return new npc_jaina_and_sylvana_FSintroAI(pCreature); +} + +CreatureAI* GetAI_npc_jaina_and_sylvana_FSextro(Creature* pCreature) +{ + return new npc_jaina_and_sylvana_FSextroAI(pCreature); +} + +void AddSC_forge_of_souls() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_jaina_and_sylvana_FSintro"; + newscript->GetAI = &GetAI_npc_jaina_and_sylvana_FSintro; + newscript->pGossipHello = &GossipHello_npc_jaina_and_sylvana_FSintro; + newscript->pGossipSelect = &GossipSelect_npc_jaina_and_sylvana_FSintro; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_jaina_and_sylvana_FSextro"; + newscript->GetAI = &GetAI_npc_jaina_and_sylvana_FSextro; + newscript->RegisterSelf(); +} 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 a6767f0589..cbcaa3ef49 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,15 +1,17 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef DEF_FORGE_OF_SOULS_H #define DEF_FORGE_OF_SOULS_H +#include "BSW_ai.h" enum { MAX_ENCOUNTER = 2, + TYPE_INTRO = 0, TYPE_BRONJAHM = 1, - TYPE_DECOURER_OF_SOULS = 2, + TYPE_DEVOURER_OF_SOULS = 2, TYPE_ACHIEV_PHANTOM_BLAST = 3, DATA_SOULFRAGMENT_REMOVE = 4, // on Death and on Use @@ -94,36 +96,31 @@ class MANGOS_DLL_DECL instance_forge_of_souls : public ScriptedInstance 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); - uint64 GetData64(uint32 uiData); - 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; - Player* GetPlayer(); - 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 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]; - std::string strInstData; + std::string m_strInstData; bool m_bCriteriaPhantomBlastFailed; uint32 m_uiTeam; // Team of first entered player, used to set if Jaina or Silvana to spawn - uint64 m_uiBronjahmGUID; - uint64 m_uiDevourerOrSoulsGUID; - - std::list m_luiSoulFragmentAliveGUIDs; - std::list 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 2b9afa4cf9..21701b3473 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,9 +26,7 @@ EndScriptData */ instance_forge_of_souls::instance_forge_of_souls(Map* pMap) : ScriptedInstance(pMap), m_bCriteriaPhantomBlastFailed(false), - m_uiTeam(0), - m_uiBronjahmGUID(0), - m_uiDevourerOrSoulsGUID(0) + m_uiTeam(0) { Initialize(); } @@ -40,11 +38,16 @@ void instance_forge_of_souls::Initialize() void instance_forge_of_souls::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - case NPC_BRONJAHM: m_uiBronjahmGUID = pCreature->GetGUID(); break; - case NPC_DEVOURER_OF_SOULS: m_uiDevourerOrSoulsGUID = pCreature->GetGUID(); break; - case NPC_CORRUPTED_SOUL_FRAGMENT: m_luiSoulFragmentAliveGUIDs.push_back(pCreature->GetGUID()); break; + case NPC_DEVOURER_OF_SOULS: + case NPC_BRONJAHM: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + case NPC_CORRUPTED_SOUL_FRAGMENT: + m_luiSoulFragmentAliveGUIDs.push_back(pCreature->GetObjectGuid()); + break; } } @@ -65,11 +68,11 @@ 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)) - m_lEventMobGUIDs.push_back(pSummon->GetGUID()); + 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()); } } else @@ -77,47 +80,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 (std::list::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); } } } } -Player* instance_forge_of_souls::GetPlayer() -{ - Map::PlayerList const& players = instance->GetPlayers(); - - if (!players.isEmpty()) - { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* plr = itr->getSource()) - return plr; - } - } - return NULL; -} - -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) { @@ -132,23 +121,23 @@ 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 (std::list::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(); } m_luiSoulFragmentAliveGUIDs.clear(); break; - case TYPE_DECOURER_OF_SOULS: + case TYPE_DEVOURER_OF_SOULS: m_auiEncounter[1] = uiData; if (uiData == DONE) - ProcessEventNpcs(GetPlayer(), true); + ProcessEventNpcs(GetPlayerInMap(), true); break; case TYPE_ACHIEV_PHANTOM_BLAST: m_bCriteriaPhantomBlastFailed = (uiData == FAIL); @@ -162,7 +151,7 @@ void instance_forge_of_souls::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -182,7 +171,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; @@ -191,36 +180,23 @@ 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]; - case TYPE_DECOURER_OF_SOULS: + case TYPE_DEVOURER_OF_SOULS: return m_auiEncounter[1]; default: return 0; } } -uint64 instance_forge_of_souls::GetData64(uint32 uiData) -{ - switch(uiData) - { - case NPC_BRONJAHM: - return m_uiBronjahmGUID; - case NPC_DEVOURER_OF_SOULS: - return m_uiDevourerOrSoulsGUID; - default: - return 0; - } -} - void instance_forge_of_souls::SetData64(uint32 uiType, uint64 uiData) { if (uiType == DATA_SOULFRAGMENT_REMOVE) - m_luiSoulFragmentAliveGUIDs.remove(uiData); + m_luiSoulFragmentAliveGUIDs.remove(ObjectGuid(uiData)); } InstanceData* GetInstanceData_instance_forge_of_souls(Map* pMap) 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 new file mode 100644 index 0000000000..741aaaae69 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falric.cpp @@ -0,0 +1,229 @@ +/* Copyright (C) 2006 - 2013 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_falric +SD%Complete: 70% +SDComment: +SDAuthor: /dev/rsa, changed by MaxXx2021 aka Mioka +SDCategory: Halls of Reflection +EndScriptData */ + +#include "precompiled.h" +#include "halls_of_reflection.h" + +enum +{ + SAY_FALRIC_AGGRO = -1668507, + SAY_FALRIC_DEATH = -1668508, + SAY_FALRIC_SLAY01 = -1668509, + SAY_FALRIC_SLAY02 = -1668510, + SAY_FALRIC_SP01 = -1668511, + SAY_FALRIC_SP02 = -1668512, + + SPELL_HOPELESSNESS = 72395, + SPELL_IMPENDING_DESPAIR = 72426, + SPELL_DEFILING_HORROR = 72435, + //SPELL_DEFILING_HORROR_H = 72452, + SPELL_QUIVERING_STRIKE = 72422, + //SPELL_QUIVERING_STRIKE_H = 72453, + + SPELL_BERSERK = 47008 +}; + +struct MANGOS_DLL_DECL boss_falricAI : public BSWScriptedAI +{ + boss_falricAI(Creature *pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsCall; + + uint32 m_uiSummonTimer; + uint32 m_uiLocNo; + GuidVector m_uiSummonGUID; + uint8 SummonCount; + uint32 pSummon; + + void Reset() + { + SummonCount = 0; + m_bIsCall = false; + m_uiSummonTimer = 11000; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void Aggro(Unit* pVictim) + { + m_creature->SetWalk(false); + DoScriptText(SAY_FALRIC_AGGRO, m_creature); + DoCast(m_creature, SPELL_HOPELESSNESS); + } + + void KilledUnit(Unit* pVictim) override + { + switch(urand(0,1)) + { + case 0: DoScriptText(SAY_FALRIC_SLAY01, m_creature); break; + case 1: DoScriptText(SAY_FALRIC_SLAY02, m_creature); break; + } + } + + void JustDied(Unit* pKiller) override + { + if(!m_pInstance) + return; + m_pInstance->SetData(TYPE_MARWYN, SPECIAL); + DoScriptText(SAY_FALRIC_DEATH, m_creature); + } + + void AttackStart(Unit* who) + { + if(!m_pInstance) return; + + if(m_pInstance->GetData(TYPE_FALRIC) != IN_PROGRESS) + return; + + ScriptedAI::AttackStart(who); + } + + void Summon() + { + m_uiLocNo = 0; + + for(uint8 i = 0; i < 16; i++) + { + switch(urand(0,3)) + { + case 0: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_1; break; + case 2: pSummon = NPC_DARK_3; break; + case 3: pSummon = NPC_DARK_6; break; + } + break; + case 1: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_2; break; + case 2: pSummon = NPC_DARK_3; break; + case 3: pSummon = NPC_DARK_4; break; + } + break; + case 2: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_2; break; + case 2: pSummon = NPC_DARK_5; break; + case 3: pSummon = NPC_DARK_6; break; + } + break; + case 3: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_1; break; + case 2: pSummon = NPC_DARK_5; break; + case 3: pSummon = NPC_DARK_4; break; + } + break; + } + + if(Creature* Summon = m_creature->SummonCreature(pSummon, SpawnLoc[m_uiLocNo].x, SpawnLoc[m_uiLocNo].y, SpawnLoc[m_uiLocNo].z, SpawnLoc[m_uiLocNo].o, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000)) + { + m_uiSummonGUID.push_back(Summon->GetObjectGuid()); + Summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Summon->setFaction(974); + } + m_uiLocNo++; + } + } + + void CallFallSoldier() + { + for (uint8 i = 0; i < 4 && m_uiSummonGUID.size(); i++) + { + if(Creature* Summon = m_pInstance->instance->GetCreature(m_uiSummonGUID.back())) + { + Summon->setFaction(14); + Summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Summon->SetInCombatWithZone(); + } + m_uiSummonGUID.pop_back(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EVENT) == 5) + { + m_pInstance->SetData(TYPE_EVENT, 6); + Summon(); + } + + if (m_pInstance->GetData(TYPE_FALRIC) == SPECIAL) + { + + if (m_uiSummonTimer < uiDiff) + { + ++SummonCount; + m_pInstance->SetData(DATA_WAVE_COUNT,SummonCount); + if(SummonCount > 4) + { + m_pInstance->SetData(TYPE_FALRIC, IN_PROGRESS); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetInCombatWithZone(); + } + else CallFallSoldier(); + m_uiSummonTimer = 60000; + } else m_uiSummonTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + timedCast(SPELL_QUIVERING_STRIKE, uiDiff); + timedCast(SPELL_IMPENDING_DESPAIR, uiDiff); + timedCast(SPELL_DEFILING_HORROR, uiDiff); + + timedCast(SPELL_BERSERK, uiDiff); + + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_boss_falric(Creature* pCreature) +{ + return new boss_falricAI(pCreature); +} + +void AddSC_boss_falric() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_falric"; + newscript->GetAI = &GetAI_boss_falric; + newscript->RegisterSelf(); +} 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 78d6d649c6..f3742b978f 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,663 @@ /* ScriptData SDName: boss_lich_king -SD%Complete: 0% +SD%Complete: 100% SDComment: +SDAuthor: MaxXx2021 aka Mioka SDCategory: Halls of Reflection EndScriptData */ #include "precompiled.h" +#include "halls_of_reflection.h" +#include "escort_ai.h" + +enum +{ + SPELL_WINTER = 69780, + SPELL_FURY_OF_FROSTMOURNE = 70063, + SPELL_SOUL_REAPER = 73797, + SPELL_ICE_PRISON = 69708, + SPELL_DARK_ARROW = 70194, + SPELL_EMERGE_VISUAL = 50142, + SPELL_DESTROY_ICE_WALL_02 = 70224, + SPELL_SILENCE = 69413, + SPELL_LICH_KING_CAST = 57561, + SPELL_GNOUL_JUMP = 70150, + SPELL_ABON_STRIKE = 40505, + + // summon spells + SPELL_WITCH_DOCTOR = 69836, + SPELL_SUMMON_ABOM = 69835, + SPELL_RAISE_DEAD = 69818, + + /*SPELLS - Witch Doctor, 36941 */ + SPELL_COURSE_OF_DOOM = 70144, + SPELL_SHADOW_BOLT_VALLEY = 70145, + SPELL_SHADOW_BOLT = 70080, + + /*SPELLS - abomination, 37069 */ + SPELL_CLEAVE = 40505, + + /*SPELLS - raging ghoul, 36940 */ + SPELL_LEAP = 70150, + + SAY_LICH_KING_WALL_01 = -1594486, + SAY_LICH_KING_WALL_02 = -1594491, + SAY_LICH_KING_GNOUL = -1594482, + SAY_LICH_KING_ABON = -1594483, + SAY_LICH_KING_WINTER = -1594481, + SAY_LICH_KING_END_DUN = -1594504, + SAY_LICH_KING_WIN = -1594485, + + /*INTRO - Lich King Arrive*/ + SAY_LICH_KING_17 = -1668468, + SAY_LICH_KING_18 = -1668469, + SAY_LICH_KING_19 = -1668470, + SAY_JAINA_20 = -1668471, + SAY_SYLVANA_20 = -1668472, + SAY_LICH_KING_A_21 = -1668473, + SAY_LICH_KING_H_21 = -1668474, + SAY_FALRIC_INTRO = -1668475, + SAY_MARWYN_INTRO = -1668476, + SAY_FALRIC_INTRO2 = -1668505, + + SPELL_TAKE_FROSTMOURNE = 72729, + SPELL_FROSTMOURNE_DESPAWN = 72726, + SPELL_FROSTMOURNE_SOUNDS = 70667, + SPELL_CAST_VISUAL = 65633, //Jaina And Sylavana cast this when summon uther. + SPELL_BOSS_SPAWN_AURA = 72712, //Falric and Marwyn + SPELL_UTHER_DESPAWN = 70693, + SPELL_FROSTMOURNE_VISUAL = 73220, + + /*INTRO - Pre Escape*/ + SAY_LICH_KING_AGGRO_A = -1668477, + SAY_LICH_KING_AGGRO_H = -1668478, + SAY_JAINA_AGGRO = -1668479, + SAY_SYLVANA_AGGRO = -1668480, + +}; + +struct MANGOS_DLL_DECL boss_lich_king_hrAI : public npc_escortAI +{ + boss_lich_king_hrAI(Creature *pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + BSWScriptedInstance* m_pInstance; + bool StartEscort; + bool NonFight; + bool Finish; + + void Reset() + { + if(!m_pInstance) return; + NonFight = false; + StartEscort = false; + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, 36942); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (m_pInstance->GetData(TYPE_LICH_KING) == DONE) + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void JustDied(Unit* pKiller) override + { + } + + void MoveInLineOfSight(Unit* who) override + { + if (!who || !m_pInstance) + return; + + if (who->GetTypeId() != TYPEID_PLAYER) + return; + + Player* pPlayer = (Player *)who; + + if (pPlayer->isGameMaster()) + return; + + if (m_pInstance->GetData(TYPE_PHASE) != 3 + || m_pInstance->GetData(TYPE_LICH_KING) == DONE + || !m_creature->IsWithinDistInMap(who, 50.0f) + || m_pInstance->GetData(TYPE_FROST_GENERAL) != DONE) + return; + + m_pInstance->DoOpenDoor(GO_ICECROWN_DOOR_2); + + Team team = TEAM_NONE; + if (Group* pGroup = pPlayer->GetGroup()) + { + ObjectGuid LeaderGuid = pGroup->GetLeaderGuid(); + if (!LeaderGuid.IsEmpty()) + if (Player* pLeader =m_creature->GetMap()->GetPlayer(LeaderGuid)) + team = pLeader->GetTeam(); + } + else + team = ((Player*)who)->GetTeam(); + + uint32 newLeader; + + if (team == ALLIANCE) + newLeader = NPC_JAINA_OUTRO; + else + newLeader = NPC_SYLVANA_OUTRO; + + if (Creature* pNewLeader = m_creature->SummonCreature(newLeader,WallLoc[6].x,WallLoc[6].y,WallLoc[6].z,WallLoc[6].o,TEMPSUMMON_MANUAL_DESPAWN,0,true)) + { + pNewLeader->SetWalk(false); + pNewLeader->SetSpeedRate(MOVE_RUN, 1.0f, true); + pNewLeader->SetRespawnDelay(DAY); + pNewLeader->SetHealth(pNewLeader->GetMaxHealth()/10); + m_pInstance->SetData(DATA_ESCAPE_LIDER, pNewLeader->GetEntry()); + } + m_pInstance->DoOpenDoor(GO_ICECROWN_DOOR_2); + m_pInstance->SetData(TYPE_PHASE, 4); + m_pInstance->SetNextEvent(100,GetLeader(),500); + } + + void WaypointReached(uint32 i) override + { + switch(i) + { + case 20: + SetEscortPaused(true); + Finish = true; + DoCast(m_creature, SPELL_LICH_KING_CAST); + m_pInstance->SetData(TYPE_LICH_KING, SPECIAL); + DoScriptText(SAY_LICH_KING_END_DUN, m_creature); + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + { + pLider->CastSpell(pLider, SPELL_SILENCE, false); + pLider->SetLevitate(true); + pLider->MonsterMoveWithSpeed(pLider->GetPositionX(), pLider->GetPositionY(), pLider->GetPositionZ() + 4, 26); + } + m_pInstance->SetData(TYPE_PHASE, 6); + m_pInstance->SetNextEvent(610,GetLeader(),5000); + m_creature->SetActiveObjectState(false); + break; + } + } + + void AttackStart(Unit* who) + { + if (!m_pInstance || !who || NonFight) + return; + + if (m_pInstance->GetData(TYPE_LICH_KING) == IN_PROGRESS || who->GetTypeId() == TYPEID_PLAYER) return; + + npc_escortAI::AttackStart(who); + } + + void SummonedCreatureJustDied(Creature* summoned) + { + if(!m_pInstance || !summoned) + return; + + if (summoned->GetEntry() == NPC_JAINA_OUTRO + || summoned->GetEntry() == NPC_SYLVANA_OUTRO) + { + m_creature->NearTeleportTo(5572.077f, 2283.1f, 734.976f, 3.89f); + if (boss_lich_king_hrAI* pEscortAI = dynamic_cast(m_creature->AI())) + pEscortAI->EnterEvadeMode(); + StartEscort = false; + } + else + m_pInstance->SetData(DATA_SUMMONS, 0); + } + + void JustSummoned(Creature* summoned) + { + if (!m_pInstance || !summoned) + return; + + if (summoned->GetEntry() == NPC_JAINA_OUTRO + || summoned->GetEntry() == NPC_SYLVANA_OUTRO) + { + summoned->SetCreatorGuid(ObjectGuid()); + summoned->setFaction(2076); + summoned->SetPhaseMask(65535, true); + m_creature->SetInCombatWith(summoned); + summoned->SetInCombatWith(m_creature); + } + else + { + summoned->SetPhaseMask(65535, true); + summoned->SetInCombatWithZone(); + summoned->SetActiveObjectState(true); + + m_pInstance->SetData(DATA_SUMMONS, 1); + + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + { + summoned->GetMotionMaster()->MoveChase(pLider); + summoned->AddThreat(pLider, 100.0f); + } + } + } + + uint32 GetLeader() + { + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + return pLider->GetEntry(); + else + return 0; + } + + void Event() + { + switch (m_pInstance->GetEvent(m_creature->GetEntry())) + { +// Intro phase + case 101: + if(GetLeader() == NPC_JAINA_OUTRO) + DoScriptText((GetLeader() == NPC_JAINA_OUTRO ? SAY_LICH_KING_AGGRO_A : SAY_LICH_KING_AGGRO_H), m_creature); + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + AttackStart(pLider); + m_pInstance->SetNextEvent(102,GetLeader(),3000); + break; + +// Active phase + case 200: + SetEscortPaused(true); + m_pInstance->SetData(DATA_SUMMONS, 3); + DoScriptText(SAY_LICH_KING_WALL_01, m_creature); + m_pInstance->SetNextEvent(210,m_creature->GetEntry(),2000); + break; + case 210: + m_pInstance->SetNextEvent(220,m_creature->GetEntry(),2000); + break; + case 220: + DoCast(m_creature, SPELL_RAISE_DEAD); + DoScriptText(SAY_LICH_KING_GNOUL, m_creature); + m_pInstance->SetNextEvent(230,m_creature->GetEntry(),7000); + break; + case 230: + DoScriptText(SAY_LICH_KING_WINTER, m_creature); + DoCast(m_creature, SPELL_WINTER); + m_creature->SetSpeedRate(MOVE_WALK, 1.3f, true); + m_pInstance->SetNextEvent(240,m_creature->GetEntry(),1000); + break; + case 240: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + SetEscortPaused(false); + m_pInstance->SetNextEvent(250,m_creature->GetEntry(),2000); + break; + case 250: + m_pInstance->SetNextEvent(290,GetLeader(),1000); + DoCast(m_creature, SPELL_WITCH_DOCTOR); + break; + + case 300: + SetEscortPaused(true); + DoCast(m_creature, SPELL_SUMMON_ABOM); + m_pInstance->SetData(DATA_SUMMONS, 3); + DoScriptText(SAY_LICH_KING_GNOUL, m_creature); + m_pInstance->SetNextEvent(310,m_creature->GetEntry(),500); + break; + case 310: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(320,m_creature->GetEntry(),500); + break; + case 320: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(330,m_creature->GetEntry(),5000); + break; + case 330: + DoCast(m_creature, SPELL_RAISE_DEAD); + SetEscortPaused(false); + m_pInstance->SetNextEvent(390,GetLeader(),1000); + break; + + case 400: + SetEscortPaused(true); + DoCast(m_creature, SPELL_SUMMON_ABOM); + m_pInstance->SetData(DATA_SUMMONS, 3); + DoScriptText(SAY_LICH_KING_GNOUL, m_creature); + m_pInstance->SetNextEvent(410,m_creature->GetEntry(),500); + break; + case 410: + DoScriptText(SAY_LICH_KING_ABON, m_creature); + DoCast(m_creature, SPELL_SUMMON_ABOM); + m_pInstance->SetNextEvent(420,m_creature->GetEntry(),500); + break; + case 420: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(430,m_creature->GetEntry(),500); + break; + case 430: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(440,m_creature->GetEntry(),500); + break; + case 440: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(450,m_creature->GetEntry(),500); + break; + case 450: + DoCast(m_creature, SPELL_RAISE_DEAD); + m_pInstance->SetNextEvent(490,GetLeader(),5000); + SetEscortPaused(false); + break; + + case 500: + m_pInstance->SetData(DATA_SUMMONS, 3); + DoScriptText(SAY_LICH_KING_GNOUL, m_creature); + DoCast(m_creature, SPELL_SUMMON_ABOM); + m_pInstance->SetNextEvent(510,m_creature->GetEntry(),10000); + break; + case 510: + m_creature->SetSpeedRate(MOVE_WALK, 1.3f, true); + DoCast(m_creature, SPELL_SUMMON_ABOM); + m_pInstance->SetNextEvent(520,m_creature->GetEntry(),500); + break; + case 520: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(530,m_creature->GetEntry(),500); + break; + case 530: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(540,m_creature->GetEntry(),500); + break; + case 540: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(550,m_creature->GetEntry(),500); + break; + case 550: + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(570,m_creature->GetEntry(),2000); + break; + case 570: + DoScriptText(SAY_LICH_KING_ABON, m_creature); + DoCast(m_creature, SPELL_WITCH_DOCTOR); + m_pInstance->SetNextEvent(580,m_creature->GetEntry(),5000); + break; + case 580: + DoScriptText(SAY_LICH_KING_ABON, m_creature); + DoCast(m_creature, SPELL_RAISE_DEAD); + m_pInstance->SetNextEvent(590,GetLeader(),1000); + break; + + case 900: + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + m_creature->DealDamage(pLider, pLider->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_pInstance->SetData(TYPE_LICH_KING, FAIL); + m_creature->SetActiveObjectState(false); + m_pInstance->SetData(TYPE_PHASE, 3); + m_pInstance->SetNextEvent(0,0); + break; + + default: + break; + } + } + + void UpdateEscortAI(const uint32 diff) + { + if(!m_pInstance) + return; + + if ( (m_pInstance->GetData(TYPE_PHASE) == 4 || m_pInstance->GetData(TYPE_PHASE) == 5 || m_pInstance->GetData(TYPE_PHASE) == 7) + && m_pInstance->GetEventTimer(m_creature->GetEntry(),diff)) + Event(); + + if(m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + return; + } + + if(m_pInstance->GetData(TYPE_LICH_KING) == IN_PROGRESS && !StartEscort) + { + StartEscort = true; + if(m_creature->HasAura(SPELL_ICE_PRISON)) + m_creature->RemoveAurasDueToSpell(SPELL_ICE_PRISON); + if(m_creature->HasAura(SPELL_DARK_ARROW)) + m_creature->RemoveAurasDueToSpell(SPELL_DARK_ARROW); + + m_creature->SetActiveObjectState(true); + + NonFight = true; + m_creature->AttackStop(); + m_creature->SetWalk(true); + m_creature->SetSpeedRate(MOVE_WALK, 2.7f, true); + if (boss_lich_king_hrAI* pEscortAI = dynamic_cast(m_creature->AI())) + pEscortAI->Start(); + } + if (m_pInstance->GetData(TYPE_PHASE) == 5) + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + if (pLider->isAlive() && pLider->IsWithinDistInMap(m_creature, 2.0f)) + { + m_pInstance->SetData(TYPE_PHASE,7); + SetEscortPaused(true); + m_creature->GetMotionMaster()->Clear(); + DoScriptText(SAY_LICH_KING_WIN, m_creature); + m_pInstance->SetNextEvent(900,m_creature->GetEntry(),4000); + m_creature->CastSpell(m_creature, SPELL_FURY_OF_FROSTMOURNE, false); + }; + + return; + } +}; + +CreatureAI* GetAI_boss_lich_king_hr(Creature* pCreature) +{ + return new boss_lich_king_hrAI(pCreature); +} + +struct MANGOS_DLL_DECL boss_lich_king_intro_horAI : public ScriptedAI +{ + boss_lich_king_intro_horAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + BSWScriptedInstance* m_pInstance; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void JustDied(Unit* pKiller) override + { + } + + void AttackStart(Unit* who) + { + } + + uint32 GetLeader() + { + if (Creature* pLider = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(DATA_ESCAPE_LIDER))) + return pLider->GetEntry(); + else + return 0; + } + + void Event() + { + switch(m_pInstance->GetEvent(m_creature->GetEntry())) + { + case 24: + m_pInstance->DoOpenDoor(GO_IMPENETRABLE_DOOR); + m_pInstance->SetNextEvent(25,GetLeader(),1000); + break; + case 25: + m_creature->GetMotionMaster()->MovePoint(0, 5314.881f, 2012.496f, 709.341f); + m_pInstance->SetNextEvent(26,m_creature->GetEntry(),3000); + break; + case 26: + m_pInstance->DoCloseDoor(GO_IMPENETRABLE_DOOR); + m_pInstance->SetNextEvent(27,m_creature->GetEntry(),7000); + break; + case 27: + DoScriptText(SAY_LICH_KING_17, m_creature); + if (Creature* pUther = (m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER))) + pUther->CastSpell(pUther, SPELL_UTHER_DESPAWN, false); + m_pInstance->SetNextEvent(28,m_creature->GetEntry(),1500); + break; + case 28: + if (Creature* pUther = (m_pInstance->GetSingleCreatureFromStorage(NPC_UTHER))) + pUther->ForcedDespawn(); + m_pInstance->SetNextEvent(29,m_creature->GetEntry(),10000); + break; + case 29: + DoScriptText(SAY_LICH_KING_18, m_creature); + m_pInstance->SetNextEvent(30,m_creature->GetEntry(),5000); + break; + case 30: + m_creature->CastSpell(m_creature, SPELL_TAKE_FROSTMOURNE, false); + m_pInstance->DoCloseDoor(GO_FROSTMOURNE); + m_pInstance->SetNextEvent(31,m_creature->GetEntry(),1500); + break; + case 31: + if (GameObject* pFrostmourne = m_pInstance->GetSingleGameObjectFromStorage(GO_FROSTMOURNE)) + pFrostmourne->SetPhaseMask(0, true); + m_creature->CastSpell(m_creature, SPELL_FROSTMOURNE_VISUAL, false); + m_pInstance->SetNextEvent(31,GetLeader(),500); + break; + case 32: + DoScriptText(SAY_LICH_KING_19, m_creature); + m_pInstance->SetNextEvent(33,m_creature->GetEntry(),9000); + break; + case 33: + if (Creature* pFalric = (m_pInstance->GetSingleCreatureFromStorage(NPC_FALRIC))) + { + pFalric->SetVisibility(VISIBILITY_ON); + pFalric->CastSpell(pFalric, SPELL_BOSS_SPAWN_AURA, false); + pFalric->GetMotionMaster()->MovePoint(0, 5283.309f, 2031.173f, 709.319f); + } + if (Creature* pMarwyn = (m_pInstance->GetSingleCreatureFromStorage(NPC_MARWYN))) + { + pMarwyn->SetVisibility(VISIBILITY_ON); + pMarwyn->CastSpell(pMarwyn, SPELL_BOSS_SPAWN_AURA, false); + pMarwyn->GetMotionMaster()->MovePoint(0, 5335.585f, 1981.439f, 709.319f); + } + m_creature->GetMotionMaster()->MovePoint(0, 5402.286f, 2104.496f, 707.695f); + m_pInstance->SetNextEvent(34,m_creature->GetEntry(),1000); + break; + case 34: + if (Creature* pFalric = (m_pInstance->GetSingleCreatureFromStorage(NPC_FALRIC))) + DoScriptText(SAY_FALRIC_INTRO, pFalric); + if (Creature* pMarwyn = (m_pInstance->GetSingleCreatureFromStorage(NPC_MARWYN))) + DoScriptText(SAY_MARWYN_INTRO, pMarwyn); + m_pInstance->SetData(TYPE_EVENT, 5); + m_pInstance->SetNextEvent(35,m_creature->GetEntry(),3000); + break; + case 35: + if (GameObject* pGate = m_pInstance->GetSingleGameObjectFromStorage(GO_IMPENETRABLE_DOOR)) + pGate->SetGoState(GO_STATE_ACTIVE); + if (Creature* pFalric = m_pInstance->GetSingleCreatureFromStorage(NPC_FALRIC)) + DoScriptText(SAY_FALRIC_INTRO2, pFalric); + m_pInstance->SetData(TYPE_FALRIC, SPECIAL); + m_pInstance->SetNextEvent(36,GetLeader(),4000); + break; + case 37: + m_creature->GetMotionMaster()->MovementExpired(false); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(0, 5443.880f, 2147.095f, 707.695f); + if (GetLeader() == NPC_JAINA) + DoScriptText(SAY_LICH_KING_A_21, m_creature); + else if (GetLeader() == NPC_SYLVANA) + DoScriptText(SAY_LICH_KING_H_21, m_creature); + m_pInstance->SetNextEvent(38,m_creature->GetEntry(),8000); + break; + case 38: + m_pInstance->DoCloseDoor(GO_IMPENETRABLE_DOOR); + m_pInstance->SetNextEvent(39,m_creature->GetEntry(),5000); + break; + case 39: + m_creature->SetVisibility(VISIBILITY_OFF); + m_pInstance->SetNextEvent(39,GetLeader(),1000); + break; + case 40: + m_pInstance->SetData(TYPE_PHASE, 2); + m_pInstance->SetNextEvent(0,0); + m_creature->ForcedDespawn(500); + break; + default: + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetEventTimer(m_creature->GetEntry(),diff) && m_pInstance->GetData(TYPE_PHASE) == 1) + Event(); + + } +}; + +CreatureAI* GetAI_boss_lich_king_intro_hor(Creature* pCreature) +{ + return new boss_lich_king_intro_horAI(pCreature); +} + +struct MANGOS_DLL_DECL npc_undead_horAI : public BSWScriptedAI +{ + npc_undead_horAI(Creature *pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + } + + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + doCastAll(uiDiff); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_undead_hor(Creature* pCreature) +{ + return new npc_undead_horAI(pCreature); +} + +void AddSC_boss_lich_king_hr() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_lich_king_hr"; + newscript->GetAI = &GetAI_boss_lich_king_hr; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_lich_king_intro_hor"; + newscript->GetAI = &GetAI_boss_lich_king_intro_hor; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_undead_hor"; + newscript->GetAI = &GetAI_npc_undead_hor; + newscript->RegisterSelf(); +} 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 9bc11a1fd2..8fac1fffe9 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,224 @@ /* ScriptData SDName: boss_marwyn -SD%Complete: 0% +SD%Complete: 60% SDComment: +SDAuthor: /dev/rsa, changed by MaxXx2021 aka Mioka SDCategory: Halls of Reflection EndScriptData */ #include "precompiled.h" +#include "halls_of_reflection.h" + +enum +{ + SAY_MARWYN_INTRO = -1668506, + SAY_MARWYN_AGGRO = -1668513, + SAY_MARWYN_DEATH = -1668514, + SAY_MARWYN_SLAY01 = -1668515, + SAY_MARWYN_SLAY02 = -1668516, + SAY_MARWYN_SP01 = -1668517, + SAY_MARWYN_SP02 = -1668518, + + SPELL_OBLITERATE = 72360, + SPELL_SHARED_SUFFERING = 72368, + SPELL_WELL_OF_CORRUPTION = 72362, + SPELL_CORRUPTED_FLESH = 72436, + + SPELL_BERSERK = 47008, +}; + +struct MANGOS_DLL_DECL boss_marwynAI : public BSWScriptedAI +{ + boss_marwynAI(Creature *pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsCall; + uint32 m_uiSummonTimer; + + uint32 m_uiLocNo; + GuidVector m_uiSummonGUID; + uint32 m_uiCheckSummon; + + uint8 SummonCount; + + uint32 pSummon; + + void Reset() + { + SummonCount = 0; + m_uiCheckSummon = 0; + m_bIsCall = false; + m_uiSummonTimer = 15000; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void Summon() + { + m_uiLocNo = 14; + + for(uint8 i = 0; i < 16; i++) + { + switch(urand(0,3)) + { + case 0: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_1; break; + case 2: pSummon = NPC_DARK_3; break; + case 3: pSummon = NPC_DARK_6; break; + } + break; + case 1: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_2; break; + case 2: pSummon = NPC_DARK_3; break; + case 3: pSummon = NPC_DARK_4; break; + } + break; + case 2: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_2; break; + case 2: pSummon = NPC_DARK_5; break; + case 3: pSummon = NPC_DARK_6; break; + } + break; + case 3: + switch(urand(1, 3)) + { + case 1: pSummon = NPC_DARK_1; break; + case 2: pSummon = NPC_DARK_5; break; + case 3: pSummon = NPC_DARK_4; break; + } + break; + } + + m_uiCheckSummon = 0; + + if(Creature* Summon = m_creature->SummonCreature(pSummon, SpawnLoc[m_uiLocNo].x, SpawnLoc[m_uiLocNo].y, SpawnLoc[m_uiLocNo].z, SpawnLoc[m_uiLocNo].o, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000)) + { + m_uiSummonGUID.push_back(Summon->GetObjectGuid()); + Summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Summon->setFaction(974); + } + m_uiLocNo++; + } + } + + void CallFallSoldier() + { + for (uint8 i = 0; i < 4 && m_uiSummonGUID.size(); i++) + { + if (Creature* Summon = m_pInstance->instance->GetCreature(m_uiSummonGUID.back())) + { + Summon->setFaction(14); + Summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Summon->SetInCombatWithZone(); + } + m_uiSummonGUID.pop_back(); + } + } + + void JustDied(Unit* pKiller) override + { + if(m_pInstance) + { + m_pInstance->SetData(TYPE_MARWYN, DONE); + m_pInstance->SetData(TYPE_PHASE, 3); + } + + DoScriptText(SAY_MARWYN_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + switch(urand(0,1)) + { + case 0: DoScriptText(SAY_MARWYN_SLAY01, m_creature); break; + case 1: DoScriptText(SAY_MARWYN_SLAY02, m_creature); break; + } + } + + void Aggro(Unit* pVictim) + { + if (!m_pInstance) return; + m_creature->SetWalk(false); + DoScriptText(SAY_MARWYN_AGGRO, m_creature); + } + + void AttackStart(Unit* who) + { + if (!m_pInstance) return; + + if (m_pInstance->GetData(TYPE_MARWYN) != IN_PROGRESS) + return; + + ScriptedAI::AttackStart(who); + } + + void UpdateAI(const uint32 uiDiff) override + { + if(!m_pInstance) return; + + if (m_pInstance->GetData(TYPE_EVENT) == 6) + { + m_pInstance->SetData(TYPE_EVENT, 7); + Summon(); + } + + if(m_pInstance->GetData(TYPE_MARWYN) == SPECIAL) + { + if(m_uiSummonTimer < uiDiff) + { + ++SummonCount; + m_pInstance->SetData(DATA_WAVE_COUNT,SummonCount+5); + if(SummonCount == 1) + DoScriptText(SAY_MARWYN_INTRO, m_creature); + + if(SummonCount > 4) + { + m_pInstance->SetData(TYPE_MARWYN, IN_PROGRESS); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetInCombatWithZone(); + } + else CallFallSoldier(); + m_uiSummonTimer = 60000; + } else m_uiSummonTimer -= uiDiff; + } + + if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + timedCast(SPELL_OBLITERATE, uiDiff); + timedCast(SPELL_WELL_OF_CORRUPTION, uiDiff); + timedCast(SPELL_SHARED_SUFFERING, uiDiff); + timedCast(SPELL_CORRUPTED_FLESH, uiDiff); + + timedCast(SPELL_BERSERK, uiDiff); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_marwyn(Creature* pCreature) +{ + return new boss_marwynAI(pCreature); +} + +void AddSC_boss_marwyn() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_marwyn"; + newscript->GetAI = &GetAI_boss_marwyn; + newscript->RegisterSelf(); +} 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 new file mode 100644 index 0000000000..56f6eb3285 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.cpp @@ -0,0 +1,1354 @@ +/* Copyright (C) 2006 - 2013 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: Hall Of Reflection +SD%Complete: Who knows? :D +SDComment: event script! +SDErrors: They have, but i dont know were it! :D +SDCategory: hall_of_reflection +SDAuthor: MaxXx2021 aka Mioka +EndScriptData */ + +#include "precompiled.h" +#include "halls_of_reflection.h" +#include "escort_ai.h" + +enum +{ + /*INTRO - Pre Uther*/ + SAY_JAINA_INTRO_01 = -1668433, + SAY_SYLVANA_INTRO_01 = -1668434, + SAY_JAINA_INTRO_02 = -1668435, + SAY_JAINA_INTRO_03 = -1668436, + SAY_SYLVANA_INTRO_03 = -1668437, + SAY_JAINA_INTRO_04 = -1668438, + SAY_SYLVANA_INTRO_04 = -1668439, + + /*INTRO - Uther Dialog*/ + SAY_UTHER_A_01 = -1668440, + SAY_UTHER_H_01 = -1668441, + SAY_JAINA_02 = -1668442, + SAY_SYLVANA_02 = -1668443, + SAY_UTHER_A_03 = -1668444, + SAY_UTHER_H_03 = -1668445, + SAY_JAINA_04 = -1668446, + SAY_SYLVANA_04 = -1668447, + SAY_UTHER_A_05 = -1668448, + SAY_UTHER_H_05 = -1668449, + SAY_JAINA_06 = -1668450, + SAY_SYLVANA_06 = -1668451, + SAY_UTHER_A_07 = -1668452, + SAY_UTHER_H_07 = -1668453, + SAY_JAINA_08 = -1668454, + SAY_SYLVANA_08 = -1668455, + SAY_UTHER_A_09 = -1668456, + SAY_UTHER_H_09 = -1668457, + SAY_JAINA_10 = -1668458, + SAY_UTHER_A_11 = -1668459, + SAY_UTHER_H_11 = -1668660, + SAY_JAINA_12 = -1668461, + SAY_SYLVANA_12 = -1668462, + SAY_UTHER_A_13 = -1668463, + SAY_UTHER_A_14 = -1668464, + SAY_JAINA_15 = -1668465, + + /*INTRO - Lich King Arrive*/ + SAY_UTHER_A_16 = -1668466, + SAY_UTHER_H_16 = -1668467, + SAY_LICH_KING_17 = -1668468, + SAY_LICH_KING_18 = -1668469, + SAY_LICH_KING_19 = -1668470, + SAY_JAINA_20 = -1668471, + SAY_SYLVANA_20 = -1668472, + SAY_LICH_KING_A_21 = -1668473, + SAY_LICH_KING_H_21 = -1668474, + SAY_FALRIC_INTRO = -1668475, + SAY_MARWYN_INTRO = -1668476, + SAY_FALRIC_INTRO2 = -1668505, + + /*INTRO - Pre Escape*/ + SAY_LICH_KING_AGGRO_A = -1668477, + SAY_LICH_KING_AGGRO_H = -1668478, + SAY_JAINA_AGGRO = -1668479, + SAY_SYLVANA_AGGRO = -1668480, + + /*ESCAPE*/ + SAY_JAINA_WALL_01 = -1668487, + SAY_SYLVANA_WALL_01 = -1668488, + SAY_JAINA_WALL_02 = -1668489, + SAY_SYLVANA_WALL_02 = -1668490, + SAY_LICH_KING_WALL_02 = -1668491, + SAY_LICH_KING_WALL_03 = -1668492, + SAY_LICH_KING_WALL_04 = -1668493, + SAY_JAINA_WALL_03 = -1668494, + SAY_JAINA_WALL_04 = -1668495, + SAY_SYLVANA_WALL_03 = -1668496, + SAY_SYLVANA_WALL_04 = -1668497, + SAY_JAINA_ESCAPE_01 = -1668498, + SAY_JAINA_ESCAPE_02 = -1668499, + SAY_SYLVANA_ESCAPE_01 = -1668500, + SAY_SYLVANA_ESCAPE_02 = -1668501, + SAY_JAINA_TRAP = -1668502, + SAY_SYLVANA_TRAP = -1668503, + SAY_LICH_KING_END_01 = -1668506, + SAY_LICH_KING_END_02 = -1668507, + SAY_LICH_KING_END_03 = -1668508, + + SAY_ESCAPE_01 = -1668531, + SAY_ESCAPE_02 = -1668532, + SAY_ESCAPE_03 = -1668533, + + + /*SPELLS AND VISUAL EFFECTS*/ + SPELL_TAKE_FROSTMOURNE = 72729, + SPELL_FROSTMOURNE_DESPAWN = 72726, + SPELL_FROSTMOURNE_SOUNDS = 70667, + SPELL_CAST_VISUAL = 65633, //Jaina And Sylavana cast this when summon uther. + SPELL_BOSS_SPAWN_AURA = 72712, //Falric and Marwyn + SPELL_UTHER_DESPAWN = 70693, + SPELL_WINTER = 69780, + SPELL_FURY_OF_FROSTMOURNE = 70063, + SPELL_SOUL_REAPER = 73797, + SPELL_RAISE_DEAD = 69818, + SPELL_ICE_PRISON = 69708, + SPELL_DARK_ARROW = 70194, + SPELL_ICE_BARRIER = 69787, + SPELL_DESTROY_ICE_WALL_01 = 69784, //Jaina + SPELL_DESTROY_ICE_WALL_02 = 70224, + SPELL_DESTROY_ICE_WALL_03 = 70225, //Sylvana + SPELL_DESTRUCT_ICE_WALL = 69784, + SPELL_SUMMON_ICE_WALL = 69768, + SPELL_SYLVANA_JUMP = 68339, + SPELL_SYLVANA_STEP = 69087, + SPELL_SILENCE = 69413, + SPELL_LICH_KING_CAST = 57561, + SPELL_FROSTMOURNE_VISUAL = 73220, + SPELL_SHIELD_DISRUPTION = 58291, + + SPELL_ESCAPED_FROM_ARTHAS = 72830, + + FACTION = 2076, +}; + +struct MANGOS_DLL_DECL npc_jaina_and_sylvana_HRintroAI : public ScriptedAI +{ + npc_jaina_and_sylvana_HRintroAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + BSWScriptedInstance* m_pInstance; + + Creature* pUther; + bool Small; + + void Reset() + { + m_creature->SetPhaseMask(65535, true); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + Small = false; + pUther = NULL; + } + + void Event() + { + switch(m_pInstance->GetEvent(m_creature->GetEntry())) + { + case 1: + if (m_pInstance->GetData(TYPE_EVENT) == 2) + Small = true; + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_pInstance->SetNextEvent(2,m_creature->GetEntry(),2000); + break; + case 2: + if(m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_INTRO_01, m_creature); + m_pInstance->SetNextEvent(3,m_creature->GetEntry(),5000); + } + else if(m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_INTRO_01, m_creature); + m_pInstance->SetNextEvent(3,m_creature->GetEntry(),8000); + } + break; + case 3: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_INTRO_02, m_creature); + m_pInstance->SetNextEvent(4,m_creature->GetEntry(),5000); + } + else if(m_creature->GetEntry() == NPC_SYLVANA) + m_pInstance->SetNextEvent(4,m_creature->GetEntry(),500); + break; + case 4: + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(0, 5307.031f, 1997.920f, 709.341f); + m_pInstance->SetNextEvent(5,m_creature->GetEntry(),10000); + break; + case 5: + if(Creature* pTarget = m_creature->SummonCreature(NPC_ALTAR_TARGET,5309.374f,2006.788f,711.615f,1.37f,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,360000)) + { + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTarget->GetObjectGuid()); + pTarget->SetCreatorGuid(ObjectGuid()); + } + m_pInstance->SetNextEvent(6,m_creature->GetEntry(),1000); + break; + case 6: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_INTRO_03, m_creature); + m_pInstance->SetNextEvent(7,m_creature->GetEntry(),5000); + } + if (m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_INTRO_03, m_creature); + m_pInstance->SetNextEvent(7,m_creature->GetEntry(),5000); + } + break; + case 7: + DoCast(m_creature, SPELL_CAST_VISUAL); + if (m_creature->GetEntry() == NPC_JAINA) + DoScriptText(SAY_JAINA_INTRO_04, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA) + DoScriptText(SAY_SYLVANA_INTRO_04, m_creature); + m_pInstance->SetNextEvent(8,m_creature->GetEntry(),3000); + break; + case 8: + DoCast(m_creature, SPELL_FROSTMOURNE_SOUNDS); + if(GameObject* pFrostmourne = m_pInstance->GetSingleGameObjectFromStorage(GO_FROSTMOURNE)) + pFrostmourne->SetGoState(GO_STATE_ACTIVE); + if(m_creature->GetEntry() == NPC_JAINA) + m_pInstance->SetNextEvent(9,m_creature->GetEntry(),12000); + if(m_creature->GetEntry() == NPC_SYLVANA) + m_pInstance->SetNextEvent(9,m_creature->GetEntry(),8000); + break; + case 9: + if (pUther = m_creature->SummonCreature(NPC_UTHER,5308.228f,2003.641f,709.341f,4.17f,TEMPSUMMON_MANUAL_DESPAWN,360000)) + { + pUther->SetCreatorGuid(ObjectGuid()); + pUther->SetRespawnDelay(DAY); + pUther->SetGuidValue(UNIT_FIELD_TARGET, m_creature->GetObjectGuid()); + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pUther->GetObjectGuid()); + if (m_creature->GetEntry() == NPC_JAINA && pUther) + { + DoScriptText(SAY_UTHER_A_01, pUther); + m_pInstance->SetNextEvent(10,m_creature->GetEntry(),3000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_UTHER_H_01, pUther); + m_pInstance->SetNextEvent(10,m_creature->GetEntry(),10000); + } + } + break; + case 10: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_02, m_creature); + m_pInstance->SetNextEvent(11,m_creature->GetEntry(),5000); + } + else if(m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_02, m_creature); + m_pInstance->SetNextEvent(11,m_creature->GetEntry(),3000); + } + break; + case 11: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_03, pUther); + m_pInstance->SetNextEvent(Small ? 24 : 12, m_creature->GetEntry(),7000); + } + else if ((m_creature->GetEntry() == NPC_SYLVANA) && pUther) + { + DoScriptText(SAY_UTHER_H_03, pUther); + m_pInstance->SetNextEvent(Small ? 24 : 12, m_creature->GetEntry(),6000); + } + break; + case 12: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_04, m_creature); + m_pInstance->SetNextEvent(13,m_creature->GetEntry(),2000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_04, m_creature); + m_pInstance->SetNextEvent(13,m_creature->GetEntry(),5000); + } + break; + case 13: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_05, pUther); + m_pInstance->SetNextEvent(14,m_creature->GetEntry(),10000); + } + else if ((m_creature->GetEntry() == NPC_SYLVANA) && pUther) + { + DoScriptText(SAY_UTHER_H_05, pUther); + m_pInstance->SetNextEvent(14,m_creature->GetEntry(),19000); + } + break; + case 14: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_06, m_creature); + m_pInstance->SetNextEvent(15,m_creature->GetEntry(),6000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_06, m_creature); + m_pInstance->SetNextEvent(15,m_creature->GetEntry(),2000); + } + break; + case 15: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_07, pUther); + m_pInstance->SetNextEvent(16,m_creature->GetEntry(),12000); + } + else if ((m_creature->GetEntry() == NPC_SYLVANA) && pUther) + { + DoScriptText(SAY_UTHER_H_07, pUther); + m_pInstance->SetNextEvent(16,m_creature->GetEntry(),6000); + } + break; + case 16: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_08, m_creature); + m_pInstance->SetNextEvent(17,m_creature->GetEntry(),6000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_08, m_creature); + m_pInstance->SetNextEvent(17,m_creature->GetEntry(),3000); + } + break; + case 17: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_09, pUther); + m_pInstance->SetNextEvent(18,m_creature->GetEntry(),12000); + } + else if ((m_creature->GetEntry() == NPC_SYLVANA) && pUther) + { + DoScriptText(SAY_UTHER_H_09, pUther); + m_pInstance->SetNextEvent(18,m_creature->GetEntry(),11000); + } + break; + case 18: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_10, m_creature); + m_pInstance->SetNextEvent(19,m_creature->GetEntry(),12000); + } + else if(m_creature->GetEntry() == NPC_SYLVANA) + { + m_pInstance->SetNextEvent(19,m_creature->GetEntry(),500); + } + break; + case 19: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_11, pUther); + m_pInstance->SetNextEvent(20,m_creature->GetEntry(),24000); + } + else if ((m_creature->GetEntry() == NPC_SYLVANA) && pUther) + { + DoScriptText(SAY_UTHER_H_11, pUther); + m_pInstance->SetNextEvent(20,m_creature->GetEntry(),9000); + } + break; + case 20: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_12, m_creature); + m_pInstance->SetNextEvent(21,m_creature->GetEntry(),2000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + DoScriptText(SAY_SYLVANA_12, m_creature); + m_pInstance->SetNextEvent(21,m_creature->GetEntry(),2100); + } + break; + case 21: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_13, pUther); + m_pInstance->SetNextEvent(22,m_creature->GetEntry(),5000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + m_pInstance->SetNextEvent(22,m_creature->GetEntry(),500); + } + break; + case 22: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + { + DoScriptText(SAY_UTHER_A_14, pUther); + m_pInstance->SetNextEvent(23,m_creature->GetEntry(),12000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + m_pInstance->SetNextEvent(23,m_creature->GetEntry(),500); + } + break; + case 23: + if (m_creature->GetEntry() == NPC_JAINA) + { + DoScriptText(SAY_JAINA_15, m_creature); + m_pInstance->SetNextEvent(24,m_creature->GetEntry(),2000); + } + else if (m_creature->GetEntry() == NPC_SYLVANA) + { + m_pInstance->SetNextEvent(24,m_creature->GetEntry(),500); + } + break; + case 24: + if ((m_creature->GetEntry() == NPC_JAINA) && pUther) + DoScriptText(SAY_UTHER_A_16, pUther); + else if ((m_creature->GetEntry() == NPC_SYLVANA) && pUther) + DoScriptText(SAY_UTHER_H_16, pUther); + if(Creature* LichKing = m_creature->SummonCreature(NPC_LICH_KING,5362.469f,2062.342f,707.695f,3.97f,TEMPSUMMON_MANUAL_DESPAWN,0,true)) + { + LichKing->SetRespawnDelay(DAY); + LichKing->SetCreatorGuid(ObjectGuid()); + } + m_pInstance->SetNextEvent(24,NPC_LICH_KING,2000); + break; + case 25: + if (pUther) + pUther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); + m_pInstance->SetNextEvent(25,NPC_LICH_KING,2000); + break; + case 31: + m_creature->RemoveAurasDueToSpell(SPELL_FROSTMOURNE_SOUNDS); + m_pInstance->SetNextEvent(32,NPC_LICH_KING,4500); + break; + case 36: + if (m_creature->GetEntry() == NPC_JAINA) + DoScriptText(SAY_JAINA_20, m_creature); + else if(m_creature->GetEntry() == NPC_SYLVANA) + DoScriptText(SAY_SYLVANA_20, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, 5443.880f, 2147.095f, 707.695f); + m_pInstance->SetNextEvent(37,NPC_LICH_KING,4000); + break; + case 39: + m_pInstance->SetNextEvent(40,NPC_LICH_KING,1000); + m_creature->ForcedDespawn(1000); + if (pUther && pUther->IsInWorld()) + pUther->ForcedDespawn(); + break; + default: + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if (m_pInstance->GetEventTimer(m_creature->GetEntry(),diff) && m_pInstance->GetData(TYPE_PHASE) == 1) + Event(); + + return; + } +}; + +bool GossipHello_npc_jaina_and_sylvana_HRintro(Player* pPlayer, Creature* pCreature) +{ + BSWScriptedInstance* m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + + if(pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu( pCreature->GetObjectGuid()); + + switch(pCreature->GetEntry()) + { + case NPC_JAINA: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, -3594536, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, -3594537, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + break; + case NPC_SYLVANA: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, -3594538, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, -3594539, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + break; + } + + pPlayer->PlayerTalkClass->SendGossipMenu(907,pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_jaina_and_sylvana_HRintro(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + BSWScriptedInstance* m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + + if (!m_pInstance) return false; + + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->CLOSE_GOSSIP_MENU(); + m_pInstance->SetData(TYPE_EVENT, 1); + m_pInstance->SetData(TYPE_PHASE, 1); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->CLOSE_GOSSIP_MENU(); + m_pInstance->SetData(TYPE_EVENT, 2); + m_pInstance->SetData(TYPE_PHASE, 1); + break; + } + + m_pInstance->SetNextEvent(1, pCreature->GetEntry(), 500); + + m_pInstance->SetData(DATA_ESCAPE_LIDER,pCreature->GetEntry()); + + return true; +} + +struct MANGOS_DLL_DECL npc_jaina_and_sylvana_HRextroAI : public npc_escortAI +{ + npc_jaina_and_sylvana_HRextroAI(Creature *pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + BSWScriptedInstance* m_pInstance; + + uint32 CastTimer; + uint32 HoldTimer; + uint8 m_wallNum; + bool Fight; + ObjectGuid wallTarget; + uint32 m_chestID; + + void Reset() + { + if(!m_pInstance) return; + + if(m_pInstance->GetData(TYPE_LICH_KING) == IN_PROGRESS) return; + + HoldTimer = 10000; + Fight = true; + m_wallNum = 0; + wallTarget = ObjectGuid(); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + m_creature->CastSpell(m_creature, SPELL_ICE_BARRIER, false); + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + { + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2HL); + } + + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->GetEntry() != NPC_SYLVANA_OUTRO) + return; + + if (m_pInstance->GetData(TYPE_LICH_KING) == IN_PROGRESS || Fight != true) + return; + + npc_escortAI::AttackStart(who); + + } + + void JustDied(Unit* pKiller) override + { + if(!m_pInstance) + return; + DoDestructWall(); + } + + void DoSummonWall(uint8 wallNum) + { + if(!m_pInstance || wallNum > 3) + return; + + m_wallNum = wallNum+1; + HoldTimer = 20000; + + switch (wallNum) + { + case 0: m_pInstance->SetNextEvent(200,BOSS_LICH_KING,500); break; + case 1: m_pInstance->SetNextEvent(300,BOSS_LICH_KING,500); break; + case 2: m_pInstance->SetNextEvent(400,BOSS_LICH_KING,500); break; + case 3: m_pInstance->SetNextEvent(500,BOSS_LICH_KING,500); break; + default: + break; + } + + if (Creature* pWallTarget = m_creature->SummonCreature(NPC_ICE_WALL,WallLoc[wallNum].x,WallLoc[wallNum].y,WallLoc[wallNum].z,WallLoc[wallNum].o,TEMPSUMMON_MANUAL_DESPAWN,0, true)) + { + pWallTarget->SetPhaseMask(65535, true); + pWallTarget->setFaction(114); + pWallTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pWallTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + wallTarget = pWallTarget->GetObjectGuid(); + pWallTarget->CastSpell(pWallTarget, SPELL_SUMMON_ICE_WALL, false); + } + } + + void DoDestructWall() + { + m_pInstance->DoOpenDoor(GO_ICE_WALL); + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + { + pWallTarget->ForcedDespawn(); + } + wallTarget = ObjectGuid(); + m_wallNum = 0; + } + + void WaypointReached(uint32 i) override + { + switch(i) + { + case 0: + break; + case 1: + break; + case 2: + DoSummonWall(0); + break; + case 3: + break; + case 4: + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_WALL_01, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_WALL_01, m_creature); + CastTimer = 1000; + SetEscortPaused(true); + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_01, false); + } + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_02, false); + } + break; + case 5: + break; + case 6: + DoSummonWall(1); + break; + case 7: + break; + case 8: + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_WALL_02, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_WALL_02, m_creature); + CastTimer = 1000; + SetEscortPaused(true); + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_01, false); + } + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_02, false); + } + break; + case 9: + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_ESCAPE_01, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_ESCAPE_01, m_creature); + DoSummonWall(2); + break; + case 10: + break; + case 11: + break; + case 12: + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_WALL_03, m_creature); + if(m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_WALL_03, m_creature); + CastTimer = 1000; + SetEscortPaused(true); + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_01, false); + } + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_02, false); + } + break; + case 13: + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_ESCAPE_02, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_ESCAPE_02, m_creature); + break; + case 14: + break; + case 15: + DoSummonWall(3); + break; + case 16: + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_WALL_04, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_WALL_04, m_creature); + CastTimer = 1000; + SetEscortPaused(true); + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_01, false); + } + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_02, false); + } + break; + case 17: + break; + case 18: + break; + case 19: + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + DoScriptText(SAY_JAINA_TRAP, m_creature); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + DoScriptText(SAY_SYLVANA_TRAP, m_creature); + break; + case 20: + SetEscortPaused(true); + if (m_creature->GetEntry() == NPC_JAINA_OUTRO) + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2HL); + else if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H); + break; + default: + break; + } + } + + void Intro() + { + switch(m_pInstance->GetEvent(m_creature->GetEntry())) + { + case 100: + m_creature->SetWalk(false); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + { + if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + AttackStart(pLichKing); + } + m_pInstance->SetNextEvent(101,BOSS_LICH_KING,500); + break; + case 102: + if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + Fight = false; + m_creature->GetMotionMaster()->MovePoint(0, (m_creature->GetPositionX()-5)+rand()%10, (m_creature->GetPositionY()-5)+rand()%10, m_creature->GetPositionZ()); + m_pInstance->SetNextEvent(103,m_creature->GetEntry(),3000); + } + else + m_pInstance->SetNextEvent(103,m_creature->GetEntry(),500); + break; + case 103: + if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + Fight = true; + m_pInstance->SetNextEvent(104,m_creature->GetEntry(),500); + break; + case 104: + if(m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + m_creature->CastSpell(pLichKing, SPELL_SYLVANA_STEP, false); + m_pInstance->SetNextEvent(105,m_creature->GetEntry(),3000); + } + else + m_pInstance->SetNextEvent(105,m_creature->GetEntry(),500); + break; + case 105: + if(m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + Fight = false; + m_creature->GetMotionMaster()->MovePoint(0, (m_creature->GetPositionX()-5)+rand()%10, (m_creature->GetPositionY()-5)+rand()%10, m_creature->GetPositionZ()); + m_pInstance->SetNextEvent(106,m_creature->GetEntry(),3000); + } + else + m_pInstance->SetNextEvent(106,m_creature->GetEntry(),12000); + break; + case 106: + Fight = true; + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + m_creature->CastSpell(pLichKing,(m_creature->GetEntry() == NPC_JAINA_OUTRO ? SPELL_ICE_PRISON : SPELL_DARK_ARROW),true); + m_pInstance->SetNextEvent(107,m_creature->GetEntry(),2500); + break; + case 107: + m_creature->RemoveAurasDueToSpell(SPELL_ICE_BARRIER); + if(m_creature->GetEntry() == NPC_JAINA_OUTRO) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + if (!pLichKing->HasAura(SPELL_ICE_PRISON)) + pLichKing->CastSpell(pLichKing,SPELL_ICE_PRISON,true); + DoScriptText(SAY_JAINA_AGGRO, m_creature); + } + else if(m_creature->GetEntry() == NPC_SYLVANA_OUTRO) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + if (!pLichKing->HasAura(SPELL_DARK_ARROW)) + pLichKing->CastSpell(pLichKing,SPELL_DARK_ARROW,true); + DoScriptText(SAY_SYLVANA_AGGRO, m_creature); + } + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + m_creature->AttackStop(); + m_pInstance->SetNextEvent(108,m_creature->GetEntry(),3000); + break; + case 108: + m_creature->GetMotionMaster()->MovePoint(0, 5577.187f, 2236.003f, 733.012f); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pLichKing->GetObjectGuid()); + m_pInstance->SetNextEvent(109,m_creature->GetEntry(),10000); + break; + case 109: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); +// Count = 1; + m_pInstance->SetNextEvent(110,m_creature->GetEntry(),10000); + break; + } + } + + void Outro() + { + switch(m_pInstance->GetEvent(m_creature->GetEntry())) + { + case 610: + m_creature->CastSpell(m_creature, SPELL_SHIELD_DISRUPTION,false); + m_pInstance->SetData(DATA_ESCAPE_LIDER,m_creature->GetEntry()); + m_creature->SummonGameobject(GO_CAVE, 5275.28f, 1694.23f, 786.147f, 0.981225f, 0); + m_pInstance->SetNextEvent(611,m_creature->GetEntry(),6000); + break; + case 611: + if (GameObject* pCave = m_pInstance->GetSingleGameObjectFromStorage(GO_CAVE)) + pCave->SetGoState(GO_STATE_READY); + m_creature->RemoveAurasDueToSpell(SPELL_SILENCE); + m_creature->SetLevitate(false); + m_creature->CastSpell(m_creature, SPELL_SHIELD_DISRUPTION,false); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(0, 5258.911328f,1652.112f,784.295166f); + DoScriptText(SAY_ESCAPE_01, m_creature); + m_pInstance->SetNextEvent(612,m_creature->GetEntry(),10000); + break; + case 612: + m_creature->CastSpell(m_creature,SPELL_ESCAPED_FROM_ARTHAS,false); + m_pInstance->SetData(TYPE_LICH_KING, DONE); + DoScriptText(SAY_ESCAPE_02, m_creature); + m_pInstance->SetNextEvent(613,m_creature->GetEntry(),10000); + break; + case 613: + DoScriptText(SAY_ESCAPE_03, m_creature); + m_pInstance->SetNextEvent(614,m_creature->GetEntry(),10000); + break; + case 614: + m_creature->GetMotionMaster()->MovePoint(0, 5240.66f, 1646.93f, 784.302f); + m_pInstance->SetNextEvent(615,m_creature->GetEntry(),5000); + break; + case 615: + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + m_creature->SetOrientation(0.68f); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_pInstance->SetNextEvent(616,m_creature->GetEntry(),5000); + break; + } + } + + void UpdateEscortAI(const uint32 diff) + { + if(!m_pInstance || m_pInstance->GetData(TYPE_PHASE) < 4) + return; + + if (m_pInstance->GetData(TYPE_PHASE) == 6 && m_pInstance->GetEventTimer(m_creature->GetEntry(),diff)) + { + Outro(); + return; + } + + DoMeleeAttackIfReady(); + + if (m_pInstance->GetData(TYPE_PHASE) == 4 && m_pInstance->GetEventTimer(m_creature->GetEntry(),diff)) + { + Intro(); + return; + } + + if (m_creature->GetEntry() == NPC_SYLVANA_OUTRO && !wallTarget.IsEmpty() && m_wallNum && CastTimer < diff) + { + if (Creature* pWallTarget = m_creature->GetMap()->GetCreature(wallTarget)) + m_creature->CastSpell(pWallTarget, SPELL_DESTROY_ICE_WALL_03, false); + CastTimer = 1000; + } + else + CastTimer -= diff; + + if (!wallTarget.IsEmpty() && m_wallNum && m_pInstance->GetData(DATA_SUMMONS) == 0 && HoldTimer < 1000) + { + m_creature->InterruptNonMeleeSpells(false); + SetEscortPaused(false); + + switch(m_wallNum) + { + case 1: + DoDestructWall(); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + DoScriptText(SAY_LICH_KING_WALL_02, pLichKing); + break; + case 2: + DoDestructWall(); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + DoScriptText(SAY_LICH_KING_WALL_03, pLichKing); + break; + case 3: + DoDestructWall(); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + DoScriptText(SAY_LICH_KING_WALL_04, pLichKing); + break; + case 4: + DoDestructWall(); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(BOSS_LICH_KING)) + { + pLichKing->RemoveAurasDueToSpell(SPELL_WINTER); + pLichKing->SetSpeedRate(MOVE_WALK, 2.5f, true); + } + break; + } + HoldTimer = 10000; + } + else + { + if (HoldTimer <= diff) + HoldTimer = 0; + else + HoldTimer -= diff; + } + } +}; + +bool GossipHello_npc_jaina_and_sylvana_HRextro(Player* pPlayer, Creature* pCreature) +{ + + ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if(!m_pInstance) return false; + + if(m_pInstance->GetData(TYPE_LICH_KING) == DONE) return false; + + if(pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu( pCreature->GetObjectGuid()); + + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, -3594540, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_jaina_and_sylvana_HRextro(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->CLOSE_GOSSIP_MENU(); + ((npc_jaina_and_sylvana_HRextroAI*)pCreature->AI())->Start(true); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pCreature->SetUInt64Value(UNIT_FIELD_TARGET, 0); + + if(m_pInstance) + { + m_pInstance->SetData(DATA_ESCAPE_LIDER, pCreature->GetEntry()); + m_pInstance->SetData(TYPE_LICH_KING, IN_PROGRESS); + m_pInstance->SetData(TYPE_PHASE, 5); + } + return true; + break; + default: return false; + } +} + +CreatureAI* GetAI_npc_jaina_and_sylvana_HRintro(Creature* pCreature) +{ + return new npc_jaina_and_sylvana_HRintroAI(pCreature); +} + +CreatureAI* GetAI_npc_jaina_and_sylvana_HRextro(Creature* pCreature) +{ + return new npc_jaina_and_sylvana_HRextroAI(pCreature); +} + +enum GENERAL_EVENT +{ + SAY_AGGRO = -1594519, + SAY_DEATH = -1594520, + + SPELL_SHIELD_THROWN = 69222, +}; + +struct MANGOS_DLL_DECL npc_frostworn_generalAI : public ScriptedAI +{ + npc_frostworn_generalAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShieldTimer; + + void Reset() + { + if (!m_pInstance) + return; + m_uiShieldTimer = 5000; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + DoScriptText(SAY_DEATH, m_creature); + m_pInstance->SetData(TYPE_FROST_GENERAL, DONE); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_creature->getVictim()) + return; + + if (pWho->GetTypeId() != TYPEID_PLAYER + || m_pInstance->GetData(TYPE_MARWYN) != DONE + || !m_creature->IsWithinDistInMap(pWho, 30.0f) + ) return; + + if (Player* pPlayer = (Player*)pWho) + if (pPlayer->isGameMaster()) return; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + AttackStart(pWho); + } + + void Aggro(Unit* pVictim) + { + if (!m_pInstance) + return; + DoScriptText(SAY_AGGRO, m_creature); + m_pInstance->SetData(TYPE_FROST_GENERAL, IN_PROGRESS); + + Map::PlayerList const &pList = m_creature->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = pList.begin(); i != pList.end(); ++i) + { + if (Player* pPlayer = i->getSource()) + { + if (pPlayer && pPlayer->isAlive() && pPlayer->IsInMap(m_creature)) + { + if (Creature* pMirror = m_creature->SummonCreature(NPC_SPIRITUAL_REFLECTION,0,0,0,0,TEMPSUMMON_DEAD_DESPAWN,0, true)) + { + pMirror->SetPhaseMask(65535, true); + pMirror->SetInCombatWith(pPlayer); + pMirror->AddThreat(pPlayer, 1000.0f); + } + + } + } + }; + + } + + void UpdateAI(const uint32 uiDiff) override + { + if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_uiShieldTimer < uiDiff) + { + if(Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget,SPELL_SHIELD_THROWN); + m_uiShieldTimer = urand(4000, 8000); + } + else m_uiShieldTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_frostworn_general(Creature* pCreature) +{ + return new npc_frostworn_generalAI(pCreature); +} + +enum spiritual_reflection +{ + SPELL_REFLECTION_GHOST = 69861, + SPELL_CLONE = 69828, + SPELL_CLONE2 = 69837, + + SPELL_BALEFUL_STRIKE = 69933, + SPELL_SPIRIT_BURST = 69900, + +}; + +struct MANGOS_DLL_DECL npc_spiritual_reflectionAI : public BSWScriptedAI +{ + npc_spiritual_reflectionAI(Creature *pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool isMirror; + ObjectGuid victimGuid; + + void Reset() + { + if (!m_pInstance) + return; + isMirror = false; + victimGuid = ObjectGuid(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void Aggro(Unit* pVictim) + { + if (!m_pInstance || !pVictim || pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (victimGuid.IsEmpty()) + victimGuid = pVictim->GetObjectGuid(); + + DoStartMovement(pVictim); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!m_pInstance || !m_creature ) + return; + + if (uiDamage >= m_creature->GetHealth()) + doCast(SPELL_SPIRIT_BURST); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_FROST_GENERAL) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!isMirror) + { + if (Unit* pVictim = m_creature->GetMap()->GetUnit(victimGuid)) + if (m_creature->IsWithinDistInMap(pVictim, 5.0f)) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pVictim->CastSpell(m_creature, SPELL_CLONE, true); + pVictim->CastSpell(m_creature, SPELL_CLONE2, true); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, pVictim->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID)); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID+1, pVictim->GetUInt32Value(PLAYER_VISIBLE_ITEM_17_ENTRYID)); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID+2, pVictim->GetUInt32Value(PLAYER_VISIBLE_ITEM_18_ENTRYID)); + pVictim->CastSpell(m_creature, SPELL_REFLECTION_GHOST, true); + isMirror = true; + } + } + + if (!isMirror) + return; + + timedCast(SPELL_BALEFUL_STRIKE,uiDiff); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_spiritual_reflection(Creature* pCreature) +{ + return new npc_spiritual_reflectionAI(pCreature); +} + +struct MANGOS_DLL_DECL npc_queldelar_horAI : public ScriptedAI +{ + npc_queldelar_horAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (BSWScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + BSWScriptedInstance* m_pInstance; + bool intro; + Team team; + uint32 newLeader; + + void Reset() + { + intro = false; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance || intro) + return; + + if (!pWho || pWho->GetTypeId() != TYPEID_PLAYER || !pWho->IsWithinDistInMap(m_creature, 22.0f)) + return; + + debug_log("HOR event started"); + + intro = true; + + if (m_pInstance->GetData(TYPE_LICH_KING) == DONE) + return; + else if (m_pInstance->GetData(TYPE_FROST_GENERAL) == DONE) + { + m_pInstance->DoOpenDoor(GO_IMPENETRABLE_DOOR); + m_pInstance->DoOpenDoor(GO_ICECROWN_DOOR_2); + m_pInstance->SetData(TYPE_PHASE, 3); + return; + } + else if (m_pInstance->GetData(TYPE_MARWYN) == DONE) + { + m_pInstance->DoOpenDoor(GO_IMPENETRABLE_DOOR); + return; + } + else if (m_pInstance->GetData(TYPE_FALRIC) == DONE) + { + if (Creature* pMarwyn = m_pInstance->GetSingleCreatureFromStorage(NPC_MARWYN)) + { + pMarwyn->SetVisibility(VISIBILITY_ON); + pMarwyn->CastSpell(pMarwyn, SPELL_BOSS_SPAWN_AURA, false); + m_pInstance->SetData(TYPE_EVENT, 7); + m_pInstance->SetData(TYPE_MARWYN, SPECIAL); + } + return; + } + + + if (Group* pGroup = ((Player*)pWho)->GetGroup()) + { + ObjectGuid LeaderGuid = pGroup->GetLeaderGuid(); + if (!LeaderGuid.IsEmpty()) + if (Player* pLeader =m_creature->GetMap()->GetPlayer(LeaderGuid)) + team = pLeader->GetTeam(); + } + else + team = ((Player*)pWho)->GetTeam(); + + + if (team == ALLIANCE) + newLeader = NPC_JAINA; + else + newLeader = NPC_SYLVANA; + + debug_log("HOR event: team %u, leader %u ",team,newLeader); + + if (Creature* pNewLeader = m_creature->SummonCreature(newLeader,WallLoc[4].x,WallLoc[4].y,WallLoc[4].z,WallLoc[4].o,TEMPSUMMON_MANUAL_DESPAWN,0,true)) + { + pNewLeader->SetCreatorGuid(ObjectGuid()); + pNewLeader->setFaction(35); + pNewLeader->SetPhaseMask(65535, true); + pNewLeader->GetMotionMaster()->MovePoint(0, WallLoc[5].x,WallLoc[5].y,WallLoc[5].z); + pNewLeader->SetWalk(false); + pNewLeader->SetSpeedRate(MOVE_RUN, 1.0f, true); + pNewLeader->SetRespawnDelay(DAY); + } +// m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, 63135); + } + + void AttackStart(Unit* who) + { + return; + } + + void UpdateAI(const uint32 diff) + { + } +}; +CreatureAI* GetAI_npc_queldelar_hor(Creature* pCreature) +{ + return new npc_queldelar_horAI(pCreature); +} + + +void AddSC_halls_of_reflection() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_jaina_and_sylvana_HRintro"; + newscript->GetAI = &GetAI_npc_jaina_and_sylvana_HRintro; + newscript->pGossipHello = &GossipHello_npc_jaina_and_sylvana_HRintro; + newscript->pGossipSelect = &GossipSelect_npc_jaina_and_sylvana_HRintro; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_jaina_and_sylvana_HRextro"; + newscript->GetAI = &GetAI_npc_jaina_and_sylvana_HRextro; + newscript->pGossipHello = &GossipHello_npc_jaina_and_sylvana_HRextro; + newscript->pGossipSelect = &GossipSelect_npc_jaina_and_sylvana_HRextro; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_frostworn_general"; + newscript->GetAI = &GetAI_npc_frostworn_general; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_spiritual_reflection"; + newscript->GetAI = &GetAI_npc_spiritual_reflection; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_queldelar_hor"; + newscript->GetAI = &GetAI_npc_queldelar_hor; + newscript->RegisterSelf(); +} 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 new file mode 100644 index 0000000000..751d707a74 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.h @@ -0,0 +1,135 @@ +/* Copyright (C) 2006 - 2013 MaXx2021 && /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_HALL_OF_REFLECTION_H +#define DEF_HALL_OF_REFLECTION_H +#include "BSW_ai.h" +#include "BSW_instance.h" + +enum Data +{ + TYPE_PHASE = 0, + TYPE_EVENT = 1, + TYPE_FALRIC = 2, + TYPE_MARWYN = 3, + TYPE_FROST_GENERAL = 4, + TYPE_LICH_KING = 5, + TYPE_HALLS = 6, + MAX_ENCOUNTERS, + + DATA_ESCAPE_LIDER = 101, + DATA_SUMMONS = 102, + DATA_WAVE_COUNT = 103, + + /*UNITS*/ + NPC_DARK_1 = 38177, //Shadowy Mercenary + NPC_DARK_2 = 38176, //Tortured Rifleman + NPC_DARK_3 = 38173, //Spectral Footman + NPC_DARK_4 = 38172, //Phantom Mage + NPC_DARK_5 = 38567, //Phantom Hallucination + NPC_DARK_6 = 38175, //Ghostly Priest + NPC_JAINA = 37221, + NPC_SYLVANA = 37223, + NPC_JAINA_OUTRO = 36955, + NPC_SYLVANA_OUTRO = 37554, + NPC_ALTAR_TARGET = 37704, + NPC_UTHER = 37225, + NPC_LICH_KING = 36954, + BOSS_LICH_KING = 37226, + NPC_ICE_WALL = 37014, + NPC_FALRIC = 38112, + NPC_MARWYN = 38113, + NPC_GHOSTLY_ROGUE = 38177, + NPC_GHOSTLY_PRIEST = 38175, + NPC_GHOSTLY_MAGE = 38172, + NPC_GHOSTLY_FOOTMAN = 38173, + NPC_GHOSTLY_RIFLEMAN = 38176, + NPC_GLUK = 38567, + + NPC_RAGING_GNOUL = 36940, + NPC_RISEN_WITCH_DOCTOR = 36941, + NPC_ABON = 37069, + + NPC_FROST_GENERAL = 36723, + NPC_SPIRITUAL_REFLECTION = 37068, + +// NPC_QUEL_DELAR = 37704, + NPC_QUEL_DELAR = 37158, + + GO_ICECROWN_DOOR = 201976, //72802 + GO_ICECROWN_DOOR_2 = 197342, + GO_ICECROWN_DOOR_3 = 197343, + GO_IMPENETRABLE_DOOR = 197341, //72801 + GO_FROSTMOURNE_ALTAR = 202236, //3551 + GO_FROSTMOURNE = 202302, //364 + + GO_ICE_WALL = 201385, + GO_CAVE = 201596, + GO_PORTAL = 202079, + + GO_CAPTAIN_CHEST_1 = 202212, //3145 + GO_CAPTAIN_CHEST_2 = 201710, //30357 + GO_CAPTAIN_CHEST_3 = 202337, //3246 + GO_CAPTAIN_CHEST_4 = 202336, //3333 +}; + +static LOCATION SpawnLoc[]= +{ + //Wing 01 + {5277.409f, 1993.161f, 707.694f, 0.05f}, //27 + {5301.876f, 2041.699f, 707.694f, 4.71f}, //1 + {5339.830f, 2020.887f, 707.694f, 3.14f}, //13 + {5311.041f, 2042.935f, 707.694f, 4.71f}, //3 + {5314.750f, 2039.969f, 707.694f, 4.71f}, //4 + {5342.823f, 2003.801f, 707.694f, 3.14f}, //10 + {5311.579f, 1972.823f, 707.694f, 1.62f}, //16 + + //Wing 02 + {5272.491f, 2005.673f, 707.694f, 0.05f}, //23 + {5302.669f, 1973.050f, 707.694f, 1.62f}, //18 + {5346.187f, 2008.058f, 707.694f, 3.14f}, //9 + {5319.752f, 2041.321f, 707.694f, 4.71f}, //5 + {5344.882f, 1998.714f, 707.694f, 3.14f}, //11 + {5340.552f, 1994.735f, 707.694f, 3.14f}, //12 + {5306.441f, 2040.358f, 707.694f, 4.71f}, //2 + + //Wing 03 + {5273.297f, 2014.009f, 707.694f, 0.05f}, //25 + {5316.062f, 1970.777f, 707.694f, 1.62f}, //15 + {5322.498f, 2037.415f, 707.694f, 4.71f}, //6 + {5307.087f, 1970.065f, 707.694f, 1.62f}, //17 + {5342.460f, 2012.391f, 707.694f, 3.14f}, //8 + {5297.601f, 1971.420f, 707.694f, 1.62f}, //19 + {5295.668f, 1975.853f, 707.694f, 1.62f}, //20 + + //Wing 04 + {5273.661f, 1996.767f, 707.694f, 0.05f}, //21 + {5275.228f, 2001.275f, 707.694f, 0.05f}, //22 + {5344.153f, 2017.753f, 707.694f, 3.14f}, //7 + {5275.310f, 2009.686f, 707.694f, 0.05f}, //24 + {5319.835f, 1975.177f, 707.694f, 1.62f}, //14 + {5277.445f, 2017.197f, 707.694f, 0.05f}, //26 + {5298.198f, 2037.762f, 707.694f, 4.71f} //0 +}; + + +static LOCATION WallLoc[]= +{ + {5540.39f, 2086.48f, 731.066f, 1.00057f}, + {5494.3f, 1978.27f, 736.689f, 1.0885f}, + {5434.27f, 1881.12f, 751.303f, 0.923328f}, + {5323.61f, 1755.85f, 770.305f, 0.784186f}, + {5239.01f, 1932.64f, 707.695f, 0.8f}, // Spawn point for Jaina && Silvana intro + {5266.779785f, 1953.42f, 707.697f, 1.0f}, + {5547.27002f, 2256.949951f, 733.010986f, 0.9f}, // Spawn point for Jaina && Silvana outro +}; + + +enum HallsOfReflectionWorldStates +{ + WORLD_STATE_HOR = 4884, + WORLD_STATE_HOR_WAVE_COUNT = 4882, +}; + +#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 new file mode 100644 index 0000000000..dd8c0b32f8 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp @@ -0,0 +1,264 @@ +/* Copyright (C) 2006 - 2013 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: instance_halls_of_reflection +SD%Complete: 70% +SDComment: +SDErrors: +SDCategory: instance script +SDAuthor: /dev/rsa, modified by MaxXx2021 aka Mioka +EndScriptData */ + +#include "precompiled.h" +#include "halls_of_reflection.h" +#include "World.h" + +struct MANGOS_DLL_DECL instance_halls_of_reflection : public BSWScriptedInstance +{ + instance_halls_of_reflection(Map* pMap) : BSWScriptedInstance(pMap) + { + Difficulty = pMap->GetDifficulty(); + Initialize(); + } + + uint32 m_auiEncounter[MAX_ENCOUNTERS+1]; + std::string strSaveData; + + uint8 Difficulty; + uint8 m_uiSummons; + uint8 m_waveCount; + + uint32 m_auiLeader; + + ObjectGuid m_uiCaptainsChestHordeGUID; + ObjectGuid m_uiCaptainsChestAllianceGUID; + + void Initialize() override + { + for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + m_auiEncounter[i] = NOT_STARTED; + m_waveCount = 0; + } + + void OnCreatureCreate(Creature* pCreature) override + { + switch(pCreature->GetEntry()) + { + case NPC_JAINA: + case NPC_SYLVANA: + case NPC_JAINA_OUTRO: + case NPC_SYLVANA_OUTRO: + case NPC_ALTAR_TARGET: + case NPC_LICH_KING: + case NPC_FALRIC: + case NPC_MARWYN: + case BOSS_LICH_KING: + case NPC_FROST_GENERAL: + case NPC_QUEL_DELAR: + case NPC_UTHER: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } + } + + void OnObjectCreate(GameObject* pGo) override + { + switch(pGo->GetEntry()) + { + case GO_IMPENETRABLE_DOOR: if (GetData(TYPE_MARWYN) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ICECROWN_DOOR_2: if (GetData(TYPE_FROST_GENERAL) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_CAPTAIN_CHEST_1: + if (Difficulty == RAID_DIFFICULTY_10MAN_NORMAL) + m_uiCaptainsChestHordeGUID = pGo->GetObjectGuid(); + break; + case GO_CAPTAIN_CHEST_3: + if (Difficulty == RAID_DIFFICULTY_25MAN_NORMAL) + m_uiCaptainsChestHordeGUID = pGo->GetObjectGuid(); + break; + case GO_CAPTAIN_CHEST_2: + if (Difficulty == RAID_DIFFICULTY_10MAN_NORMAL) + m_uiCaptainsChestAllianceGUID = pGo->GetObjectGuid(); + break; + case GO_CAPTAIN_CHEST_4: + if (Difficulty == RAID_DIFFICULTY_25MAN_NORMAL) + m_uiCaptainsChestAllianceGUID = pGo->GetObjectGuid(); + break; + + case GO_ICE_WALL: + pGo->SetPhaseMask(65535, true); + break; + case GO_CAVE: + pGo->SetGoState(GO_STATE_ACTIVE);; + break; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + } + + void SetData(uint32 uiType, uint32 uiData) override + { + switch(uiType) + { + case TYPE_PHASE: m_auiEncounter[uiType] = uiData; break; + case TYPE_EVENT: m_auiEncounter[uiType] = uiData; + uiData = NOT_STARTED; + break; + case TYPE_FALRIC: m_auiEncounter[uiType] = uiData; + if (uiData == SPECIAL) + DoCloseDoor(GO_ICECROWN_DOOR); + else if (uiData == FAIL) + DoOpenDoor(GO_ICECROWN_DOOR); + break; + case TYPE_MARWYN: m_auiEncounter[uiType] = uiData; + if (uiData == SPECIAL) + DoCloseDoor(GO_ICECROWN_DOOR); + else if (uiData == FAIL) + DoOpenDoor(GO_ICECROWN_DOOR); + else if (uiData == DONE) + { + DoOpenDoor(GO_IMPENETRABLE_DOOR); + DoOpenDoor(GO_ICECROWN_DOOR); + } + break; + case TYPE_FROST_GENERAL: m_auiEncounter[uiType] = uiData; + if(uiData == DONE) + DoOpenDoor(GO_ICECROWN_DOOR_2); + break; + case TYPE_LICH_KING: m_auiEncounter[uiType] = uiData; + if(uiData == IN_PROGRESS) + DoOpenDoor(GO_ICECROWN_DOOR_3); + if(uiData == DONE) + { + if (GameObject* pChest = instance->GetGameObject(m_uiCaptainsChestAllianceGUID)) + if (pChest && !pChest->isSpawned() && GetData(DATA_ESCAPE_LIDER) == NPC_JAINA_OUTRO) + { + pChest->SetRespawnTime(DAY); + } + if (GameObject* pChest = instance->GetGameObject(m_uiCaptainsChestHordeGUID)) + if (pChest && !pChest->isSpawned() && GetData(DATA_ESCAPE_LIDER) == NPC_SYLVANA_OUTRO) + { + pChest->SetRespawnTime(DAY); + }; + if (GameObject* pPortal = GetSingleGameObjectFromStorage(GO_PORTAL)) + if (pPortal && !pPortal->isSpawned()) + { + pPortal->SetRespawnTime(DAY); + }; + } + break; + case TYPE_HALLS: m_auiEncounter[uiType] = uiData; break; + case DATA_SUMMONS: if (uiData == 3) m_uiSummons = 0; + else if (uiData == 1) ++m_uiSummons; + else if (uiData == 0) --m_uiSummons; + uiData = NOT_STARTED; + break; + case DATA_ESCAPE_LIDER: m_auiLeader = uiData; + uiData = NOT_STARTED; + case DATA_WAVE_COUNT: m_waveCount = uiData; + uiData = NOT_STARTED; + if (m_waveCount > 0 && m_waveCount < 10) + { + DoUpdateWorldState(WORLD_STATE_HOR, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, m_waveCount); + } + else + DoUpdateWorldState(WORLD_STATE_HOR, 0); + break; + default: + break; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + saveStream << m_auiEncounter[i] << " "; + + strSaveData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + const char* Save() const override + { + return strSaveData.c_str(); + } + + uint32 GetData(uint32 uiType) const override + { + switch(uiType) + { + case TYPE_PHASE: return m_auiEncounter[uiType]; + case TYPE_EVENT: return m_auiEncounter[uiType]; + case TYPE_FALRIC: return m_auiEncounter[uiType]; + case TYPE_MARWYN: return m_auiEncounter[uiType]; + case TYPE_LICH_KING: return m_auiEncounter[uiType]; + case TYPE_FROST_GENERAL: return m_auiEncounter[uiType]; + case TYPE_HALLS: return m_auiEncounter[uiType]; + case DATA_SUMMONS: return m_uiSummons; + case DATA_ESCAPE_LIDER: return m_auiLeader; + default: return 0; + } + return 0; + } + + void Load(const char* chrIn) override + { + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + { + loadStream >> m_auiEncounter[i]; + + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; + } + +}; + +InstanceData* GetInstanceData_instance_halls_of_reflection(Map* pMap) +{ + return new instance_halls_of_reflection(pMap); +} + +void AddSC_instance_halls_of_reflection() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_halls_of_reflection"; + newscript->GetInstanceData = &GetInstanceData_instance_halls_of_reflection; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_gafrost.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_gafrost.cpp deleted file mode 100644 index 4cbde3ea48..0000000000 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_gafrost.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_forgemaster_gafrost -SD%Complete: 0% -SDComment: -SDCategory: Pit of Saron -EndScriptData */ - -#include "precompiled.h" -#include "pit_of_saron.h" - -enum -{ - SAY_AGGRO = -1658014, - SAY_SLAY_1 = -1658015, - SAY_BOULDER_HIT = -1658016, - 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, -}; - -void AddSC_boss_gafrost() -{ - -} 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 new file mode 100644 index 0000000000..6eb17dfb02 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp @@ -0,0 +1,301 @@ +/* Copyright (C) 2006 - 2013 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_forgemaster_garfrost +SD%Complete: 90 +SDComment: Tyrannus outro event NYI. +SDCategory: Pit of Saron +EndScriptData */ + +#include "precompiled.h" +#include "pit_of_saron.h" + +enum +{ + SAY_AGGRO = -1658014, + SAY_SLAY_1 = -1658015, + SAY_BOULDER_HIT = -1658016, // TODO How must this be handled? + SAY_DEATH = -1658017, + SAY_FORGE_1 = -1658018, + SAY_FORGE_2 = -1658019, + + 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, + SPELL_CHILLING_WAVE = 68778, + 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, + PHASE_MOVEMENT = 4, +}; + +static const float aGarfrostMoveLocs[2][3] = +{ + {657.539f, -203.564f, 526.691f}, + {719.785f, -230.227f, 527.033f}, +}; + +static const float afOutroNpcSpawnLoc[4] = {695.0146f, -123.7532f, 515.3067f, 4.59f}; + +struct MANGOS_DLL_DECL boss_forgemaster_garfrostAI : public ScriptedAI +{ + boss_forgemaster_garfrostAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_pit_of_saron*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + 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() override + { + m_uiCheckPermafrostTimer = 2000; + m_uiThrowSaroniteTimer = 13000; + m_uiChillingWaveTimer = 10000; + m_uiDeepFreezeTimer = 10000; + SetCombatMovement(true); + m_uiPhase = PHASE_NO_ENCHANTMENT; + } + + 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) 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*/) override + { + DoScriptText(SAY_SLAY_1, m_creature); + } + + 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 + { + if (uiMotionType != EFFECT_MOTION_TYPE) + return; + + if (uiPointId != PHASE_BLADE_ENCHANTMENT && uiPointId != PHASE_MACE_ENCHANTMENT) + return; + + // Cast and say expected spell + DoCastSpellIfCan(m_creature, uiPointId == PHASE_BLADE_ENCHANTMENT ? SPELL_FORGE_FROZEN_BLADE : SPELL_FORGE_FROSTBORN_MACE); + DoScriptText(uiPointId == PHASE_BLADE_ENCHANTMENT ? SAY_FORGE_1 : SAY_FORGE_2, m_creature); + + m_uiThrowSaroniteTimer += 5000; // Delay next Saronit + m_uiPhase = uiPointId; + SetCombatMovement(true); + + if (m_creature->getVictim()) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + + 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; + + // Casted in every phase + if (m_uiThrowSaroniteTimer < uiDiff) + { + // TODO - only target players? + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_THROW_SARONITE) == CAST_OK) + { + DoScriptText(EMOTE_THROW_SARONITE, m_creature, pTarget); + m_uiThrowSaroniteTimer = 16000; + } + } + } + else + m_uiThrowSaroniteTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_NO_ENCHANTMENT: + { + if (m_creature->GetHealthPercent() < 66.0f) + { + DoCastSpellIfCan(m_creature, SPELL_THUNDERING_STOMP, CAST_INTERRUPT_PREVIOUS); + SetCombatMovement(false); + + 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 + return; + } + break; + } + case PHASE_BLADE_ENCHANTMENT: + { + if (m_creature->GetHealthPercent() < 33.0f) + { + DoCastSpellIfCan(m_creature, SPELL_THUNDERING_STOMP, CAST_INTERRUPT_PREVIOUS); + SetCombatMovement(false); + + 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 + return; + } + + if (m_uiChillingWaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHILLING_WAVE) == CAST_OK) + m_uiChillingWaveTimer = 14000; + } + else + m_uiChillingWaveTimer -= uiDiff; + + break; + } + case PHASE_MACE_ENCHANTMENT: + { + if (m_uiDeepFreezeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEEP_FREEZE) == CAST_OK) + { + DoScriptText(EMOTE_DEEP_FREEZE, m_creature, pTarget); + m_uiDeepFreezeTimer = 20000; + } + } + } + else + m_uiDeepFreezeTimer -= uiDiff; + + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_forgemaster_garfrost(Creature* pCreature) +{ + return new boss_forgemaster_garfrostAI(pCreature); +} + +void AddSC_boss_garfrost() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_forgemaster_garfrost"; + pNewScript->GetAI = &GetAI_boss_forgemaster_garfrost; + pNewScript->RegisterSelf(); +} 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 728a83d48c..7462dced74 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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->RemoveAllAuras(); + 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 MANGOS_DLL_DECL 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 d2d817a5ab..07c90cc62d 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_scourgelord_tyrannus -SD%Complete: 0% -SDComment: +SD%Complete: 80 +SDComment: Icy Blast not fully implemented. 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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->RemoveAllAuras(); + 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 1fd74c91b9..3b441db795 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,7 +16,7 @@ /* ScriptData SDName: instance_pit_of_saron -SD%Complete: 50% +SD%Complete: 80% SDComment: SDCategory: Pit of Saron EndScriptData */ @@ -24,67 +24,297 @@ EndScriptData */ #include "precompiled.h" #include "pit_of_saron.h" -instance_pit_of_saron::instance_pit_of_saron(Map* pMap) : ScriptedInstance(pMap), - m_uiTyrannusIntroGUID(0), - m_uiGarfrostGUID(0), - m_uiKrickGUID(0), - m_uiIckGUID(0), - m_uiTyrannusGUID(0), - m_uiRimefangGUID(0), - m_uiIcewallGUID(0), - m_uiHallsPortGUID(0) +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: m_uiTyrannusIntroGUID = pCreature->GetGUID(); break; - case NPC_GARFROST: m_uiGarfrostGUID = pCreature->GetGUID(); break; - case NPC_KRICK: m_uiKrickGUID = pCreature->GetGUID(); break; - case NPC_ICK: m_uiIckGUID = pCreature->GetGUID(); break; - case NPC_TYRANNUS: m_uiTyrannusGUID = pCreature->GetGUID(); break; - case NPC_RIMEFANG: m_uiRimefangGUID = pCreature->GetGUID(); break; + 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: - m_uiIcewallGUID = pGo->GetGUID(); if (m_auiEncounter[TYPE_GARFROST] == DONE && m_auiEncounter[TYPE_KRICK] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_HALLS_OF_REFLECT_PORT: - m_uiHallsPortGUID = pGo->GetGUID(); break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } 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(m_uiIcewallGUID); + 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(m_uiIcewallGUID); + 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) + { + Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS); + if (!pTyrannus) + return; + + // ToDo: enable this when the achiev check spells are implemented + // pTyrannus->CastSpell(pTyrannus, SPELL_ACHIEVEMENT_CHECK, true); + m_uiIciclesTimer = 0; + } m_auiEncounter[uiType] = uiData; break; default: @@ -96,9 +326,9 @@ 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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -116,9 +346,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; @@ -127,30 +357,283 @@ 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 { - switch(uiType) + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_pit_of_saron::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_YMIRJAR_DEATHBRINGER) { - case TYPE_GARFROST: return m_auiEncounter[uiType]; - case TYPE_KRICK: return m_auiEncounter[uiType]; - case TYPE_TYRANNUS: return m_auiEncounter[uiType]; - default: - return 0; + ++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); + } + } + } } } -uint64 instance_pit_of_saron::GetData64(uint32 uiData) +void instance_pit_of_saron::OnCreatureDeath(Creature* pCreature) { - switch(uiData) + switch (pCreature->GetEntry()) { - case NPC_TYRANNUS_INTRO: return m_uiTyrannusIntroGUID; - case NPC_GARFROST: return m_uiGarfrostGUID; - case NPC_KRICK: return m_uiKrickGUID; - case NPC_ICK: return m_uiIckGUID; - case NPC_TYRANNUS: return m_uiTyrannusGUID; - case NPC_RIMEFANG: return m_uiRimefangGUID; + 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 0; + 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; } } 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 1dfe435b5b..4ae579401b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 = 69425, +}; + +/*###### +## npc_ymirjar_deathbringer +######*/ + +struct MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 && 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 2c8d8185e5..be0cf2e0a5 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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,56 +27,156 @@ 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, + NPC_GENERAL_BUNNY = 24110, 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 }; -class MANGOS_DLL_DECL instance_pit_of_saron : public ScriptedInstance +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}, +}; + +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 MANGOS_DLL_DECL 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) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); + 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) override; protected: + void JustDidDialogueStep(int32 iEntry) override; + void ProcessIntroEventNpcs(Player* pPlayer); + uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - // Creature GUIDs - uint64 m_uiTyrannusIntroGUID; - uint64 m_uiGarfrostGUID; - uint64 m_uiKrickGUID; - uint64 m_uiIckGUID; - uint64 m_uiTyrannusGUID; - uint64 m_uiRimefangGUID; - - // GameObject GUIDs - uint64 m_uiIcewallGUID; - uint64 m_uiHallsPortGUID; + 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 65b26c3f6c..0a43786852 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,1069 @@ /* ScriptData SDName: blood_prince_council -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" +#include "GridNotifiers.h" + +enum BossSpells +{ + // spells + SPELL_BERSERK = 26662, + SPELL_FEIGN_DEATH = 71598, + + SPELL_INVOCATION_V_MOVE = 71075, + SPELL_INVOCATION_K_MOVE = 71079, + SPELL_INVOCATION_T_MOVE = 71082, + + // Valanar + SPELL_INVOCATION_VALANAR = 70952, + + SPELL_SHOCK_VORTEX = 72037, + SPELL_SHOCK_VORTEX_AURA = 71945, + SPELL_SHOCK_VORTEX_VISUAL = 72633, + + SPELL_EMP_SHOCK_VORTEX = 72039, + + SPELL_KINETIC_BOMB = 72053, // summons the target, which must summon the bomb above its head and make it move to the target + SPELL_KINETIC_BOMB_TARGET = 72080, + SPELL_KINETIC_BOMB_DMG = 72052, + SPELL_KINETIC_BOMB_VISUAL = 72054, + SPELL_UNSTABLE = 72059, // this proc makes the bomb teleport by 3-5? yards up and applies knockback aura + // SPELL_KNOCKBACK_AURA = 72087, // this stacks to 2. duration = 3 secs, maybe this makes bomb stand for 3secs per stack? + + // Keleseth + SPELL_INVOCATION_KELESETH = 70981, + + SPELL_SHADOW_LANCE = 71405, + SPELL_EMP_SHADOW_LANCE = 71815, + + SPELL_SHADOW_RESONANCE = 71943, + // SPELL_SHADOW_RESONANCE_AURA = 71911, // blizz used this for determining the distance, probably. (not used) + SPELL_SHADOW_RESONANCE_BUFF = 71822, + + SPELL_SHADOW_PRISON = 73001, + + // Taldaram + SPELL_INVOCATION_TALDARAM = 70982, + + SPELL_GLITTERING_SPARKS = 71807, + + SPELL_BALL_FLAMES_VISUAL = 71706, + SPELL_CONJURE_FLAME = 71718, // dummy effect, must trigger spell summoning the sphere + SPELL_CONJURE_EMP_FLAME = 72040, + SPELL_FLAMES = 71393, // cast on the impact + SPELL_BALL_FLAMES_PERIODIC = 71709, // used on heroic, triggers empowered flare which reduces dmg of flames on impact + // SPELL_BALL_FLAMES_TRIGGERED = 71708, // this spell must reduce stack of 71756 + SPELL_FLAMES_BUFF = 71756, +}; + +// talks +enum +{ + 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, +}; + + +struct MANGOS_DLL_DECL boss_blood_queen_lanathel_introAI : public ScriptedAI +{ + boss_blood_queen_lanathel_introAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiEventTimer; + uint32 m_uiEventPhase; + bool m_bEventStarted; + bool m_bEventEnded; + + void Reset() override + { + m_bEventStarted = false; + m_bEventEnded = false; + m_uiEventPhase = 0; + m_uiEventTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override {} + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bEventStarted || m_bEventEnded) + return; + + if (pWho && pWho->IsWithinDistInMap(m_creature, 50.0f) && + ((pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster()) || + pWho->GetObjectGuid().IsPet())) + { + if (Creature* pTaldaram = m_pInstance->GetSingleCreatureFromStorage(NPC_TALDARAM)) + pTaldaram->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (Creature* pKeleseth = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + pKeleseth->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (Creature* pValanar = m_pInstance->GetSingleCreatureFromStorage(NPC_VALANAR)) + pValanar->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_bEventStarted = true; + } + } + + void NextStep(uint32 uiTimer) + { + ++m_uiEventPhase; + m_uiEventTimer = uiTimer; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bEventEnded || !m_bEventStarted) + return; + + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiEventPhase) + { + case 0: + DoScriptText(SAY_COUNCIL_INTRO_1, m_creature); + NextStep(15000); + break; + case 1: + DoScriptText(SAY_COUNCIL_INTRO_2, m_creature); + NextStep(5000); + break; + case 2: + // raise princes + if (m_pInstance) + { + if (Creature* pTaldaram = m_pInstance->GetSingleCreatureFromStorage(NPC_TALDARAM)) + { + pTaldaram->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTaldaram->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + pTaldaram->SetInCombatWithZone(); + } + if (Creature* pKeleseth = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + { + pKeleseth->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pKeleseth->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + pKeleseth->SetInCombatWithZone(); + } + if (Creature* pValanar = m_pInstance->GetSingleCreatureFromStorage(NPC_VALANAR)) + { + pValanar->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pValanar->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + pValanar->SetInCombatWithZone(); + } + } + m_creature->SetVisibility(VISIBILITY_OFF); + m_bEventEnded = true; + break; + default: + break; + } + } + else + m_uiEventTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_blood_queen_lanathel_intro(Creature* pCreature) +{ + return new boss_blood_queen_lanathel_introAI(pCreature); +} + +// Blood Orb Controller +struct MANGOS_DLL_DECL npc_blood_orb_controlAI : public ScriptedAI +{ + npc_blood_orb_controlAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiCheckTimer; + uint32 m_uiLastResult; + uint32 m_uiInvocationTimer; + bool m_bIsInProgress; + + void Reset() override + { + m_uiCheckTimer = 1000; + m_bIsInProgress = false; + m_uiInvocationTimer = 30000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsInProgress) + { + if (m_uiCheckTimer <= uiDiff) + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_BLOOD_PRINCE_COUNCIL) == IN_PROGRESS) + { + m_bIsInProgress = true; + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_VALANAR, CAST_TRIGGERED); + m_uiLastResult = 0; + } + } + + m_uiCheckTimer = 1000; + } + else + m_uiCheckTimer -= uiDiff; + + return; + } + else + { + if (m_uiCheckTimer <= uiDiff) + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_BLOOD_PRINCE_COUNCIL) == FAIL) + { + Reset(); + return; + } + } + + m_uiCheckTimer = 1000; + } + else + m_uiCheckTimer -= uiDiff; + } + + // battle in progress + // every 30 seconds cast Invocation of Blood on random prince + if (m_uiInvocationTimer <= uiDiff) + { + uint8 uiResult = urand(0, 2); + uiResult = uiResult == m_uiLastResult ? (uiResult + 1) % 3 : 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 = 30000; + } + else + m_uiInvocationTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_blood_orb_control(Creature* pCreature) +{ + return new npc_blood_orb_controlAI(pCreature); +} + +// base struct for Blood Prince Council +struct MANGOS_DLL_DECL base_blood_prince_council_bossAI : public base_icc_bossAI +{ + base_blood_prince_council_bossAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH, CAST_TRIGGERED); + } + + bool m_bIsEmpowered; + bool m_bIsSaidSpecial; // 1st spell cast after being empowered is followed by special say + uint32 m_uiEmpowermentFadeTimer; + uint32 m_uiInvocationSpellEntry; + int32 m_iSayInvocationEntry; + uint32 m_uiBerserkTimer; + uint32 m_uiSphereTimer; + + void Reset() override + { + m_bIsEmpowered = false; + m_bIsSaidSpecial = false; + m_uiEmpowermentFadeTimer = 30000; + m_uiSphereTimer = urand(5000, 15000); + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_creature->SetHealth(1); + } + + void Aggro(Unit* /*pWho*/) override + { + m_creature->CallForHelp(30.0f); + } + + void DamageTaken(Unit* pDealer, uint32& uiDamage) override + { + if (!m_bIsEmpowered && pDealer->GetEntry() != NPC_BLOOD_ORB_CONTROL) + { + m_creature->AddThreat(pDealer, uiDamage); + uiDamage = 0; + } + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance && pKiller) + { + if (m_creature->GetEntry() != NPC_VALANAR) + { + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_VALANAR)) + { + if (pTmp->isAlive()) + { + pTmp->RemoveAurasDueToSpell(SPELL_INVOCATION_VALANAR); + pKiller->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + } + + if (m_creature->GetEntry() != NPC_KELESETH) + { + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + { + if (pTmp->isAlive()) + { + pTmp->RemoveAurasDueToSpell(SPELL_INVOCATION_KELESETH); + pKiller->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + } + + if (m_creature->GetEntry() != NPC_TALDARAM) + { + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_TALDARAM)) + { + if (pTmp->isAlive()) + { + pTmp->RemoveAurasDueToSpell(SPELL_INVOCATION_TALDARAM); + pKiller->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + } + + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_QUEEN_LANATHEL_INTRO)) + { + if (pTmp->isAlive()) + pTmp->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_BLOOD_PRINCE_COUNCIL) != FAIL) + m_pInstance->SetData(TYPE_BLOOD_PRINCE_COUNCIL, FAIL); + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pSpell->Id == m_uiInvocationSpellEntry) + { + m_creature->SetHealth(pCaster->GetHealth()); + m_bIsEmpowered = true; + DoScriptText(m_iSayInvocationEntry, m_creature); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Invocation of Blood + if (m_bIsEmpowered) + { + if (m_uiEmpowermentFadeTimer <= uiDiff) + { + m_creature->RemoveAurasDueToSpell(m_uiInvocationSpellEntry); + m_creature->SetHealth(1); + m_bIsEmpowered = false; + m_bIsSaidSpecial = false; + m_uiEmpowermentFadeTimer = 30000; + } + else + m_uiEmpowermentFadeTimer -= uiDiff; + } + + // Berserk + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + } + else + m_uiBerserkTimer -= uiDiff; + } +}; + + +// Valanar +struct MANGOS_DLL_DECL boss_valanar_iccAI : public base_blood_prince_council_bossAI +{ + boss_valanar_iccAI(Creature* pCreature) : base_blood_prince_council_bossAI(pCreature) + { + Reset(); + m_uiInvocationSpellEntry = SPELL_INVOCATION_VALANAR; + m_iSayInvocationEntry = SAY_VALANAR_INVOCATION; + } + + uint32 m_uiVortexTimer; + + void Reset() override + { + base_blood_prince_council_bossAI::Reset(); + + m_uiVortexTimer = urand(5000, 10000); + } + + void Aggro(Unit* pWho) override + { + base_blood_prince_council_bossAI::Aggro(pWho); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_BLOOD_PRINCE_COUNCIL, IN_PROGRESS); + + if (Creature* pOrb = m_pInstance->GetSingleCreatureFromStorage(NPC_BLOOD_ORB_CONTROL)) + { + uint32 uiHealth = m_creature->GetMaxHealth(); + pOrb->Respawn(); + pOrb->SetMaxHealth(uiHealth); + pOrb->SetHealth(uiHealth); + } + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_VALANAR_SLAY_1 - urand(0, 1), m_creature); + } + + void JustDied(Unit* pKiller) override + { + base_blood_prince_council_bossAI::JustDied(pKiller); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BLOOD_PRINCE_COUNCIL, DONE); + + DoScriptText(SAY_VALANAR_DEATH, m_creature); + } + + void UpdateAI(const uint32 uiDiff) override + { + base_blood_prince_council_bossAI::UpdateAI(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Kinetic Bomb + if (m_uiSphereTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB) == CAST_OK) + m_uiSphereTimer = 20000; + } + else + m_uiSphereTimer -= uiDiff; + + // Shock Vortex + if (m_uiVortexTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SHOCK_VORTEX, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, m_bIsEmpowered ? SPELL_EMP_SHOCK_VORTEX : SPELL_SHOCK_VORTEX) == CAST_OK) + { + m_uiVortexTimer = urand(18000, 22000); + + if (m_bIsEmpowered && !m_bIsSaidSpecial) + { + DoScriptText(SAY_VALANAR_SPECIAL, m_creature); + m_bIsSaidSpecial = false; + } + } + } + } + else + m_uiVortexTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_valanar_icc(Creature* pCreature) +{ + return new boss_valanar_iccAI(pCreature); +} + + +// Keleseth +struct MANGOS_DLL_DECL boss_keleseth_iccAI : public base_blood_prince_council_bossAI +{ + boss_keleseth_iccAI(Creature* pCreature) : base_blood_prince_council_bossAI(pCreature) + { + Reset(); + m_uiInvocationSpellEntry = SPELL_INVOCATION_KELESETH; + m_iSayInvocationEntry = SAY_KELESETH_INVOCATION; + } + + uint32 m_uiShadowLanceTimer; + bool m_bHasCastShadowPrison; + + void Reset() override + { + base_blood_prince_council_bossAI::Reset(); + + m_bHasCastShadowPrison = false; + m_uiShadowLanceTimer = urand(2000, 5000); + m_uiSphereTimer = 4000; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_KELESETH_SLAY_1 - urand(0, 1), m_creature); + } + + void JustDied(Unit* pKiller) override + { + base_blood_prince_council_bossAI::JustDied(pKiller); + + DoScriptText(SAY_KELESETH_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + base_blood_prince_council_bossAI::UpdateAI(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bIsHeroic) + { + if (!m_bHasCastShadowPrison) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_PRISON) == CAST_OK) + m_bHasCastShadowPrison = true; + } + } + + // Shadow Resonance + if (m_uiSphereTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_RESONANCE) == CAST_OK) + m_uiSphereTimer = 20000; + } + else + m_uiSphereTimer -= uiDiff; + + // Shadow Lance + if (m_uiShadowLanceTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsEmpowered ? SPELL_EMP_SHADOW_LANCE : SPELL_SHADOW_LANCE) == CAST_OK) + { + if (m_bIsEmpowered && !m_bIsSaidSpecial) + { + DoScriptText(SAY_KELESETH_SPECIAL, m_creature); + m_bIsSaidSpecial = true; + } + + m_uiShadowLanceTimer = urand(2000, 5000); + } + } + else + m_uiShadowLanceTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_keleseth_icc(Creature* pCreature) +{ + return new boss_keleseth_iccAI(pCreature); +} + + +// Taldaram +struct MANGOS_DLL_DECL boss_taldaram_iccAI : public base_blood_prince_council_bossAI +{ + boss_taldaram_iccAI(Creature* pCreature) : base_blood_prince_council_bossAI(pCreature) + { + Reset(); + m_uiInvocationSpellEntry = SPELL_INVOCATION_TALDARAM; + m_iSayInvocationEntry = SAY_TALDARAM_INVOCATION; + } + + uint32 m_uiSparksTimer; + + void Reset() override + { + base_blood_prince_council_bossAI::Reset(); + + m_uiSparksTimer = urand(8000, 15000); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_TALDARAM_SLAY_1 - urand(0, 1), m_creature); + } + + void JustDied(Unit* pKiller) override + { + base_blood_prince_council_bossAI::JustDied(pKiller); + + DoScriptText(SAY_TALDARAM_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + Player* pTarget = GetFarthestPlayer(pSummoned, 60.0f); + + if (pTarget) + { + pSummoned->FixateTarget(pTarget); + pSummoned->AI()->AttackStart(pTarget); + if (m_bIsEmpowered) + { + pSummoned->CastSpell(pSummoned, SPELL_FLAMES_BUFF, true); + pSummoned->CastSpell(pSummoned, SPELL_BALL_FLAMES_PERIODIC, true); + } + } + pSummoned->SetInCombatWithZone(); + } + + Player* GetFarthestPlayer(Creature* pCreature, float MaxRangeDistance = 100.0f) + { + Player* farPlayer = NULL; + std::list targets; + float distance = 0.0f; + + GetPlayerListInGrid(targets, m_creature, 100.0f); + + for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + Player* pPlayer = *itr; + if (pPlayer && pPlayer->IsInWorld()) + { + float distance2 = pCreature->GetDistance(pPlayer); + if (distance2 > distance) + { + farPlayer = pPlayer; + distance = distance2; + } + } + } + return farPlayer; + } + + void UpdateAI(const uint32 uiDiff) override + { + base_blood_prince_council_bossAI::UpdateAI(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Conjure Flame + if (m_uiSphereTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsEmpowered ? SPELL_CONJURE_EMP_FLAME : SPELL_CONJURE_FLAME) == CAST_OK) + m_uiSphereTimer = 20000; + } + else + m_uiSphereTimer -= uiDiff; + + // Glittering Sparks + if (m_uiSparksTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_GLITTERING_SPARKS, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, 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); +} + +// Shock Vortex +struct MANGOS_DLL_DECL mob_shock_vortexAI : public ScriptedAI +{ + mob_shock_vortexAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiCastTimer; + + void Reset() override + { + m_creature->SetInCombatWithZone(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiCastTimer = 4000; + SetCombatMovement(false); + m_creature->ForcedDespawn(30000); + DoCastSpellIfCan(m_creature, SPELL_SHOCK_VORTEX_VISUAL, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiCastTimer) + { + if (m_uiCastTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_SHOCK_VORTEX_AURA, CAST_TRIGGERED); + m_uiCastTimer = 0; + } + else + m_uiCastTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_mob_shock_vortex(Creature* pCreature) +{ + return new mob_shock_vortexAI(pCreature); +}; + +// Dark Nucleus +struct MANGOS_DLL_DECL mob_dark_nucleusAI : public base_icc_bossAI +{ + mob_dark_nucleusAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + void Reset() override {} + + void DamageTaken(Unit* pDealer, uint32& /*uiDamage*/) override + { + m_creature->FixateTarget(pDealer); + m_creature->InterruptNonMeleeSpells(true); + } + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_BLOOD_PRINCE_COUNCIL) != IN_PROGRESS) + { + m_creature->ForcedDespawn(); + return; + } + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_RESONANCE_BUFF); + } +}; + +CreatureAI* GetAI_mob_dark_nucleus(Creature* pCreature) +{ + return new mob_dark_nucleusAI(pCreature); +}; + +// Ball of Flames +struct MANGOS_DLL_DECL mob_ball_of_flamesAI : public ScriptedAI +{ + mob_ball_of_flamesAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 3.0f, false); + Reset(); + } + + uint32 m_uiStartTimer; + bool m_bIsDespawned; + + void Reset() override + { + m_creature->SetSpeedRate(MOVE_RUN, 2.0f); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetLevitate(true); + m_creature->SetDisplayId(26767); + + m_uiStartTimer = 3000; + m_bIsDespawned = false; + + DoCastSpellIfCan(m_creature, SPELL_BALL_FLAMES_VISUAL, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bIsDespawned) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_creature->GetFixatedTarget()) + m_creature->FixateTarget(m_creature->getVictim()); + + if (m_uiStartTimer) + { + if (m_uiStartTimer <= uiDiff) + { + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiStartTimer = 0; + } + else + m_uiStartTimer -= uiDiff; + + return; + } + + if (m_creature->GetDistance(m_creature->getVictim()) < INTERACTION_DISTANCE) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAMES) == CAST_OK) + { + m_creature->ForcedDespawn(1000); + m_creature->RemoveAurasDueToSpell(SPELL_BALL_FLAMES_PERIODIC); + m_bIsDespawned = true; + } + } + } +}; + +CreatureAI* GetAI_mob_ball_of_flames(Creature* pCreature) +{ + return new mob_ball_of_flamesAI(pCreature); +}; + +// Kinetic Bomb +struct MANGOS_DLL_DECL mob_kinetic_bombAI : public ScriptedAI +{ + mob_kinetic_bombAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsHeroic = pCreature->GetMap()->GetDifficulty() > RAID_DIFFICULTY_25MAN_NORMAL; + Reset(); + } + + bool m_bHasCast; + bool m_bIsHeroic; + uint32 m_uiStartTimer; + float m_fZ; + + void Reset() override + { + float x, y; + + m_bHasCast = false; + m_uiStartTimer = 3000; + + m_creature->SetSpeedRate(MOVE_WALK, 0.7f); + + m_creature->SetDisplayId(31095); + + DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_VISUAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_UNSTABLE, CAST_TRIGGERED); + + m_creature->SetLevitate(true); + m_creature->GetPosition(x, y, m_fZ); + + m_creature->NearTeleportTo(x, y, m_fZ + (m_bIsHeroic ? 10.0f : 15.0f), 0.0f); + + m_creature->GetMotionMaster()->MovePoint(0, x, y, m_fZ, false); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + + if (!m_bHasCast && !m_creature->HasAura(SPELL_KINETIC_BOMB_VISUAL)) + DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_VISUAL, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override {} + void EnterEvadeMode() override {} + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiStartTimer) + { + if (m_uiStartTimer <= uiDiff) + { + m_uiStartTimer = 0; + } + else + m_uiStartTimer -= uiDiff; + + return; + } + + if (m_bHasCast) + return; + + if (m_creature->GetPositionZ() < m_fZ + 2.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_DMG) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_KINETIC_BOMB_VISUAL); + m_bHasCast = true; + m_creature->ForcedDespawn(3000); + } + } + } +}; + +CreatureAI* GetAI_mob_kinetic_bomb(Creature* pCreature) +{ + return new mob_kinetic_bombAI(pCreature); +}; + + +struct MANGOS_DLL_DECL mob_kinetic_bomb_targetAI : public ScriptedAI +{ + mob_kinetic_bomb_targetAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + void Reset() override + { + m_creature->SetDisplayId(31095); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetCombatMovement(false); + + DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_TARGET, CAST_TRIGGERED); + } + + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override + { + m_creature->ForcedDespawn(); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } + + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_kinetic_bomb_target(Creature* pCreature) +{ + return new mob_kinetic_bomb_targetAI(pCreature); +}; + + +void AddSC_blood_prince_council() +{ + Script* pNewScript; + + 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(); + + pNewScript = new Script; + pNewScript->Name = "boss_blood_queen_lanathel_intro"; + pNewScript->GetAI = &GetAI_boss_blood_queen_lanathel_intro; + 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 = "mob_shock_vortex"; + pNewScript->GetAI = &GetAI_mob_shock_vortex; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_dark_nucleus"; + pNewScript->GetAI = &GetAI_mob_dark_nucleus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_ball_of_flames"; + pNewScript->GetAI = &GetAI_mob_ball_of_flames; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_kinetic_bomb"; + pNewScript->GetAI = &GetAI_mob_kinetic_bomb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_kinetic_bomb_target"; + pNewScript->GetAI = &GetAI_mob_kinetic_bomb_target; + 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 8a71d4575f..57f0684c93 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,512 @@ /* ScriptData SDName: boss_blood_queen_lanathel -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum BossSpells +{ + // all phases + SPELL_BERSERK = 26662, + SPELL_SHROUD_OF_SORROW = 70986, + + // phase ground + SPELL_BLOOD_MIRROR = 70445, + SPELL_BLOOD_MIRROR_LINKED = 70451, // cast on the target receiving damage? + // SPELL_DELIRIOUS_SLASH = 72261, + SPELL_DELIRIOUS_SLASH_1 = 71623, // effect + SPELL_DELIRIOUS_SLASH_2 = 72264, // with charge effect. cast on random target if offtank is not present? + SPELL_SWARMING_SHADOWS = 71861, + SPELL_SWARMING_SHADOWS_TRIGGERED = 71264, // triggered by previous + SPELL_SWARMING_SHADOWS_AURA = 71267, + SPELL_PACT_OF_THE_DARKFALLEN = 71336, + // SPELL_VAMPIRIC_BITE = 71837, + SPELL_VAMPIRIC_BITE_TRIGGERED = 71726, // triggered spell with effects + // SPELL_VAMPIRIC_BITE_PLAYER = 70946, // used by players + SPELL_TWILIGHT_BLOODBOLT = 71445, + // SPELL_TWILIGHT_BLOODBOLT_TRIGGERED = 71818, // spell dealing dmg + // SPELL_TWILIGHT_BLOODBOLT_VISUAL = 72313, // dummy effect + // SPELL_TWILIGHT_BLOODBOLT_TRIGGERED1 = 71446, // one of the triggered spells + // SPELL_TWILIGHT_BLOODBOLT_TRIGGERED2 = 71818, // another of the triggered spells. same effects but other spell id... + // SPELL_PRESENCE_OF_DARKFALLEN = 71952, // on heroic + + // phase air + SPELL_INCITE_TERROR = 73070, + SPELL_BLOODBOLT_WHIRL = 71772, + + // others +// NPC_SWARMING_SHADOWS = 38163, + +// THIRST_QUENCHED_AURA = 72154 +}; + +// talks +enum +{ + SAY_AGGRO = -1631121, + SAY_BITE_1 = -1631122, + SAY_BITE_2 = -1631123, + SAY_SHADOWS = -1631124, + SAY_PACT = -1631125, + SAY_MC = -1631126, + SAY_AIR_PHASE = -1631127, + SAY_BERSERK = -1631128, + SAY_DEATH = -1631129, +}; + +static LOCATION QueenLocs[]= +{ + {4595.640137f, 2769.195557f, 400.137054f}, // 0 Phased + {4595.904785f, 2769.315918f, 421.838623f}, // 1 Fly +}; + +enum +{ + PHASE_GROUND, + PHASE_RUNNING, + PHASE_AIR, + PHASE_FLYING +}; + +enum +{ + POINT_CENTER_GROUND, + POINT_CENTER_AIR +}; + +/** + * Queen Lana'thel + */ +struct MANGOS_DLL_DECL boss_blood_queen_lanathelAI : public base_icc_bossAI +{ + boss_blood_queen_lanathelAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiPhase; + + uint32 m_uiBloodMirrorTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiPhaseTimer; + uint32 m_uiVampiricBiteTimer; + uint32 m_uiBloodboltTimer; + uint32 m_uiPactTimer; + uint32 m_uiSwarmingShadowsTimer; + uint32 m_uiDeliriousSlashTimer; + + bool m_bHasBitten; + + void Reset() override + { + m_uiPhase = PHASE_GROUND; + + m_bHasBitten = false; // for Vampiric Bite + + m_uiPhaseTimer = 2 * MINUTE * IN_MILLISECONDS; + m_uiEnrageTimer = (5 * MINUTE + 30) * IN_MILLISECONDS; + m_uiBloodMirrorTimer = 0; + m_uiDeliriousSlashTimer = 20000; + m_uiVampiricBiteTimer = 15000; + m_uiBloodboltTimer = urand(15000, 20000); + m_uiPactTimer = urand(20000, 25000); + m_uiSwarmingShadowsTimer= urand(30000, 35000); + + m_creature->SetWalk(false); + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + } + + void JustReachedHome() override + { + if(m_pInstance) + { + m_pInstance->SetData(TYPE_QUEEN_LANATHEL, FAIL); + RemoveAurasFromAllPlayers(); + } + } + + void KilledUnit(Unit* pVictim) override + { + // entry missing in sd2 database + if (pVictim->GetTypeId() == TYPEID_PLAYER) + m_creature->MonsterYell("Is that all you got?", 0); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_QUEEN_LANATHEL, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SHROUD_OF_SORROW, CAST_TRIGGERED); + } + + void JustDied(Unit* /*pKiller*/) override + { + if(m_pInstance) + { + m_pInstance->SetData(TYPE_QUEEN_LANATHEL, DONE); + RemoveAurasFromAllPlayers(); + } + + DoScriptText(SAY_DEATH, m_creature); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_CENTER_GROUND) + { + if (m_uiPhase == PHASE_RUNNING) + { + m_uiPhase = PHASE_AIR; // start counting timer for Bloodbolt Whirl immediately + + DoCastSpellIfCan(m_creature, SPELL_INCITE_TERROR); + // fly up + m_creature->SetWalk(true); + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_AIR, QueenLocs[1].x, QueenLocs[1].y, QueenLocs[1].z, false); + } + else + { + m_uiPhase = PHASE_GROUND; + + // stop flying + m_creature->SetWalk(false); + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + + SetCombatMovement(true, true); + } + } + else if (uiData == POINT_CENTER_AIR) + { + // Bloodbolt Whirl + DoCastSpellIfCan(m_creature, SPELL_BLOODBOLT_WHIRL); + m_uiPhase = PHASE_AIR; + m_uiPhaseTimer = 7000; + DoScriptText(SAY_AIR_PHASE, m_creature); + } + } + + Unit* SelectClosestFriendlyTarget(Unit* pVictim) + { + Unit* pResult = NULL; + + if (m_pInstance) + { + float lastDist = 500.0f; + const Map::PlayerList& players = m_pInstance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (!(*itr).getSource()->IsInWorld() || // don't target not in world players + !(*itr).getSource()->isAlive() || // don't target dead players + (*itr).getSource()->isGameMaster() || // don't target GMs + (*itr).getSource()->GetObjectGuid() == pVictim->GetObjectGuid()) // don't target current victim + continue; + + float dist = pVictim->GetDistance((*itr).getSource()); + if (dist < lastDist) + { + pResult = (*itr).getSource(); + lastDist = dist; + } + } + } + + return pResult; + } + + Unit* SelectVampiricBiteTarget() + { + const ThreatList& threatList = m_creature->getThreatManager().getThreatList(); + ThreatList::const_iterator itr = threatList.begin(); + std::advance(itr, 1); // don't target the main tank + for (;itr != threatList.end(); ++itr) + { + if (Unit* pVictim = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (!pVictim->HasAuraOfDifficulty(70867) && // Essence of the Blood Queen + !pVictim->HasAuraOfDifficulty(70877) && // Frenzied Bloodthirst + !pVictim->HasAuraOfDifficulty(70445) && // Blood Mirror + !pVictim->HasAuraOfDifficulty(70923)) // Uncontrollable Frenzy + { + return pVictim; + } + } + } + + return NULL; + } + + void RemoveAurasFromAllPlayers() + { + 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 (Player* pPlayer = i->getSource()) + { + if (pPlayer->isAlive()) + { + // Additional checking for achiev + pPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_QUEEN_LANATHEL, 0); + + // Uncontrollable Frenzy + pPlayer->RemoveAurasDueToSpell(70923); + pPlayer->RemoveAurasDueToSpell(70924); + + // Frenzied Bloodthirst + pPlayer->RemoveAurasDueToSpell(70877); + pPlayer->RemoveAurasDueToSpell(71474); + + // Essence of The Blood Queen + pPlayer->RemoveAurasDueToSpell(70867); + pPlayer->RemoveAurasDueToSpell(70871); + } + } + } + } + + void EnterEvadeMode() override + { + if (!IsCombatMovement()) + { + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + } + ScriptedAI::EnterEvadeMode(); + } + + void UpdateAI(const uint32 uiDiff) override + { + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Enrage + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiEnrageTimer = (5 * MINUTE + 30) * IN_MILLISECONDS; + } + } + else + m_uiEnrageTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_GROUND: + { + // phase change timer + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = PHASE_RUNNING; + SetCombatMovement(false, true); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_GROUND, QueenLocs[0].x, QueenLocs[0].y, QueenLocs[0].z); + m_uiPhaseTimer = 13000; + } + else + m_uiPhaseTimer -= uiDiff; + + // Blood Mirror + if (m_uiBloodMirrorTimer <= uiDiff) + { + if (Unit* pVictim = SelectClosestFriendlyTarget(m_creature->getVictim())) + { + pVictim->CastSpell(m_creature->getVictim(), SPELL_BLOOD_MIRROR, true); + pVictim->CastSpell(pVictim, SPELL_BLOOD_MIRROR_LINKED, true); + m_uiBloodMirrorTimer = 5000; + } + } + else + m_uiBloodMirrorTimer -= uiDiff; + + // Delirious Slash + if (m_bIsHeroic) + { + if (m_uiDeliriousSlashTimer <= uiDiff) + { + /** + * Spell that handles targeting - we can do this here. + * if (DoCastSpellIfCan(m_creature, SPELL_DELIRIOUS_SLASH) == CAST_OK) + */ + if (Unit* pTarget = SelectClosestFriendlyTarget(m_creature->getVictim())) + { + uint32 spell = SPELL_DELIRIOUS_SLASH_1; + + // if target is not in 5yd range then cast spell with charge effect + if (!m_creature->IsWithinDist(pTarget, 5.0f)) + spell = SPELL_DELIRIOUS_SLASH_2; + + if (DoCastSpellIfCan(pTarget, spell) == CAST_OK) + m_uiDeliriousSlashTimer = 15000; + } + } + else + m_uiDeliriousSlashTimer -= uiDiff; + } + + // Vampiric Bite + if (!m_bHasBitten) + { + if (m_uiVampiricBiteTimer <= uiDiff) + { + /** + * Spell handles targeting, but we can do this here. + * if (DoCastSpellIfCan(m_creature, SPELL_VAMPIRIC_BITE) == CAST_OK) + */ + if (Unit* pTarget = SelectVampiricBiteTarget()) + { + if (DoCastSpellIfCan(pTarget, SPELL_VAMPIRIC_BITE_TRIGGERED) == CAST_OK) + { + m_bHasBitten = true; + DoScriptText(SAY_BITE_1 - urand(0, 1), m_creature); + } + } + } + else + m_uiVampiricBiteTimer -= uiDiff; + } + + // Twilight Bloodbolt + if (m_uiBloodboltTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_BLOODBOLT) == CAST_OK) + m_uiBloodboltTimer = urand(15000, 20000); + } + else + m_uiBloodboltTimer -= uiDiff; + + // Pact of the Darkfallen + if (m_uiPactTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PACT_OF_THE_DARKFALLEN) == CAST_OK) + { + m_uiPactTimer = urand(20000, 25000); + DoScriptText(SAY_PACT, m_creature); + } + } + else + m_uiPactTimer -= uiDiff; + + // Swarming Shadows + if (m_uiSwarmingShadowsTimer <= uiDiff) + { + /** + * spell which handles picking targets + * but we can use SelectAttackingTarget() here + * if (DoCastSpellIfCan(m_creature, SPELL_SWARMING_SHADOWS) == CAST_OK) + */ + if (Unit* pTarget = SelectRandomRangedTarget(m_creature)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SWARMING_SHADOWS_TRIGGERED) == CAST_OK) + { + m_uiSwarmingShadowsTimer = urand(30000, 35000); + DoScriptText(SAY_SHADOWS, m_creature); + } + } + } + else + m_uiSwarmingShadowsTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + } + case PHASE_RUNNING: + case PHASE_FLYING: + { + // wait for arriving at the point + break; + } + case PHASE_AIR: + { + // phase change timer + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = PHASE_FLYING; + m_uiPhaseTimer = 2 * MINUTE * IN_MILLISECONDS - 13000; // substract the air phase duration + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_GROUND, QueenLocs[0].x, QueenLocs[0].y, QueenLocs[0].z); + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + } + } +}; + +CreatureAI* GetAI_boss_blood_queen_lanathel(Creature* pCreature) +{ + return new boss_blood_queen_lanathelAI(pCreature); +} + +/** + * Swarming Shadows + */ +struct MANGOS_DLL_DECL mob_swarming_shadowsAI : public ScriptedAI +{ + mob_swarming_shadowsAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetDisplayId(11686); + SetCombatMovement(false, true); + m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_SWARMING_SHADOWS_AURA, CAST_TRIGGERED); + } + + ScriptedInstance* m_pInstance; + + void Reset() override {} + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_QUEEN_LANATHEL) != IN_PROGRESS) + m_creature->ForcedDespawn(); + } + } +}; + +CreatureAI* GetAI_mob_swarming_shadows(Creature* pCreature) +{ + return new mob_swarming_shadowsAI(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(); + + pNewScript = new Script; + pNewScript->Name = "mob_swarming_shadows"; + pNewScript->GetAI = &GetAI_mob_swarming_shadows; + 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 6faff7ab39..5fc32cb4c6 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,911 @@ /* ScriptData SDName: boss_deathbringer_saurfang -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +// talks +enum +{ + SAY_AGGRO = -1631028, + SAY_FALLENCHAMPION = -1631029, + SAY_BLOODBEASTS = -1631030, + SAY_SLAY_1 = -1631031, + SAY_SLAY_2 = -1631032, + SAY_BERSERK = -1631033, + SAY_DEATH = -1631034, + SAY_INTRO_ALLY_0 = -1631035, + SAY_INTRO_ALLY_1 = -1631036, + SAY_INTRO_ALLY_2 = -1631037, + SAY_INTRO_ALLY_3 = -1631038, + SAY_INTRO_ALLY_4 = -1631039, + SAY_INTRO_ALLY_5 = -1631040, + SAY_INTRO_HORDE_1 = -1631041, + SAY_INTRO_HORDE_2 = -1631042, + SAY_INTRO_HORDE_3 = -1631043, + SAY_INTRO_HORDE_4 = -1631044, + SAY_INTRO_HORDE_5 = -1631045, + SAY_INTRO_HORDE_6 = -1631046, + SAY_INTRO_HORDE_7 = -1631047, + SAY_INTRO_HORDE_8 = -1631048, + SAY_INTRO_HORDE_9 = -1631049, + SAY_OUTRO_ALLY_1 = -1631050, + SAY_OUTRO_ALLY_2 = -1631051, + SAY_OUTRO_ALLY_3 = -1631052, + SAY_OUTRO_ALLY_4 = -1631053, + SAY_OUTRO_ALLY_5 = -1631054, + SAY_OUTRO_ALLY_6 = -1631055, + SAY_OUTRO_ALLY_7 = -1631056, + SAY_OUTRO_ALLY_8 = -1631057, + SAY_OUTRO_ALLY_9 = -1631058, + SAY_OUTRO_ALLY_10 = -1631059, + SAY_OUTRO_ALLY_11 = -1631060, + SAY_OUTRO_ALLY_12 = -1631061, + SAY_OUTRO_ALLY_13 = -1631062, + SAY_OUTRO_ALLY_14 = -1631063, + SAY_OUTRO_ALLY_15 = -1631064, + SAY_OUTRO_ALLY_16 = -1631065, + SAY_OUTRO_HORDE_1 = -1631066, + SAY_OUTRO_HORDE_2 = -1631067, + SAY_OUTRO_HORDE_3 = -1631068, + SAY_OUTRO_HORDE_4 = -1631069, +}; + +enum +{ + // Intro + SPELL_GRIP_OF_AGONY = 70572, + + // Blood Power + SPELL_BLOOD_POWER = 72371, + SPELL_BLOOD_LINK_BEAST = 72176, // proc aura for Blood Beasts + // SPELL_BLOOD_LINK = 72202, // cast on Saurfang to give 1 Blood Power + + // Mark of the Fallen Champion + SPELL_MARK_OF_FALLEN_CHAMPION = 72256, // proc on melee hit, dmg to marked targets + SPELL_MARK_OF_FALLEN_CHAMPION_DEBUFF = 72293, // proc on death - heal Saurfang + SPELL_REMOVE_MARKS = 72257, + + // Rune of Blood + SPELL_RUNE_OF_BLOOD = 72408, // cast on self on aggro + SPELL_RUNE_OF_BLOOD_DEBUFF = 72410, + + // Blood Nova + SPELL_BLOOD_NOVA = 72378, + + // Boiling Blood + SPELL_BOILING_BLOOD = 72385, + + // Blood Beasts + SPELL_CALL_BLOOD_BEAST_1 = 72172, + 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, + SPELL_SCENT_OF_BLOOD_TRIGGERED = 72771, // doesn't trigger, so cast in script... + SPELL_RESISTANT_SKIN = 72723, + + // enrage + SPELL_BERSERK = 26662, + SPELL_FRENZY = 72737, + + //summons + NPC_BLOOD_BEAST = 38508, + + // Achievements + SPELL_ACHIEVEMENT_CREDIT = 72928, +}; + +enum Equipment +{ + EQUIP_MAIN = 50798, + EQUIP_OFFHAND = EQUIP_NO_CHANGE, + EQUIP_RANGED = EQUIP_NO_CHANGE, + EQUIP_DONE = EQUIP_NO_CHANGE, +}; + +enum SaurfangEvent +{ + NPC_OVERLORD_SAURFANG = 37187, + NPC_KORKRON_REAVER = 37920, + + NPC_MURADIN_BRONZEBEARD = 37200, + // NPC_ALLIANCE_MASON = 37902, + + SPELL_VEHICLE_HARDCODED = 46598, // Deathbringer enters Overlord +}; + +enum SaurfangWaypoint +{ + POINT_ID_EVADE = 1 +}; + +// positions +static const float fPositions[12][4] = +{ + {-468.05f, 2211.69f, 541.11f, 3.16f}, // Deathbringer teleport point + {-491.30f, 2211.35f, 541.11f, 3.16f}, // Deathbringer dest point + {-559.82f, 2211.29f, 539.30f, 6.28f}, // main npc summon/despawn point + {-561.87f, 2215.94f, 539.30f, 6.28f}, // guard npc1 summon/despawn point + {-560.17f, 2214.17f, 539.30f, 6.28f}, // guard npc2 summon/despawn point + {-560.17f, 2207.71f, 539.30f, 6.28f}, // guard npc3 summon/despawn point + {-561.87f, 2205.68f, 539.30f, 6.28f}, // guard npc4 summon/despawn point + {-534.82f, 2211.29f, 539.30f, 6.28f}, // main npc first move + {-536.87f, 2215.94f, 539.30f, 6.28f}, // guard npc1 first move + {-535.17f, 2214.17f, 539.30f, 6.28f}, // guard npc2 first move + {-535.17f, 2207.71f, 539.30f, 6.28f}, // guard npc3 first move + {-536.87f, 2205.68f, 539.30f, 6.28f} // guard npc4 first move +}; + +// passive guards AI +struct MANGOS_DLL_DECL npc_deathbringer_event_guards_iccAI : public ScriptedAI +{ + npc_deathbringer_event_guards_iccAI(Creature* pCreature) : ScriptedAI(pCreature){} + + void Reset() override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} + void AttackStart(Unit* /*pWho*/) override {} +}; + +// Event handler +struct MANGOS_DLL_DECL npc_highlord_saurfang_iccAI : public base_icc_bossAI +{ + npc_highlord_saurfang_iccAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_bIsEventStarted = false; + m_uiEventStep = 0; + m_uiNextEventTimer = 0; + + m_lGuards.clear(); + } + + uint32 m_uiNextEventTimer; + uint32 m_uiEventStep; + bool m_bIsEventStarted; + + GuidList m_lGuards; + + void Reset() override {} + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } + + void AttackStart(Unit* /*pWho*/) override {} + + Creature* GetSaurfang() + { + if (m_pInstance) + return m_pInstance->GetSingleCreatureFromStorage(NPC_DEATHBRINGER_SAURFANG); + + return NULL; + } + + void DoSummonGuards() + { + // 4 adds + if (Creature* pTmp = m_creature->SummonCreature(NPC_KORKRON_REAVER, fPositions[3][0], fPositions[3][1], fPositions[3][2], fPositions[3][3], TEMPSUMMON_MANUAL_DESPAWN, 0)) + m_lGuards.push_back(pTmp->GetObjectGuid()); + if (Creature* pTmp = m_creature->SummonCreature(NPC_KORKRON_REAVER, fPositions[4][0], fPositions[4][1], fPositions[4][2], fPositions[4][3], TEMPSUMMON_MANUAL_DESPAWN, 0)) + m_lGuards.push_back(pTmp->GetObjectGuid()); + if (Creature* pTmp = m_creature->SummonCreature(NPC_KORKRON_REAVER, fPositions[5][0], fPositions[5][1], fPositions[5][2], fPositions[5][3], TEMPSUMMON_MANUAL_DESPAWN, 0)) + m_lGuards.push_back(pTmp->GetObjectGuid()); + if (Creature* pTmp = m_creature->SummonCreature(NPC_KORKRON_REAVER, fPositions[6][0], fPositions[6][1], fPositions[6][2], fPositions[6][3], TEMPSUMMON_MANUAL_DESPAWN, 0)) + m_lGuards.push_back(pTmp->GetObjectGuid()); + } + + void DoStartEvent() + { + m_bIsEventStarted = true; + NextStep(0); + } + + void DoContinueEvent() + { + NextStep(); + } + + void NextStep(uint32 uiTime = 1000) + { + ++m_uiEventStep; + m_uiNextEventTimer = uiTime; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsEventStarted || !m_pInstance) + return; + + if (m_uiNextEventTimer <= uiDiff) + { + switch (m_uiEventStep) + { + case 0: + { + break; + } + case 1: + { + DoSummonGuards(); + m_pInstance->DoUseDoorOrButton(GO_SAURFANG_DOOR, 0, false); + if (Creature* pSaurfang = GetSaurfang()) + pSaurfang->GetMotionMaster()->MovePoint(0, fPositions[1][0], fPositions[1][1], fPositions[1][2]); + NextStep(1000); + break; + } + case 2: + { + m_pInstance->DoUseDoorOrButton(GO_SAURFANG_DOOR, 0, true); + DoScriptText(SAY_INTRO_HORDE_1, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, fPositions[7][0], fPositions[7][1], fPositions[7][2]); + + // move guards + int8 n = 8; + for (GuidList::iterator i = m_lGuards.begin(); i != m_lGuards.end(); ++i) + { + if (Creature* pTmp = m_creature->GetMap()->GetCreature(*i)) + pTmp->GetMotionMaster()->MovePoint(0, fPositions[n][0], fPositions[n][1], fPositions[n][2]); + ++n; + } + NextStep(6000); + break; + } + case 3: + { + if (Creature* pSaurfang = GetSaurfang()) + DoScriptText(SAY_INTRO_HORDE_2, pSaurfang); + NextStep(13000); + break; + } + case 4: + { + DoScriptText(SAY_INTRO_HORDE_3, m_creature); + NextStep(7000); + break; + } + case 5: + { + if (Creature* pSaurfang = GetSaurfang()) + DoScriptText(SAY_INTRO_HORDE_4, pSaurfang); + NextStep(11000); + break; + } + case 6: + { + DoScriptText(SAY_INTRO_HORDE_5, m_creature); + NextStep(16000); + break; + } + case 7: + { + DoScriptText(SAY_INTRO_HORDE_6, m_creature); + NextStep(15000); + break; + } + case 8: + { + DoScriptText(SAY_INTRO_HORDE_7, m_creature); + NextStep(3000); + break; + } + case 9: + { + if (Creature* pSaurfang = GetSaurfang()) + { + float x, y, z; + pSaurfang->GetPosition(x, y, z); + + DoScriptText(SAY_INTRO_HORDE_8, m_creature); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z, false); + + // move guards + for (GuidList::iterator i = m_lGuards.begin(); i != m_lGuards.end(); ++i) + { + if (Creature* pTmp = m_creature->GetMap()->GetCreature(*i)) + { + pTmp->SetWalk(false); + pTmp->GetMotionMaster()->MovePoint(0, x, y, z, false); + pTmp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pTmp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + pSaurfang->CastSpell(pSaurfang, SPELL_GRIP_OF_AGONY, true); + } + + NextStep(1500); + break; + } + case 10: + { + float x, y, z; + // npcs float in air + m_creature->SetWalk(true); + m_creature->SetSpeedRate(MOVE_WALK, 3.0f); + m_creature->SetLevitate(true); + m_creature->GetPosition(x, y, z); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z + frand(5.0f, 7.0f)); + + // move guards + for (GuidList::iterator i = m_lGuards.begin(); i != m_lGuards.end(); ++i) + { + if (Creature* pTmp = m_creature->GetMap()->GetCreature(*i)) + { + pTmp->SetWalk(true); + pTmp->SetSpeedRate(MOVE_WALK, 3.0f); + pTmp->SetLevitate(true); + pTmp->GetPosition(x, y, z); + pTmp->GetMotionMaster()->MovePoint(0, x, y, z + frand(5.0f, 7.0f)); + } + } + if (Creature* pSaurfang = GetSaurfang()) + DoScriptText(SAY_INTRO_HORDE_9, pSaurfang); + + NextStep(10000); + break; + } + case 11: + { + if (Creature* pSaurfang = GetSaurfang()) + { + pSaurfang->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pSaurfang->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pSaurfang->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pSaurfang->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pSaurfang->SetInCombatWithZone(); + } + + NextStep(); + break; + } + case 12: + { + // fight is in progress + break; + } + case 13: + { + m_creature->HandleEmote(EMOTE_ONESHOT_NONE); + m_creature->GetMotionMaster()->MoveFall(); + + // move guards + for (GuidList::iterator i = m_lGuards.begin(); i != m_lGuards.end(); ++i) + { + if (Creature* pTmp = m_creature->GetMap()->GetCreature(*i)) + { + pTmp->HandleEmote(EMOTE_ONESHOT_NONE); + pTmp->GetMotionMaster()->MoveFall(); + } + } + NextStep(3000); + break; + } + case 14: + { + m_creature->SetLevitate(false); + m_creature->SetSpeedRate(MOVE_WALK, 1.0f); + m_creature->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); + + for (GuidList::iterator i = m_lGuards.begin(); i != m_lGuards.end(); ++i) + { + if (Creature* pGuard = m_creature->GetMap()->GetCreature(*i)) + { + pGuard->SetLevitate(false); + pGuard->SetSpeedRate(MOVE_WALK, 1.0f); + pGuard->GetMotionMaster()->MoveFollow(m_creature, frand(2.0f, 5.0f), frand(M_PI_F / 2, 1.5f * M_PI_F)); + pGuard->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); + } + } + + NextStep(1000); + break; + } + case 15: + { + DoScriptText(SAY_OUTRO_HORDE_1, m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_KNEEL); + NextStep(3000); + break; + } + case 16: + { + if (Creature* pSaurfang = GetSaurfang()) + { + float x, y, z; + pSaurfang->GetContactPoint(m_creature, x, y, z, 1.0f); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z); + } + NextStep(0); + break; + } + case 17: + { + if (Creature* pSaurfang = GetSaurfang()) + { + // wait until Overlord comes to Deathbringer + if (!m_creature->IsWithinDist(pSaurfang, 2.0f)) + return; + + m_creature->StopMoving(); + m_creature->SetFacingToObject(pSaurfang); + } + NextStep(1000); + break; + } + case 18: + { + if (Creature* pSaurfang = GetSaurfang()) + { + DoScriptText(SAY_OUTRO_HORDE_2, m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_KNEEL); + // doesnt work, invalid target (probably related to strangluating aura problem, maybe factions?) + // pSaurfang->CastSpell(m_creature, SPELL_VEHICLE_HARDCODED, true); + } + NextStep(3000); + break; + } + case 19: + { + // take deathbringer + DoScriptText(SAY_OUTRO_HORDE_3, m_creature); + NextStep(11000); + break; + } + case 20: + { + DoScriptText(SAY_OUTRO_HORDE_4, m_creature); + m_creature->GetMotionMaster()->MovePoint(0, fPositions[2][0], fPositions[2][1], fPositions[2][2], false); + NextStep(); + break; + } + case 21: + { + // wait until coming to gunship boarding place + if (!m_creature->IsWithinDist2d(fPositions[2][0], fPositions[2][1], 3.0f)) + return; + + for (GuidList::iterator i = m_lGuards.begin(); i != m_lGuards.end(); ++i) + { + if (Creature* pGuard = m_creature->GetMap()->GetCreature(*i)) + pGuard->ForcedDespawn(); + } + m_creature->ForcedDespawn(); + return; + } + default: + break; + } + } + else + m_uiNextEventTimer -= uiDiff; + } +}; + +struct MANGOS_DLL_DECL boss_deathbringer_saurfangAI : public base_icc_bossAI +{ + boss_deathbringer_saurfangAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_pInstance = ((instance_icecrown_citadel*)pCreature->GetInstanceData()); + m_powerBloodPower = m_creature->GetPowerType(); // don't call this function multiple times in script + m_bIsIntroStarted = false; + m_guidEventNpcGuid.Clear(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + uint32 m_uiRuneOfBloodTimer; + uint32 m_uiBoilingBloodTimer; + uint32 m_uiBloodNovaTimer; + uint32 m_uiBloodBeastsTimer; + uint32 m_uiScentOfBloodTimer; + uint32 m_uiBerserkTimer; + int32 m_iMarkOfFallenCount; + + bool m_bIsFrenzied; + + bool m_bIsIntroStarted; + bool m_bIsAlliance; + + Powers m_powerBloodPower; + + ObjectGuid m_guidEventNpcGuid; + + void Reset() override + { + m_uiRuneOfBloodTimer = 20000; + m_uiBoilingBloodTimer = urand(10000, 35000); + m_uiBloodNovaTimer = urand(16000, 35000); + m_uiBloodBeastsTimer = 40000; + m_uiScentOfBloodTimer = 47000; // 5 seconds after beasts engage in combat + m_uiBerserkTimer = (m_bIsHeroic ? 6 : 8) * MINUTE * IN_MILLISECONDS; + + m_bIsFrenzied = false; + + m_creature->SetPower(m_powerBloodPower, 0); + m_iMarkOfFallenCount = 0; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIsIntroStarted && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->GetDistance2d(pWho) < 50.0f) + { + m_bIsAlliance = false; //((Player*)pWho)->GetTeam() == ALLIANCE; + DoSummonEventNpc(); + m_bIsIntroStarted = true; + } + } + + void DoSummonEventNpc() + { + // main npc: Saurfang or Muradin + if (Creature* pTmp = m_creature->SummonCreature(m_bIsAlliance ? NPC_MURADIN_BRONZEBEARD : NPC_OVERLORD_SAURFANG, fPositions[2][0], fPositions[2][1], fPositions[2][2], fPositions[2][3], TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + m_guidEventNpcGuid = pTmp->GetObjectGuid(); + if (npc_highlord_saurfang_iccAI* pTmpAI = dynamic_cast(pTmp->AI())) + pTmpAI->DoStartEvent(); + } + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_DEATHBRINGER_SAURFANG, IN_PROGRESS); + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_IVE_GONE_AND_MADE_A_MESS, true); + m_iMarkOfFallenCount = 0; + } + + DoScriptText(SAY_AGGRO, m_creature); + + SetEquipmentSlots(false, EQUIP_MAIN, EQUIP_OFFHAND, EQUIP_RANGED); + + DoCastSpellIfCan(m_creature, SPELL_BLOOD_POWER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_RUNE_OF_BLOOD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_MARK_OF_FALLEN_CHAMPION, CAST_TRIGGERED); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + // Boss needs to evade to the point in front of the door + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(POINT_ID_EVADE, fPositions[1][0], fPositions[1][1], fPositions[1][2]); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + // "JustReachedHome()" + if (uiPointId == POINT_ID_EVADE) + { + m_creature->SetFacingTo(M_PI_F); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_DEATHBRINGER_SAURFANG, FAIL); + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_IVE_GONE_AND_MADE_A_MESS, false); + } + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_DEATHBRINGER_SAURFANG, DONE); + if (m_iMarkOfFallenCount > (m_bIs25Man ? 5: 3)) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_IVE_GONE_AND_MADE_A_MESS, false); + } + + m_creature->CastSpell(m_creature, SPELL_ACHIEVEMENT_CREDIT, false); + + DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_REMOVE_MARKS, CAST_TRIGGERED); + + if (Creature* pTmp = m_creature->GetMap()->GetCreature(m_guidEventNpcGuid)) + { + if (npc_highlord_saurfang_iccAI* pTmpAI = dynamic_cast(pTmp->AI())) + pTmpAI->DoContinueEvent(); + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_SLAY_1 - urand(0,1), m_creature, pVictim); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_BLOOD_BEAST) + { + pSummoned->CastSpell(pSummoned, SPELL_BLOOD_LINK_BEAST, true); + pSummoned->CastSpell(pSummoned, SPELL_RESISTANT_SKIN, true); + pSummoned->setFaction(m_creature->getFaction()); + } + } + + Player* SelectRandomPlayerForMark() + { + Player* pResult = NULL; + GuidList lPlayers; + ThreatList const& threatlist = m_creature->getThreatManager().getThreatList(); + + if (!threatlist.empty()) + { + for (ThreatList::const_iterator itr = threatlist.begin();itr != threatlist.end(); ++itr) + { + ObjectGuid const& guid = (*itr)->getUnitGuid(); + if (guid.IsPlayer() && guid != m_creature->getVictim()->GetObjectGuid()) // exclude current target + { + // check if player already has the mark + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(guid)) + { + if (!pPlayer->HasAura(SPELL_MARK_OF_FALLEN_CHAMPION_DEBUFF)) + lPlayers.push_back(guid); + } + } + } + } + + if (!lPlayers.empty()) + { + GuidList::iterator i = lPlayers.begin(); + uint32 max = uint32(lPlayers.size() - 1); + + if (max > 0) + std::advance(i, urand(0, max)); + + pResult = m_creature->GetMap()->GetPlayer(*i); + } + + // last option - current target + if (!pResult) + { + Unit* pVictim = m_creature->getVictim(); + if (pVictim && pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasAura(SPELL_MARK_OF_FALLEN_CHAMPION_DEBUFF)) + pResult = (Player*)pVictim; + } + + return pResult; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Mark of the Fallen Champion + if (m_creature->GetPower(m_powerBloodPower) >= 100) + { + if (Player* pTarget = SelectRandomPlayerForMark()) + { + if (DoCastSpellIfCan(pTarget, SPELL_MARK_OF_FALLEN_CHAMPION_DEBUFF) == CAST_OK) + { + m_creature->SetPower(m_powerBloodPower, 0); // reset Blood Power + // decrease the buff + m_creature->RemoveAurasDueToSpell(SPELL_BLOOD_POWER); + int32 power = m_creature->GetPower(m_powerBloodPower); + m_creature->CastCustomSpell(m_creature, SPELL_BLOOD_POWER, &power, &power, NULL, true); + DoScriptText(SAY_FALLENCHAMPION, m_creature); + // count mark for achievement + ++m_iMarkOfFallenCount; + } + } + } + + // Frenzy (soft enrage) + if (!m_bIsFrenzied) + { + if (m_creature->GetHealthPercent() <= 30.0f) + { + DoCastSpellIfCan(m_creature, SPELL_FRENZY, CAST_TRIGGERED); + DoScriptText(SAY_BERSERK, m_creature); + m_bIsFrenzied = true; + } + } + + // Berserk (hard enrage) + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = (m_bIsHeroic ? 6 : 8) * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiBerserkTimer -= uiDiff; + + // Rune of Blood + if (m_uiRuneOfBloodTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_RUNE_OF_BLOOD_DEBUFF) == CAST_OK) + m_uiRuneOfBloodTimer = 20000; + } + else + m_uiRuneOfBloodTimer -= uiDiff; + + // Boiling Blood + if (m_uiBoilingBloodTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BOILING_BLOOD) == CAST_OK) + m_uiBoilingBloodTimer = urand(10000, 35000); + } + else + m_uiBoilingBloodTimer -= uiDiff; + + // Boiling Blood + if (m_uiBloodNovaTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_NOVA) == CAST_OK) + m_uiBloodNovaTimer = urand(16000, 35000); + } + else + m_uiBloodNovaTimer -= uiDiff; + + // Call Blood Beasts + if (m_uiBloodBeastsTimer <= uiDiff) + { + m_creature->CastSpell(m_creature, SPELL_CALL_BLOOD_BEAST_1, true); + m_creature->CastSpell(m_creature, SPELL_CALL_BLOOD_BEAST_2, true); + + if (m_bIs25Man) + { + m_creature->CastSpell(m_creature, SPELL_CALL_BLOOD_BEAST_3, true); + m_creature->CastSpell(m_creature, SPELL_CALL_BLOOD_BEAST_4, true); + m_creature->CastSpell(m_creature, SPELL_CALL_BLOOD_BEAST_5, true); + } + + m_uiBloodBeastsTimer = 40000; + + if (m_bIsHeroic) + m_uiScentOfBloodTimer = 7000; // 5 seconds after beasts engage in combat + + DoScriptText(SAY_BLOODBEASTS, m_creature); + } + else + m_uiBloodBeastsTimer -= uiDiff; + + // Scent of Blood + if (m_bIsHeroic) + { + if (m_uiScentOfBloodTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_SCENT_OF_BLOOD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SCENT_OF_BLOOD_TRIGGERED, CAST_TRIGGERED); + m_uiScentOfBloodTimer = 40000; + // via DB + m_creature->MonsterTextEmote("Deathbringer Saurfang's Blood Beasts gain the scent of blood!", m_creature->getVictim(), true); + } + else + m_uiScentOfBloodTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_deathbringer_saurfang(Creature* pCreature) +{ + return new boss_deathbringer_saurfangAI(pCreature); +} + +CreatureAI* GetAI_npc_highlord_saurfang_icc(Creature* pCreature) +{ + return new npc_highlord_saurfang_iccAI(pCreature); +} + +CreatureAI* GetAI_npc_deathbringer_event_guards_iccAI(Creature* pCreature) +{ + return new npc_deathbringer_event_guards_iccAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_blood_beastAI : public ScriptedAI +{ + mob_blood_beastAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiScentOfBloodTimer; + uint32 m_uiReadyTimer; + + bool m_bIsReady; + + void Reset() override + { + m_uiScentOfBloodTimer = 5000; + + m_uiReadyTimer = 2000; + m_bIsReady = false; + + SetCombatMovement(false); + m_creature->SetWalk(true); + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bIsReady) + { + if (m_uiReadyTimer <= uiDiff) + { + m_bIsReady = true; + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + else + m_uiReadyTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_blood_beast(Creature* pCreature) +{ + return new mob_blood_beastAI(pCreature); +} + +void AddSC_boss_deathbringer_saurfang() +{ + Script* pNewScript; + pNewScript = new Script; + pNewScript->Name = "boss_deathbringer_saurfang"; + pNewScript->GetAI = &GetAI_boss_deathbringer_saurfang; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_highlord_saurfang_icc"; + pNewScript->GetAI = &GetAI_npc_highlord_saurfang_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_deathbringer_event_guards_iccAI"; + pNewScript->GetAI = &GetAI_npc_deathbringer_event_guards_iccAI; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_blood_beast"; + pNewScript->GetAI = &GetAI_mob_blood_beast; + 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 63c2cd908c..6c963e6d8d 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,329 @@ /* ScriptData SDName: boss_festergut -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + 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, currently not used + SPELL_GASTRIC_BLOAT_TRIG = 72219, + + // Inhale Blight + SPELL_INHALE_BLIGHT = 69165, + SPELL_INHALED_BLIGHT_10 = 69166, + SPELL_INHALED_BLIGHT_25 = 71912, + + // Pungent Blight + SPELL_PUNGENT_BLIGHT = 69195, + + // Gaseous Blight + // periodic auras spells + SPELL_GASEUS_BLIGHT_DUMMY = 69125, // gas is spread into the room on aggro + 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_SUMMON_TRIG = 72287, + SPELL_VILE_GAS = 71307, + // SPELL_VILE_GAS_TRIGGERED = 69240, + + // Malleable Goo + SPELL_MALLEABLE_GOO_SUMMON = 72299, + SPELL_MALLEABLE_GOO = 72295, + // SPELL_MALLEABLE_GOO_VISUAL = 75845, + SPELL_MALLEABLE_GOO_MISSILE = 70852, + + // other + // NPC_ORANGE_GAS_STALKER = 36659, // has dummy auras of the orange gas + // NPC_PUDDLE_STALKER = 37013, // dummy npc for initial gas flowing from pipes animation + NPC_MALLEABLE_GOO = 38556, +}; + +// talks +enum +{ + SAY_STINKY_DIES = -1631081, + SAY_AGGRO = -1631082, + SAY_BLIGHT = -1631083, + SAY_SPORE = -1631084, + SAY_PUNGUENT_BLIGHT = -1631085, + SAY_PUNGUENT_BLIGHT_EMOTE = -1631086, + SAY_SLAY_1 = -1631087, + SAY_SLAY_2 = -1631088, + SAY_BERSERK = -1631089, + SAY_DEATH = -1631090, +}; + +static LOCATION SpawnLoc[]= +{ + {4322.85f, 3164.17f, 389.40f, 3.76f}, // festergut side + {4311.91f, 3157.42f, 389.00f, 3.62f} // hacky (LoS problems?) festergut side +}; + +struct MANGOS_DLL_DECL boss_festergutAI : public base_icc_bossAI +{ + boss_festergutAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiBerserkTimer; + uint32 m_uiGastricBloatTimer; + uint32 m_uiInhaleBlightTimer; + uint32 m_uiGasSporeTimer; + uint32 m_uiVileGasTimer; + uint32 m_uiMalleableGooTimer; + + void Reset() override + { + m_uiBerserkTimer = 5 * MINUTE * IN_MILLISECONDS; + m_uiGastricBloatTimer = 10000; + m_uiInhaleBlightTimer = 30000; + m_uiGasSporeTimer = 20000; + m_uiVileGasTimer = 10000; + m_uiMalleableGooTimer = urand(15000, 20000); + } + + void Aggro(Unit* /*pWho*/) override + { + // not working as intended currently + // DoCastSpellIfCan(m_creature, SPELL_GASTRIC_BLOAT, CAST_TRIGGERED); + + DoCastSpellIfCan(m_creature, SPELL_GASEOUS_BLIGHT_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GASEUS_BLIGHT_DUMMY, CAST_TRIGGERED); + + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FESTERGUT, IN_PROGRESS); + + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + { + pProfessor->NearTeleportTo(SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, SpawnLoc[1].o); + pProfessor->SetInCombatWithZone(); + } + } + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FESTERGUT, FAIL); + + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + pProfessor->AI()->EnterEvadeMode(); + } + + DoCastSpellIfCan(m_creature, SPELL_REMOVE_INOCULENT, CAST_TRIGGERED); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FESTERGUT, DONE); + + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + pProfessor->AI()->EnterEvadeMode(); + } + + 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; + + // Gastric Bloat + if (m_uiGastricBloatTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GASTRIC_BLOAT_TRIG) == CAST_OK) + m_uiGastricBloatTimer = 10000; + } + else + m_uiGastricBloatTimer -= uiDiff; + + // Inhale Blight, Pungent Blight + if (m_uiInhaleBlightTimer <= uiDiff) + { + // check for Pungent Blight + SpellAuraHolderPtr holder = m_creature->GetSpellAuraHolder(SPELL_INHALED_BLIGHT_10); + if (!holder) + holder = m_creature->GetSpellAuraHolder(SPELL_INHALED_BLIGHT_25); + if (holder) + { + if (holder->GetStackAmount() >= 3) + { + // can't inhale anymore... + 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; + } + + return; + } + } + + 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; + + // make sure Vile Gas is not cast when players are gathered near Gas Spore + if (m_uiVileGasTimer < 12000) + m_uiVileGasTimer = 12000; + } + } + else + m_uiGasSporeTimer -= uiDiff; + + // Vile Gas + if (m_uiVileGasTimer <= uiDiff) + { + // DoCastSpellIfCan(m_creature, SPELL_VILE_GAS_SUMMON, CAST_TRIGGERED); + // DoCastSpellIfCan(m_creature, SPELL_VILE_GAS, CAST_TRIGGERED); + + if (Unit* pTarget = SelectRandomRangedTarget(m_creature)) + { + pTarget->CastSpell(pTarget, SPELL_VILE_GAS_SUMMON_TRIG, true); + DoCastSpellIfCan(m_creature, SPELL_VILE_GAS, CAST_TRIGGERED); + m_uiVileGasTimer = 30000; + } + } + else + m_uiVileGasTimer -= uiDiff; + + // Malleable Goo + if (m_bIsHeroic) + { + if (m_uiMalleableGooTimer <= uiDiff) + { + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + { + if (Unit* pTarget = SelectRandomRangedTarget(m_creature)) + { + // pProfessor->CastSpell(m_creature, SPELL_MALLEABLE_GOO_SUMMON, true); + // pProfessor->CastSpell(m_creature, SPELL_MALLEABLE_GOO, true); + + float x, y, z; + pTarget->GetPosition(x, y, z); + if (Creature* pTmp = m_creature->SummonCreature(NPC_MALLEABLE_GOO, x, y, z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000)) + { + pProfessor->CastSpell(pTmp, SPELL_MALLEABLE_GOO_MISSILE, false); + m_uiMalleableGooTimer = urand(15000, 20000); + } + } + } + } + else + m_uiMalleableGooTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_festergut(Creature* pCreature) +{ + return new boss_festergutAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_vile_gas_malleable_gooAI : public ScriptedAI +{ + mob_vile_gas_malleable_gooAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_vile_gas_malleable_goo(Creature* pCreature) +{ + return new mob_vile_gas_malleable_gooAI(pCreature); +} + +void AddSC_boss_festergut() +{ + Script* pNewScript; + pNewScript = new Script; + pNewScript->Name = "boss_festergut"; + pNewScript->GetAI = &GetAI_boss_festergut; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_vile_gas_malleable_goo"; + pNewScript->GetAI = &GetAI_mob_vile_gas_malleable_goo; + 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 e749864882..895e80f8dd 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,755 @@ /* ScriptData SDName: boss_lady_deathwhisper -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum BossSpells +{ + SPELL_BERSERK = 26662, + SPELL_INSIGNIFICANCE = 71204, + SPELL_DOMINATE_MIND = 71289, + SPELL_MANA_BARRIER = 70842, + SPELL_DEATH_AND_DECAY = 71001, + SPELL_SHADOW_BOLT = 71254, + SPELL_FROSTBOLT = 71420, + SPELL_FROSTBOLT_VOLLEY = 72905, + + // Cult Adherents + NPC_CULT_ADHERENT = 37949, + NPC_REANIMATED_ADHERENT = 38010, + NPC_DEFORMED_FANATIC = 38135, + + SPELL_FROST_FEVER = 71129, + // SPELL_SHROUD_OF_THE_OCCULT = 70768, + SPELL_DEATHCHILL_BOLT = 70594, + SPELL_DEATHCHILL_BLAST = 70906, + SPELL_CURSE_OF_TORPOR = 71237, + SPELL_DARK_EMPOWERMENT = 70901, // dummy spell: 70896 + SPELL_DARK_MARTYRDOM = 70903, + SPELL_ADHERENTS_DETERMINATION = 71234, + + // Cult Fanatic + NPC_CULT_FANATIC = 37890, + NPC_REANIMATED_FANATIC = 38009, + + SPELL_SHADOW_CLEAVE = 70670, + SPELL_NECROTIC_STRIKE = 70659, + // SPELL_VAMPIRIC_MIGHT = 70674, + SPELL_DARK_TRANSFORMATION = 70900, // dummy spell: 70895 + //SPELL_DARK_MARTYRDOM = 70903, + SPELL_FANATICS_DETERMINATION = 71235, + + // Vengeful Shade + NPC_VENGEFUL_SHADE = 38222, + // SPELL_SUMMON_SPIRIT = 71363, // not used since trigger npc is missing (something must be the target of this spell, it can't be player) + // SPELL_SUMMON_SPIRIT_TRIGGERED = 71426, + SPELL_VENGEFUL_BLAST_AURA = 71494, // must proc on melee hit + + // Achievement + SPELL_ACHIEVEMENT_CREDIT = 72827, +}; + +// talks +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, + SAY_AGGRO = -1631018, + SAY_PHASE_TWO = -1631019, + SAY_DARK_EMPOWERMENT = -1631020, + SAY_DARK_TRANSFORMATION = -1631021, + SAY_ANIMATE_DEAD = -1631022, + SAY_DOMINATE_MIND = -1631023, + SAY_BERSERK = -1631024, + SAY_DEATH = -1631025, + SAY_SLAY_1 = -1631026, + SAY_SLAY_2 = -1631027, +}; + +static LOCATION SpawnLoc[]= +{ + {-623.055481f, 2211.326660f, 51.764259f}, // 0 Lady's stay point + {-620.197449f, 2272.062256f, 50.848679f}, // 1 Right Door 1 + {-598.636353f, 2272.062256f, 50.848679f}, // 2 Right Door 2 + {-578.495728f, 2272.062256f, 50.848679f}, // 3 Right Door 3 + {-578.495728f, 2149.211182f, 50.848679f}, // 4 Left Door 1 + {-598.636353f, 2149.211182f, 50.848679f}, // 5 Left Door 2 + {-620.197449f, 2149.211182f, 50.848679f}, // 6 Left Door 3 + {-525.652466f, 2216.611328f, 62.823681f}, // 7 Upper marsh 1 + {-525.652466f, 2211.611328f, 62.823681f}, // 8 Upper marsh 2 + {-525.652466f, 2206.611328f, 62.823681f}, // 9 Upper marsh 3 +}; + +struct MANGOS_DLL_DECL boss_lady_deathwhisper_eventAI : public base_icc_bossAI +{ + boss_lady_deathwhisper_eventAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_uiStep = 0; + m_uiEventTimer = 0; + m_bIsEventStarted = false; + m_bIsEventFinished = false; + } + + uint32 m_uiStep; + uint32 m_uiEventTimer; + bool m_bIsEventStarted; + bool m_bIsEventFinished; + + void Reset() override {} + + void NextStep(uint32 uiTimer) + { + m_uiEventTimer = uiTimer; + ++m_uiStep; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIsEventStarted) + { + if (pWho->GetTypeId() == TYPEID_PLAYER) + { + m_bIsEventStarted = true; + NextStep(0); + return; + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + // for the fight handler + virtual void UpdateFightAI(const uint32 uiDiff) {} + + void UpdateAI(const uint32 uiDiff) override + { + UpdateFightAI(uiDiff); + + if (!m_bIsEventStarted || m_bIsEventFinished) + return; + + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiStep) + { + case 0: + { + break; + } + case 1: + { + DoScriptText(SAY_SPEECH_1, m_creature); + NextStep(13000); + break; + } + case 2: + { + DoScriptText(SAY_SPEECH_2, m_creature); + NextStep(11000); + break; + } + case 3: + { + DoScriptText(SAY_SPEECH_3, m_creature); + NextStep(10000); + break; + } + case 4: + { + DoScriptText(SAY_SPEECH_4, m_creature); + NextStep(9000); + break; + } + case 5: + { + DoScriptText(SAY_SPEECH_5, m_creature); + NextStep(10000); + break; + } + case 6: + { + DoScriptText(SAY_SPEECH_6, m_creature); + NextStep(10000); + break; + } + case 7: + { + DoScriptText(SAY_SPEECH_7, m_creature); + NextStep(10000); + break; + } + case 8: + { + m_bIsEventFinished = true; + break; + } + default: + break; + } + } + else + m_uiEventTimer -= uiDiff; + } +}; + +struct MANGOS_DLL_DECL boss_lady_deathwhisperAI : public boss_lady_deathwhisper_eventAI +{ + boss_lady_deathwhisperAI(Creature* pCreature) : boss_lady_deathwhisper_eventAI(pCreature) + { + m_pInstance = ((instance_icecrown_citadel*)pCreature->GetInstanceData()); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + bool m_bIsPhaseOne; + uint32 m_uiManaBarrierCheckTimer; + + bool m_bIsLeftSideSummon; + + uint32 m_uiBerserkTimer; + uint32 m_uiSummonWaveTimer; + uint32 m_uiTouchOfInsignificanceTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiDeathAndDecayTimer; + uint32 m_uiFrostboltTimer; + uint32 m_uiFrostboltVolleyTimer; + uint32 m_uiDominateMindTimer; + uint32 m_uiVengefulShadeTimer; + + uint32 m_uiMindControlCount; + std::list SummonsEntryList; + + void Reset() override + { + m_bIsPhaseOne = true; + m_bIsLeftSideSummon = true; + m_uiManaBarrierCheckTimer = 1000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiSummonWaveTimer = 10000; + m_uiTouchOfInsignificanceTimer = 0; + m_uiShadowBoltTimer = 2000; + m_uiDeathAndDecayTimer = 30000; + m_uiFrostboltTimer = urand(5000, 10000); + m_uiFrostboltVolleyTimer = 5000; + m_uiDominateMindTimer = urand(30000, 45000); + m_uiVengefulShadeTimer = 10000; + + SetCombatMovement(false); + + m_uiMindControlCount = 0; + + if (m_bIs25Man) + { + if (m_bIsHeroic) + m_uiMindControlCount = 3; // 3 targets on heroic 25man + else + m_uiMindControlCount = 1; // 1 target on normal 25man + } + else + { + if (m_bIsHeroic) + m_uiMindControlCount = 1; // 1 target on heroic 10man + } + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LADY_DEATHWHISPER, IN_PROGRESS); + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, true); + } + + // make sure that the event will not continue in the fight + m_bIsEventFinished = true; + + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MANA_BARRIER, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LADY_DEATHWHISPER, FAIL); + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, false); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LADY_DEATHWHISPER, DONE); + + // Find required NPC as achievement criteria + SummonsEntryList.clear(); + GetCreatureListWithEntryInGrid(SummonsEntryList, m_creature, NPC_CULT_ADHERENT, 250.0f); + if (SummonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, false); + + SummonsEntryList.clear(); + GetCreatureListWithEntryInGrid(SummonsEntryList, m_creature, NPC_CULT_FANATIC, 250.0f); + if (SummonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, false); + SummonsEntryList.clear(); + GetCreatureListWithEntryInGrid(SummonsEntryList, m_creature, NPC_REANIMATED_FANATIC, 250.0f); + if (SummonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, false); + + SummonsEntryList.clear(); + GetCreatureListWithEntryInGrid(SummonsEntryList, m_creature, NPC_REANIMATED_ADHERENT, 250.0f); + if (SummonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, false); + + SummonsEntryList.clear(); + GetCreatureListWithEntryInGrid(SummonsEntryList, m_creature, NPC_DEFORMED_FANATIC, 250.0f); + if (SummonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_FULL_HOUSE, false); + + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ACHIEVEMENT_CREDIT); + } + + DoScriptText(SAY_DEATH, m_creature); + } + + void KilledUnit(Unit* /*pVictim*/) + { + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->SetInCombatWithZone(); + } + + void DoSummonShade() + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_PLAYER)) + { + float x, y, z; + pTarget->GetNearPoint(pTarget, x, y, z, pTarget->GetObjectBoundingRadius(), 10.0f, frand(-M_PI_F, M_PI_F)); + + if (Creature* pShade = m_creature->SummonCreature(NPC_VENGEFUL_SHADE, x, y, z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 10000)) + { + pShade->SetSpeedRate(MOVE_RUN, 0.5f); + pShade->FixateTarget(pTarget); + pShade->AI()->AttackStart(pTarget); + pShade->CastSpell(pShade, SPELL_VENGEFUL_BLAST_AURA, true); + } + } + } + + void DoSummonWave() + { + // summoning on all sides + if (m_bIs25Man) + { + // summon 1 fanatic and 2 adherents on right side + m_creature->SummonCreature(NPC_CULT_ADHERENT, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_FANATIC, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_ADHERENT, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + + // summon 2 fanatics and 1 adherent on left side + m_creature->SummonCreature(NPC_CULT_FANATIC, SpawnLoc[4].x, SpawnLoc[4].y, SpawnLoc[4].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_ADHERENT, SpawnLoc[5].x, SpawnLoc[5].y, SpawnLoc[5].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_FANATIC, SpawnLoc[6].x, SpawnLoc[6].y, SpawnLoc[6].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + + // summon random on stairs + m_creature->SummonCreature(roll_chance_i(50) ? NPC_CULT_FANATIC : NPC_CULT_ADHERENT, SpawnLoc[8].x, SpawnLoc[8].y, SpawnLoc[8].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + // summoning on 1 side alternatively + else + { + // left side summoning + if (m_bIsLeftSideSummon) + { + // summon 1 fanatic and 2 adherents + m_creature->SummonCreature(NPC_CULT_ADHERENT, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_FANATIC, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_ADHERENT, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + else + { + // summon 2 fanatics and 1 adherent + m_creature->SummonCreature(NPC_CULT_FANATIC, SpawnLoc[4].x, SpawnLoc[4].y, SpawnLoc[4].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_ADHERENT, SpawnLoc[5].x, SpawnLoc[5].y, SpawnLoc[5].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CULT_FANATIC, SpawnLoc[6].x, SpawnLoc[6].y, SpawnLoc[6].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + + // change sides for next summoning + m_bIsLeftSideSummon = !m_bIsLeftSideSummon; + } + } + + void UpdateFightAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Berserk - both phases + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiBerserkTimer -= uiDiff; + + // Death and Decay - both phases + 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 = 30000; + } + } + else + m_uiDeathAndDecayTimer -= uiDiff; + + // Dominate Mind - both phases + if (m_uiMindControlCount) + { + if (m_uiDominateMindTimer <= uiDiff) + { + /* uncomment when spell implemented in core + for (int i = 0; i < m_uiMindControlCount; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + DoCastSpellIfCan(pTarget, SPELL_DOMINATE_MIND, CAST_TRIGGERED); + }*/ + + DoScriptText(SAY_DOMINATE_MIND, m_creature); + m_uiDominateMindTimer = 45000; + } + else + m_uiDominateMindTimer -= uiDiff; + } + + + // PHASE ONE + if (m_bIsPhaseOne) + { + // Mana Barrier check + if (m_uiManaBarrierCheckTimer <= uiDiff) + { + // phase ends when Mana Barrier wears off + if (!m_creature->HasAura(SPELL_MANA_BARRIER)) + { + DoScriptText(SAY_PHASE_TWO, m_creature); + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_bIsPhaseOne = false; + return; + } + + m_uiManaBarrierCheckTimer = 1000; + } + else + m_uiManaBarrierCheckTimer -= uiDiff; + + // Summon wave + if (m_uiSummonWaveTimer <= uiDiff) + { + DoSummonWave(); + m_uiSummonWaveTimer = 60000; + DoScriptText(SAY_ANIMATE_DEAD, m_creature); + } + else + m_uiSummonWaveTimer -= uiDiff; + + // Shadow Bolt + 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; + } + else // PHASE TWO + { + if (m_bIsHeroic) + { + // Summon wave + if (m_uiSummonWaveTimer <= uiDiff) + { + DoSummonWave(); + m_uiSummonWaveTimer = 60000; + DoScriptText(SAY_ANIMATE_DEAD, m_creature); + } + else + m_uiSummonWaveTimer -= uiDiff; + } + + // Touch of Insignificance + if (m_uiTouchOfInsignificanceTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INSIGNIFICANCE) == CAST_OK) + m_uiTouchOfInsignificanceTimer = urand(7000, 10000); + } + else + m_uiTouchOfInsignificanceTimer -= uiDiff; + + // Frostbolt + if (m_uiFrostboltTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FROSTBOLT) == CAST_OK) + m_uiFrostboltTimer = urand(5000, 10000); + } + } + else + m_uiFrostboltTimer -= uiDiff; + + // Frostbolt Volley + if (m_uiFrostboltVolleyTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FROSTBOLT_VOLLEY) == CAST_OK) + m_uiFrostboltVolleyTimer = urand(15000, 20000); + } + else + m_uiFrostboltVolleyTimer -= uiDiff; + + // Vengeful Shade + if (m_uiVengefulShadeTimer <= uiDiff) + { + DoSummonShade(); + m_uiVengefulShadeTimer = 10000; + } + else + m_uiVengefulShadeTimer -= uiDiff; + + // melee attack in 2nd phase only + DoMeleeAttackIfReady(); + } + } +}; + +CreatureAI* GetAI_boss_lady_deathwhisper(Creature* pCreature) +{ + return new boss_lady_deathwhisperAI(pCreature); +} + +// adds AI +struct MANGOS_DLL_DECL mob_cult_fanaticAI : public ScriptedAI +{ + mob_cult_fanaticAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiCleaveTimer; + uint32 m_uiNecroticStrikeTimer; + uint32 m_uiTransformationTimer; + uint32 m_uiVampiricMightTimer; + + void Reset() override + { + m_uiCleaveTimer = urand(4000, 8000); + m_uiNecroticStrikeTimer = urand(5000, 10000); + m_uiTransformationTimer = urand(20000, 60000); + m_uiVampiricMightTimer = urand(20000, 60000); + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + } + + 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_SHADOW_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(4000, 8000); + } + else + m_uiCleaveTimer -= uiDiff; + + // Necrotic Strike + if (m_uiNecroticStrikeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_NECROTIC_STRIKE) == CAST_OK) + m_uiNecroticStrikeTimer = urand(5000, 10000); + } + else + m_uiNecroticStrikeTimer -= uiDiff; + + // random transformation + if (m_uiTransformationTimer <= uiDiff) + { + if (roll_chance_i(50)) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_TRANSFORMATION) == CAST_OK) + { + m_creature->SetSpeedRate(MOVE_RUN, 0.5f); + m_uiTransformationTimer = HOUR * IN_MILLISECONDS; + } + } + else + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_MARTYRDOM) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_FANATICS_DETERMINATION, CAST_TRIGGERED); + m_uiTransformationTimer = HOUR * IN_MILLISECONDS; + } + } + } + else + m_uiTransformationTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_cult_fanatic(Creature* pCreature) +{ + return new mob_cult_fanaticAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_cult_adherentAI : public ScriptedAI +{ + mob_cult_adherentAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiTransformationTimer; + uint32 m_uiFrostFeverTimer; + uint32 m_uiShroudTimer; + uint32 m_uiDeathchillTimer; + uint32 m_uiCurseOfTorporTimer; + + void Reset() override + { + m_uiTransformationTimer = urand(20000, 60000); + m_uiCurseOfTorporTimer = urand(5000, 10000); + m_uiDeathchillTimer = urand(3000, 5000); + m_uiFrostFeverTimer = urand(5000, 10000); + m_uiShroudTimer = urand(15000, 30000); + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Frost Fever + if (m_uiFrostFeverTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FROST_FEVER) == CAST_OK) + m_uiFrostFeverTimer = urand(5000, 10000); + } + } + else + m_uiFrostFeverTimer -= uiDiff; + + // Deathchill Bolt/Blast + if (m_uiDeathchillTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_creature->HasAura(SPELL_DARK_EMPOWERMENT) ? SPELL_DEATHCHILL_BLAST : SPELL_DEATHCHILL_BOLT) == CAST_OK) + m_uiDeathchillTimer = urand(3000, 5000); + } + } + else + m_uiDeathchillTimer -= uiDiff; + + // Curse of Torpor + if (m_uiCurseOfTorporTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CURSE_OF_TORPOR) == CAST_OK) + m_uiCurseOfTorporTimer = urand(5000, 15000); + } + } + else + m_uiCurseOfTorporTimer -= uiDiff; + + // random transformation + if (m_uiTransformationTimer <= uiDiff) + { + if (roll_chance_i(50)) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_EMPOWERMENT) == CAST_OK) + m_uiTransformationTimer = HOUR * IN_MILLISECONDS; + } + else + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_MARTYRDOM) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_ADHERENTS_DETERMINATION, CAST_TRIGGERED); + m_uiTransformationTimer = HOUR * IN_MILLISECONDS; + } + } + } + else + m_uiTransformationTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_cult_adherent(Creature* pCreature) +{ + return new mob_cult_adherentAI(pCreature); +} + +void AddSC_boss_lady_deathwhisper() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lady_deathwhisper"; + pNewScript->GetAI = &GetAI_boss_lady_deathwhisper; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_cult_adherent"; + pNewScript->GetAI = &GetAI_mob_cult_adherent; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_cult_fanatic"; + pNewScript->GetAI = &GetAI_mob_cult_fanatic; + 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 b2a30aee91..3a0bf49417 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,417 @@ /* ScriptData SDName: boss_lord_marrowgar -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +// talks +enum +{ + SAY_INTRO = -1631001, + SAY_AGGRO = -1631002, + SAY_BONE_STORM = -1631003, + SAY_BONE_SPIKE_1 = -1631004, + SAY_BONE_SPIKE_2 = -1631005, + SAY_BONE_SPIKE_3 = -1631006, + SAY_SLAY_1 = -1631007, + SAY_SLAY_2 = -1631008, + SAY_DEATH = -1631009, + SAY_BERSERK = -1631010, +}; + +// spells +enum +{ + //common + SPELL_BERSERK = 47008, + + //summons + // NPC_BONE_SPIKE = 38711, + NPC_COLDFLAME = 36672, + + // Bone Slice + SPELL_BONE_SLICE_10 = 69055, + // SPELL_BONE_SLICE_25 = 70814, + + // Bone Storm + SPELL_BONE_STORM = 69076, + + // Coldflame + SPELL_COLDFLAME = 69140, // not used, hacked with custom code + SPELL_COLDFLAME_AURA = 69145, + SPELL_COLDFLAME_X = 72705, + + // Bone Spike + // SPELL_BONE_SPIKE_10 = 69057, + // SPELL_BONE_SPIKE_10_H = 72088, + SPELL_BONE_SPIKE_STORM_10 = 73144, + // SPELL_BONE_SPIKE_25 = 70826, + // SPELL_BONE_SPIKE_25_H = 72089, + // SPELL_BONE_SPIKE_STORM_25 = 73145, + + SPELL_IMPALED = 69065, + // SPELL_VEHICLE_HARDCODED = 46598, + + // phases + PHASE_NORMAL = 1, + PHASE_BONE_STORM_CHARGE = 2, + PHASE_BONE_STORM_CHARGING = 3, + PHASE_BONE_STORM_COLDFLAME = 4, + + // others + POINT_CHARGE = 1, + + MAX_CHARGES_NORMAL = 4, + MAX_CHARGES_HEROIC = 5, +}; + +/*#### +# Lord Marrowgar +####*/ +struct MANGOS_DLL_DECL boss_lord_marrowgarAI : public base_icc_bossAI +{ + boss_lord_marrowgarAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + m_bSaidIntro = false; + m_uiMaxCharges = m_bIsHeroic ? MAX_CHARGES_HEROIC : MAX_CHARGES_NORMAL; + + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + bool m_bSaidIntro; + + 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_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiBoneSliceTimer = 10000; + m_uiColdflameTimer = 5000; + m_uiBoneSpikeTimer = 12000; + m_uiBoneStormTimer = 45000; + m_uiBoneStormChargeTimer = 3000; + m_uiBoneStormColdflameTimer = 1000; + + m_uiChargesCount = 0; + + m_creature->SetSpeedRate(MOVE_RUN, 1.0f); + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_BONED, true); + } + + void MoveInLineOfSight(Unit* pWho) override + { + ScriptedAI::MoveInLineOfSight(pWho); + + if (m_bSaidIntro) + return; + + DoScriptText(SAY_INTRO, m_creature); + m_bSaidIntro = true; + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_MARROWGAR, FAIL); + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_BONED, false); + } + } + + void Aggro(Unit* /*pWho*/) override + { + if(!m_pInstance) + return; + + m_creature->SetInCombatWithZone(); + m_pInstance->SetData(TYPE_MARROWGAR, IN_PROGRESS); + DoScriptText(SAY_AGGRO, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature, pVictim); + } + + void JustDied(Unit* /*pKiller*/) override + { + if(m_pInstance) + m_pInstance->SetData(TYPE_MARROWGAR, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_COLDFLAME) + { + float x, y, z = pSummoned->GetPositionZ(); + m_creature->GetNearPoint2D(x, y, 120.0f, m_creature->GetAngle(pSummoned)); + + pSummoned->CastSpell(pSummoned, SPELL_COLDFLAME_AURA, true); + pSummoned->SetSpeedRate(MOVE_WALK, 2.0f); // should be via DB + pSummoned->GetMotionMaster()->MovePoint(0, x, y, z, false); + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (uiPointId == POINT_CHARGE) + { + m_uiPhase = PHASE_BONE_STORM_COLDFLAME; + ++m_uiChargesCount; + } + } + + 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_TRIGGERED) == CAST_OK) + { + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + DoScriptText(SAY_BERSERK, m_creature); + } + } + else + m_uiBerserkTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_NORMAL: + { + // Coldflame (regular) + 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) + { + SetCombatMovement(false); + m_uiBoneStormTimer = 90000; + m_uiPhase = PHASE_BONE_STORM_CHARGE; + m_creature->SetSpeedRate(MOVE_RUN, 3.0f); + DoScriptText(SAY_BONE_STORM, m_creature); + } + } + else + m_uiBoneStormTimer -= uiDiff; + + // Bone Slice + if (m_uiBoneSliceTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BONE_SLICE_10) == 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)) + { + float x, y, z; + pTarget->GetPosition(x, y, z); + m_creature->GetMotionMaster()->MovePoint(POINT_CHARGE, x, y, z); + 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_X) == CAST_OK) + { + m_uiBoneStormColdflameTimer = 1000; + + if (m_uiChargesCount >= m_uiMaxCharges) + { + m_creature->RemoveAurasDueToSpell(SPELL_BONE_STORM); + m_creature->InterruptSpell(CURRENT_MELEE_SPELL); // Bone Slice related + m_uiBoneSliceTimer = 10000; + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiChargesCount = 0; + m_uiPhase = PHASE_NORMAL; + m_creature->SetSpeedRate(MOVE_RUN, 1.0f); + return; + } + else + m_uiPhase = PHASE_BONE_STORM_CHARGE; + } + } + else + m_uiBoneStormColdflameTimer -= uiDiff; + + break; + } + } + + // Bone Spike - on heroic in every phase + if (m_bIsHeroic || m_uiPhase == PHASE_NORMAL) + { + if (m_uiBoneSpikeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BONE_SPIKE_STORM_10) == CAST_OK) + { + m_uiBoneSpikeTimer = urand(20000, 30000); + DoScriptText(SAY_BONE_SPIKE_1 - urand(0, 2), m_creature); + } + } + else + m_uiBoneSpikeTimer -= uiDiff; + } + } +}; + +/*#### +# Coldflame +####*/ +struct MANGOS_DLL_DECL mob_coldflameAI : public ScriptedAI +{ + mob_coldflameAI(Creature* pCreature) : ScriptedAI(pCreature){} + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +/*#### +# Bone Spike +####*/ +struct MANGOS_DLL_DECL mob_bone_spikeAI : public ScriptedAI +{ + mob_bone_spikeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((instance_icecrown_citadel*)pCreature->GetInstanceData()); + m_victimGuid.Clear(); + m_bEmerged = false; + SetCombatMovement(false); + } + + instance_icecrown_citadel* m_pInstance; + bool m_bEmerged; + ObjectGuid m_victimGuid; + uint32 m_uiEmpaledTime; + + void Reset() override + { + m_uiEmpaledTime = 0; + } + + void AttackStart(Unit* /*pWho*/) override {} + + void JustDied(Unit* /*Killer*/) override + { + if (Unit* pCreator = m_creature->GetCreator()) + { + pCreator->RemoveAurasDueToSpell(SPELL_IMPALED); + m_creature->ForcedDespawn(); + } + + if (m_pInstance && m_uiEmpaledTime > 8000) + m_pInstance->SetSpecialAchievementCriteria(ACHIEVE_BONED, false); + } + + void UpdateAI(const uint32 uiDiff) override + { + m_uiEmpaledTime += uiDiff; + + if (!m_bEmerged) + { + m_creature->HandleEmote(EMOTE_ONESHOT_EMERGE); + m_bEmerged = true; + } + } +}; + +CreatureAI* GetAI_mob_bone_spike(Creature* pCreature) +{ + return new mob_bone_spikeAI(pCreature); +} + +CreatureAI* GetAI_mob_coldflame(Creature* pCreature) +{ + return new mob_coldflameAI(pCreature); +} + +CreatureAI* GetAI_boss_lord_marrowgar(Creature* pCreature) +{ + return new boss_lord_marrowgarAI(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 = "mob_coldflame"; + pNewScript->GetAI = &GetAI_mob_coldflame; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_bone_spike"; + pNewScript->GetAI = &GetAI_mob_bone_spike; + 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 deef0ffa85..88c90cf0f5 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,974 @@ /* ScriptData SDName: boss_professor_putricide -SD%Complete: 0% -SDComment: +SD%Complete: 95% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" +#include "Vehicle.h" + +enum BossSpells +{ + 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, + SPELL_VOLATILE_EXPERIMENT = 72842, // heroic + 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_1 = 71615, + SPELL_TEAR_GAS = 71617, + SPELL_TEAR_GAS_2 = 71618, + SPELL_TEAR_GAS_PERIODIC_AURA = 73170, + 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, + + NPC_GREEN_ORANGE_OOZE_STALKER = 37824, // casts orange and green visual spell and then summons add + NPC_GROWING_OOZE_PUDDLE = 37690, + NPC_GROWING_OOZE_PUDDLE_TRIG = 38234, + NPC_CHOKING_GAS_BOMB = 38159, + NPC_VOLATILE_OOZE = 37697, + NPC_MUTATED_ABOMINATION_1 = 37672, + NPC_MUTATED_ABOMINATION_2 = 38285, + NPC_MALLEABLE_GOO = 38556, + +/* + SPELL_OOZE_GAS_PROTECTION = 70812, + SPELL_OOZE_BEAM_PROTECTION = 71530, + SPELL_OOZE_TANK_PROTECTION = 71770, + + SPELL_ORANGE_RADIATION = 45857, //Additional visual + + QUEST_24749 = 71518, + SHADOW_INFUSION_AURA = 71516, + + VIEW_1 = 30881, + VIEW_2 = 30881, + VIEW_3 = 30993, +*/ +}; + +// talks +enum +{ + SAY_AGGRO = -1631092, + SAY_AIRLOCK = -1631093, + SAY_PHASE_CHANGE = -1631094, + SAY_TRANSFORM_1 = -1631095, + SAY_TRANSFORM_2 = -1631096, + SAY_SLAY_1 = -1631097, + SAY_SLAY_2 = -1631098, + SAY_BERSERK = -1631099, + SAY_DEATH = -1631100, + + // during other fights + SAY_SLIME_FLOW_1 = -1631074, + SAY_SLIME_FLOW_2 = -1631075, + SAY_BLIGHT = -1631083, + SAY_FESTERGUT_DEATH = -1631091, + SAY_ROTFACE_DEATH = -1631080, +}; + +static LOCATION SpawnLoc[]= +{ + {4356.779785f, 3263.510010f, 389.398010f, 1.586f}, // 0 Putricide start point o=1.586 + {4295.081055f, 3188.883545f, 389.330261f, 4.270f}, // 1 Puticide Festergut say, o=4.27 + {4417.302246f, 3188.219971f, 389.332520f, 5.102f}, // 2 Putricide Rotface say o=5.102 + {4388.1f, 3213.29f, 408.7399f, 3.8397f}, // 3 Ooze stalker - green + {4324.7212f, 3214.6428f, 408.7399f, 5.5764f}, // 4 Ooze stalker - orange +}; + +#define POINT_PUTRICIDE_SPAWN 1 + +enum Phases +{ + PHASE_ONE, + PHASE_RUNNING_ONE, + PHASE_TRANSITION_ONE, + PHASE_TWO, + PHASE_RUNNING_TWO, + PHASE_TRANSITION_TWO, + PHASE_THREE +}; + +/** + * boss_professor_putricide + */ +struct MANGOS_DLL_DECL boss_professor_putricideAI : public base_icc_bossAI +{ + boss_professor_putricideAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiPhase; + + uint32 m_uiHealthCheckTimer; + uint32 m_uiTransitionTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiPuddleTimer; + uint32 m_uiUnstableExperimentTimer; + uint32 m_uiMalleableGooTimer; + uint32 m_uiChokingGasBombTimer; + uint32 m_uiMutatedPlagueTimer; + uint32 m_uiUnboundPlagueTimer; + + // used to determine whether he is assisting one of his pupils or having his own encounter + bool m_bIsAssistingOnly; + + bool m_bIsGreenOoze; // green or orange ooze to summon + + std::list SummonEntryList; + + void Reset() override + { + m_uiPhase = PHASE_ONE; + m_bIsAssistingOnly = false; + SetCombatMovement(true); + + m_bIsGreenOoze = true; // first ooze summoned is always green + + m_uiHealthCheckTimer = 1000; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiPuddleTimer = 10000; + m_uiUnstableExperimentTimer = 20000; + m_uiMalleableGooTimer = 5000; + m_uiChokingGasBombTimer = urand(10000, 15000); + m_uiMutatedPlagueTimer = 0; + m_uiUnboundPlagueTimer = 10000; + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (m_bIsAssistingOnly) + uiDamage = 0; + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_FESTERGUT) == IN_PROGRESS || m_pInstance->GetData(TYPE_ROTFACE) == IN_PROGRESS) + { + SetCombatMovement(false, true); + m_bIsAssistingOnly = true; + return; + } + + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, IN_PROGRESS); + DoScriptText(SAY_AGGRO, m_creature); + // Make table interactable + if (GameObject* pGOTable = m_pInstance->GetSingleGameObjectFromStorage(GO_DRINK_ME_TABLE)) + pGOTable->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, DONE); + + DoScriptText(SAY_DEATH, m_creature); + + DoRemoveBossEffects(); + } + + void DoRemoveMutatedAmobination(bool bRestoreTable) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const& players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + if (pPlayer->GetVehicle()) + pPlayer->ExitVehicle(); + } + } + + if (m_pInstance) + { + if (GameObject* pGOTable = m_pInstance->GetSingleGameObjectFromStorage(GO_DRINK_ME_TABLE)) + { + if (bRestoreTable) + pGOTable->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + else + pGOTable->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + } + } + } + + void DoRemoveBossEffects() + { + DoRemoveMutatedAmobination(false); + + SummonEntryList.clear(); + GetCreatureListWithEntryInGrid(SummonEntryList, m_creature, NPC_GROWING_OOZE_PUDDLE, 100.0f); + + for (std::list::iterator itr = SummonEntryList.begin(); itr != SummonEntryList.end(); ++itr) + { + if ((*itr)->isAlive()) + (*itr)->ForcedDespawn(); + } + + Map* pMap = m_creature->GetMap(); + Map::PlayerList const& players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + pPlayer->RemoveAurasDueToSpell(SPELL_GAS_VARIABLE); + pPlayer->RemoveAurasDueToSpell(SPELL_GAS_VARIABLE_GAS); + pPlayer->RemoveAurasDueToSpell(SPELL_MUTATED_PLAGUE); + } + } + } + + void JustReachedHome() override + { + if (m_pInstance && !m_bIsAssistingOnly) + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, FAIL); + + if (VehicleKitPtr pKit = m_creature->GetVehicleKit()) + { + pKit->RemoveAllPassengers(); + pKit->Reset(); + } + + // some weird bug with not regenerating health after wipe ;/ + m_creature->SetHealth(m_creature->GetMaxHealth()); + DoRemoveBossEffects(); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE || uiData != POINT_PUTRICIDE_SPAWN) + return; + if (m_uiPhase != PHASE_RUNNING_ONE && m_uiPhase != PHASE_RUNNING_TWO) + return; + + if (m_bIsHeroic) + { + DoScriptText(SAY_PHASE_CHANGE, m_creature); + m_uiTransitionTimer = 30000; + } + else + { + DoCastSpellIfCan(m_creature, m_uiPhase == PHASE_RUNNING_ONE ? SPELL_CREATE_CONCOCTION : SPELL_GUZZLE_POTIONS); + DoScriptText(m_uiPhase == PHASE_RUNNING_ONE ? SAY_TRANSFORM_1 : SAY_TRANSFORM_2, m_creature); + m_uiTransitionTimer = 15000; + } + + // counter for entering next phase + m_uiPhase = m_uiPhase == PHASE_RUNNING_ONE ? PHASE_TRANSITION_ONE : PHASE_TRANSITION_TWO; + } + + void DoExperiment(bool green, bool orange) + { + if (green) + { + if (m_creature->SummonCreature(NPC_GREEN_ORANGE_OOZE_STALKER, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z, SpawnLoc[3].o, TEMPSUMMON_TIMED_DESPAWN, 10000)) + DoCastSpellIfCan(m_creature, SPELL_GREEN_OOZE_SUMMON, CAST_TRIGGERED); + } + + if (orange) + { + if (m_creature->SummonCreature(NPC_GREEN_ORANGE_OOZE_STALKER, SpawnLoc[4].x, SpawnLoc[4].y, SpawnLoc[4].z, SpawnLoc[4].o, TEMPSUMMON_TIMED_DESPAWN, 10000)) + DoCastSpellIfCan(m_creature, SPELL_ORANGE_OOZE_SUMMON, CAST_TRIGGERED); + } + + // variable + if (green && orange && m_bIs25Man) + DoVariable(); + } + + void DoVariable() + { + bool bToggle = true; + + Map::PlayerList const& players = m_creature->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + if (!pPlayer->GetVehicle() && pPlayer->isAlive()) + { + pPlayer->CastSpell(pPlayer, bToggle ? SPELL_GAS_VARIABLE : SPELL_OOZE_VARIABLE, true); + bToggle = !bToggle; + } + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (!m_creature->isInCombat()) + return; + if (pSummoned->GetEntry() != NPC_GREEN_ORANGE_OOZE_STALKER) + pSummoned->SetInCombatWithZone(); + } + + void UpdateSlimePuddle(const uint32 uiDiff) + { + if (m_uiPuddleTimer <= uiDiff) + { + for (uint8 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; + } + + void UpdateUnstableExperiment(const uint32 uiDiff) + { + if (m_uiUnstableExperimentTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNSTABLE_EXPERIMENT) == CAST_OK) + { + DoExperiment(m_bIsGreenOoze, !m_bIsGreenOoze); + m_uiUnstableExperimentTimer = 30000; + m_bIsGreenOoze = !m_bIsGreenOoze; + } + } + else + m_uiUnstableExperimentTimer -= uiDiff; + } + + void UpdateUnboundPlague(const uint32 uiDiff) + { + if (!m_bIsHeroic) + return; + 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; + } + + void UpdateSwitchPhaseIntro(const uint32 uiDiff) + { + if (!m_pInstance) + return; + + if (m_uiHealthCheckTimer <= uiDiff) + { + float fSwitchHealthPercent = m_uiPhase == PHASE_ONE ? 80.0f : 35.0f; + if (m_creature->GetHealthPercent() <= fSwitchHealthPercent) + { + SetCombatMovement(false, true); + if (m_bIsHeroic) + { + DoCastSpellIfCan(m_creature, SPELL_VOLATILE_EXPERIMENT); + DoExperiment(true, true); + DoScriptText(SAY_PHASE_CHANGE, m_creature); + } + else + { + DoCastSpellIfCan(m_creature, SPELL_TEAR_GAS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TEAR_GAS_1, CAST_TRIGGERED); + } + + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, SPECIAL); + + m_uiPhase = m_uiPhase == PHASE_ONE ? PHASE_RUNNING_ONE : PHASE_RUNNING_TWO; + m_creature->GetMotionMaster()->MovePoint(POINT_PUTRICIDE_SPAWN, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z); + + if (m_uiPhase == PHASE_RUNNING_TWO) + DoRemoveMutatedAmobination(false); + } + m_uiHealthCheckTimer = 1000; + } + else + m_uiHealthCheckTimer -= uiDiff; + } + + void UpdateMalleableGoo(const uint32 uiDiff) + { + if (m_uiMalleableGooTimer <= uiDiff) + { + for (uint8 i = 0; i < (m_bIs25Man ? 2 : 1); ++i) + { + if (Unit* pTarget = SelectRandomRangedTarget(m_creature)) + { + float x, y, z; + pTarget->GetPosition(x, y, z); + if (Creature* pTrigger = m_creature->SummonCreature(NPC_MALLEABLE_GOO, x, y, z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000)) + { + m_creature->CastSpell(pTrigger, SPELL_MALLEABLE_GOO_MISSILE, true); + m_uiMalleableGooTimer = 20000; + } + } + } + } + else + m_uiMalleableGooTimer -= uiDiff; + } + + void UpdateChokingGasBomb(const uint32 uiDiff) + { + if (m_uiChokingGasBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CHOKING_GAS_BOMB) == CAST_OK) + m_uiChokingGasBombTimer = urand(25000, 30000); + } + else + m_uiChokingGasBombTimer -= uiDiff; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bIsAssistingOnly) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Enrage + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiEnrageTimer = 30 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiEnrageTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_ONE: + { + UpdateSlimePuddle(uiDiff); + UpdateUnstableExperiment(uiDiff); + UpdateUnboundPlague(uiDiff); + UpdateSwitchPhaseIntro(uiDiff); + break; + } + case PHASE_TWO: + { + UpdateSlimePuddle(uiDiff); + UpdateUnstableExperiment(uiDiff); + UpdateUnboundPlague(uiDiff); + UpdateMalleableGoo(uiDiff); + UpdateChokingGasBomb(uiDiff); + UpdateSwitchPhaseIntro(uiDiff); + break; + } + case PHASE_THREE: + { + UpdateSlimePuddle(uiDiff); + UpdateMalleableGoo(uiDiff); + UpdateChokingGasBomb(uiDiff); + UpdateUnboundPlague(uiDiff); + + // Mutated Plague (proc cooldown for creatures doesn't work) + if (m_uiMutatedPlagueTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MUTATED_PLAGUE) == CAST_OK) + m_uiMutatedPlagueTimer = 10000; + } + else + m_uiMutatedPlagueTimer -= uiDiff; + + break; + } + case PHASE_TRANSITION_ONE: + case PHASE_TRANSITION_TWO: + { + if (m_uiTransitionTimer <= uiDiff) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, IN_PROGRESS); + + if (m_bIsHeroic) + { + DoCastSpellIfCan(m_creature, m_uiPhase == PHASE_TRANSITION_ONE ? SPELL_CREATE_CONCOCTION : SPELL_GUZZLE_POTIONS); + DoScriptText(m_uiPhase == PHASE_TRANSITION_ONE ? SAY_TRANSFORM_1 : SAY_TRANSFORM_2, m_creature); + } + else + DoCastSpellIfCan(m_creature, SPELL_TEAR_GAS_CANCEL, CAST_TRIGGERED); + + m_uiPhase = m_uiPhase == PHASE_TRANSITION_ONE ? PHASE_TWO : PHASE_THREE; + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true, true); + } + else + m_uiTransitionTimer -= uiDiff; + + return; + } + case PHASE_RUNNING_ONE: + case PHASE_RUNNING_TWO: + // wait for arriving at the table (during phase transition) + return; + } + + DoMeleeAttackIfReady(); + } +}; +CreatureAI* GetAI_boss_professor_putricide(Creature* pCreature) +{ + return new boss_professor_putricideAI(pCreature); +} + +/** + * mob_icc_gas_cloud + */ +struct MANGOS_DLL_DECL mob_icc_gas_cloudAI : public base_icc_bossAI +{ + mob_icc_gas_cloudAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_bIsVariable = false; + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_PROFESSOR_PUTRICIDE) == SPECIAL) + { + DoCastSpellIfCan(m_creature, SPELL_GAS_VARIABLE_GAS, CAST_TRIGGERED); + m_bIsVariable = true; + } + } + m_creature->SetSpeedRate(MOVE_RUN, 1.0f); + Reset(); + } + + uint32 m_uiMoveTimer; + bool m_bIsVariable; + + void Reset() override + { + m_uiMoveTimer = 0; + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_GASEOUS_BLOAT_VISUAL, CAST_TRIGGERED); + DoSelectTarget(); + m_creature->SetInCombatWithZone(); + } + + void DamageTaken(Unit* pDealer, uint32& uiDamage) override + { + if (!m_bIsVariable) + return; + if (pDealer->HasAuraOfDifficulty(SPELL_GAS_VARIABLE)) + { + uiDamage = 0; + return; + } + + // remove variable debuffs + if (uiDamage >= m_creature->GetHealth()) + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + + for (ThreatList::const_iterator itr = tList.begin(); itr != tList.end(); ++itr) + { + if (!(*itr)->getUnitGuid().IsPlayer()) + continue; + + if (Unit* pPlayer = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + pPlayer->RemoveAurasDueToSpell(SPELL_GAS_VARIABLE); + } + } + } + + void DoSelectTarget() + { + if (!m_pInstance) + return; + m_creature->FixateTarget(NULL); // Clear target + if (Creature* pProf = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + { + Unit* pTarget = NULL; + + pTarget = pProf->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_GASEOUS_BLOAT, SELECT_FLAG_PLAYER); + if (!pTarget) + pTarget = pProf->getVictim(); + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, SPELL_GASEOUS_BLOAT) == CAST_OK) + m_creature->FixateTarget(pTarget); + } + } + m_uiMoveTimer = 3000; // 3 sec cast + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance) + { + uint32 uiData = m_pInstance->GetData(TYPE_PROFESSOR_PUTRICIDE); + if (uiData != IN_PROGRESS && uiData != SPECIAL) + m_creature->ForcedDespawn(); + if (!m_bIsVariable && uiData == SPECIAL) + { + if (IsCombatMovement()) + SetCombatMovement(false, true); + m_uiMoveTimer = 1; + } + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || !m_creature->GetFixatedTarget()) + { + DoSelectTarget(); + return; + } + + if (m_uiMoveTimer) + { + if (m_uiMoveTimer <= uiDiff) + { + SetCombatMovement(true, true); + m_uiMoveTimer = 0; + } + else + m_uiMoveTimer -= uiDiff; + } + + if (!m_uiMoveTimer && m_creature->GetDistance(m_creature->getVictim()) <= 4.0f) + { + m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_EXPUNGED_GAS, true); + m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); + SetCombatMovement(false, true); + DoSelectTarget(); + } + } +}; + +CreatureAI* GetAI_mob_icc_gas_cloud(Creature* pCreature) +{ + return new mob_icc_gas_cloudAI(pCreature); +} + +/** + * mob_icc_volatile_ooze + */ +struct MANGOS_DLL_DECL mob_icc_volatile_oozeAI : public base_icc_bossAI +{ + mob_icc_volatile_oozeAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_bIsVariable = false; + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_PROFESSOR_PUTRICIDE) == SPECIAL) + { + DoCastSpellIfCan(m_creature, SPELL_OOZE_VARIABLE_OOZE, CAST_TRIGGERED); + m_bIsVariable = true; + } + } + m_creature->SetSpeedRate(MOVE_RUN, 1.0f); + Reset(); + } + + uint32 m_uiMoveTimer; + bool m_bIsVariable; + + void Reset() override + { + m_uiMoveTimer = 0; + SetCombatMovement(false); + DoSelectTarget(); + m_creature->SetInCombatWithZone(); + } + + void DamageTaken(Unit* pDealer, uint32& uiDamage) override + { + if (!m_bIsVariable) + return; + if (pDealer->HasAuraOfDifficulty(SPELL_OOZE_VARIABLE)) + { + uiDamage = 0; + return; + } + + // remove variable debuffs + if (uiDamage >= m_creature->GetHealth()) + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + + for (ThreatList::const_iterator itr = tList.begin(); itr != tList.end(); ++itr) + { + if (!(*itr)->getUnitGuid().IsPlayer()) + continue; + + if (Unit* pTmp = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + pTmp->RemoveAurasDueToSpell(SPELL_OOZE_VARIABLE); + } + } + } + + void DoSelectTarget() + { + if (!m_pInstance) + return; + m_creature->FixateTarget(NULL); // Clear target + if (Creature* pProf = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + { + Unit* pTarget = NULL; + + pTarget = pProf->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_OOZE_ADHESIVE, SELECT_FLAG_PLAYER); + if (!pTarget) + pTarget = pProf->getVictim(); + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, SPELL_OOZE_ADHESIVE) == CAST_OK) + { + m_creature->FixateTarget(pTarget); + m_uiMoveTimer = 3000; // 3 sec cast + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance) + { + uint32 uiData = m_pInstance->GetData(TYPE_PROFESSOR_PUTRICIDE); + if (uiData != IN_PROGRESS && uiData != SPECIAL) + m_creature->ForcedDespawn(); + if (!m_bIsVariable && uiData == SPECIAL) + { + if (IsCombatMovement()) + SetCombatMovement(false, true); + m_uiMoveTimer = 1; + return; + } + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || !m_creature->GetFixatedTarget()) + { + DoSelectTarget(); + return; + } + + if (m_uiMoveTimer) + { + if (m_uiMoveTimer <= uiDiff) + { + SetCombatMovement(true, true); + m_uiMoveTimer = 0; + } + else + m_uiMoveTimer -= uiDiff; + } + + if (!m_uiMoveTimer && m_creature->GetDistance(m_creature->getVictim()) <= 4.0f) + { + m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); + DoCastSpellIfCan(m_creature, SPELL_OOZE_ERUPTION); + SetCombatMovement(false, true); + DoSelectTarget(); + } + } +}; +CreatureAI* GetAI_mob_icc_volatile_ooze(Creature* pCreature) +{ + return new mob_icc_volatile_oozeAI(pCreature); +} + +// passive mob AI struct +struct MANGOS_DLL_DECL mob_choking_gas_bombAI : public ScriptedAI +{ + mob_choking_gas_bombAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + pCreature->CastSpell(pCreature, SPELL_CHOKING_GAS_BOMB_AURA, true); + pCreature->CastSpell(pCreature, SPELL_CHOKING_GAS_BOMB_EXPL_AUR, true); + pCreature->ForcedDespawn(12000); + } + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } +}; + +CreatureAI* GetAI_mob_choking_gas_bomb(Creature* pCreature) +{ + return new mob_choking_gas_bombAI(pCreature); +} + +// passive mob AI struct +struct MANGOS_DLL_DECL mob_ooze_puddleAI : public ScriptedAI +{ + mob_ooze_puddleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetObjectScale(0.2f); + DoCastSpellIfCan(m_creature, SPELL_GROW_STACKER, CAST_TRIGGERED); + m_creature->CastSpell(m_creature, SPELL_SLIME_PUDDLE_AURA, true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + } + + ScriptedInstance* m_pInstance; + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_pInstance) + { + uint32 data = m_pInstance->GetData(TYPE_PROFESSOR_PUTRICIDE); + if (data == SPECIAL) + { + // don't grow while Putricide is mutating between phases + return; + } + else if (data != IN_PROGRESS) + m_creature->ForcedDespawn(); + } + } +}; +CreatureAI* GetAI_mob_ooze_puddle(Creature* pCreature) +{ + return new mob_ooze_puddleAI(pCreature); +} + +// mob Mutated Abomination +struct MANGOS_DLL_DECL mob_mutated_amobinationAI : public ScriptedAI +{ + mob_mutated_amobinationAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() override + { + m_creature->SetPower(POWER_ENERGY, 0); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_PROFESSOR_PUTRICIDE) != DONE) + { + // Possibly remove GO_FLAG_NO_INTERACT when amob dies is not blizz-like + if (GameObject* pGOTable = m_pInstance->GetSingleGameObjectFromStorage(GO_DRINK_ME_TABLE)) + pGOTable->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + } + } +}; + +CreatureAI* GetAI_mob_mutated_amobination(Creature* pCreature) +{ + return new mob_mutated_amobinationAI(pCreature); +} + +// GO Drink Me! +bool GOUse_go_drink_me(Player* pPlayer, GameObject* pGameObject) +{ + pGameObject->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + pPlayer->CastSpell(pPlayer, SPELL_MUTATED_TRANSFORMATION, true); + return true; +} + +void AddSC_boss_professor_putricide() +{ + Script* pNewScript; + pNewScript = new Script; + pNewScript->Name = "boss_professor_putricide"; + pNewScript->GetAI = &GetAI_boss_professor_putricide; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_icc_volatile_ooze"; + pNewScript->GetAI = &GetAI_mob_icc_volatile_ooze; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_icc_gas_cloud"; + pNewScript->GetAI = &GetAI_mob_icc_gas_cloud; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_choking_gas_bomb"; + pNewScript->GetAI = &GetAI_mob_choking_gas_bomb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_ooze_puddle"; + pNewScript->GetAI = &GetAI_mob_ooze_puddle; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_mutated_amobination"; + pNewScript->GetAI = &GetAI_mob_mutated_amobination; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_drink_me"; + pNewScript->pGOUse = &GOUse_go_drink_me; + 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 58ec9f0c92..b384ffb824 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,488 @@ /* ScriptData SDName: boss_rotface -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum BossSpells +{ + SPELL_BERSERK = 47008, + + // 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, + 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, + 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 + + // Vile Gas (heroic) + // SPELL_VILE_GAS_SUMMON = 72288, + SPELL_VILE_GAS_SUMMON_TRIG = 72287, + SPELL_VILE_GAS = 71307, + // SPELL_VILE_GAS_TRIGGERED = 72272, + + // others + // NPC_PUDDLE_STALKER = 37013, + // NPC_LITTLE_OOZE = 36897, + // NPC_BIG_OOZE = 36899, +}; + +static uint32 uiMutatedInfections[5] = +{ + SPELL_MUTATED_INFECTION_1, + SPELL_MUTATED_INFECTION_2, + SPELL_MUTATED_INFECTION_3, + SPELL_MUTATED_INFECTION_4, + SPELL_MUTATED_INFECTION_5 +}; + +//talks +enum +{ + SAY_PRECIOUS_DIES = -1631070, + SAY_AGGRO = -1631071, + SAY_SLIME_SPRAY = -1631072, + SAY_OOZE_EXPLODE = -1631073, + SAY_SLIME_FLOW_1 = -1631074, + SAY_SLIME_FLOW_2 = -1631075, + SAY_SLAY_1 = -1631076, + SAY_SLAY_2 = -1631077, + SAY_BERSERK = -1631078, + SAY_DEATH = -1631079, +}; + +static LOCATION SpawnLoc[]= +{ + {4391.38f, 3163.71f, 389.40f, 5.8f} // rotface side +}; + +// Rotface +struct MANGOS_DLL_DECL boss_rotfaceAI : public base_icc_bossAI +{ + boss_rotfaceAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiSlimeSprayTimer; + uint32 m_uiMutatedInfectionTimer; + uint32 m_uiMutatedInfectionBeforeTimer; + uint32 m_uiInfectionsRate; + uint32 m_uiVileGasTimer; + uint32 m_uiSlimeFlowTimer; + + void Reset() override + { + m_uiSlimeSprayTimer = urand(17000, 23000); + m_uiVileGasTimer = 20000; + m_uiMutatedInfectionTimer = m_uiMutatedInfectionBeforeTimer = 60000; + m_uiInfectionsRate = 1; + m_uiSlimeFlowTimer = 20000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_ROTFACE, IN_PROGRESS); + + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + { + pProfessor->NearTeleportTo(SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, SpawnLoc[0].o); + pProfessor->SetInCombatWithZone(); + } + } + + 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); + + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + pProfessor->AI()->EnterEvadeMode(); + } + + DoCastSpellIfCan(m_creature, SPELL_OOZE_FLOOD_REMOVE, CAST_TRIGGERED); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature, pVictim); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_ROTFACE, DONE); + + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + pProfessor->AI()->EnterEvadeMode(); + } + + 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_SUMMON, CAST_TRIGGERED) == CAST_OK) + { + 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 < 5) + { + if (m_uiMutatedInfectionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, uiMutatedInfections[m_uiInfectionsRate], CAST_TRIGGERED) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(uiMutatedInfections[m_uiInfectionsRate - 1]); + m_uiMutatedInfectionBeforeTimer = m_uiMutatedInfectionBeforeTimer - 10000; // every next 15 seconds faster + m_uiMutatedInfectionTimer = m_uiMutatedInfectionBeforeTimer; + ++m_uiInfectionsRate; + } + } + else + m_uiMutatedInfectionTimer -= uiDiff; + } + + // Vile Gas + if (m_bIsHeroic) + { + if (m_uiVileGasTimer <= uiDiff) + { + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + { + if (Unit* pTarget = SelectRandomRangedTarget(m_creature)) + { + if (DoCastSpellIfCan(pTarget, SPELL_VILE_GAS_SUMMON_TRIG, CAST_TRIGGERED) == CAST_OK) + { + pProfessor->CastSpell(pProfessor, SPELL_VILE_GAS, true); + m_uiVileGasTimer = 20000; + } + } + } + } + else + m_uiVileGasTimer -= uiDiff; + } + + // Slime Flow + if (m_uiSlimeFlowTimer <= uiDiff) + { + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + DoScriptText(SAY_SLIME_FLOW_1 - urand(0, 1), pProfessor); + + m_uiSlimeFlowTimer = 20000; + } + else + m_uiSlimeFlowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_rotface(Creature* pCreature) +{ + return new boss_rotfaceAI(pCreature); +} + +// all passive dummy NPCs +struct MANGOS_DLL_DECL mob_rotface_ooze_dummyAI : public ScriptedAI +{ + mob_rotface_ooze_dummyAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + if (pCreature->GetEntry() == 37986) + pCreature->ForcedDespawn(10000); + } + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_rotface_ooze_dummy(Creature* pCreature) +{ + return new mob_rotface_ooze_dummyAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_little_oozeAI : public ScriptedAI +{ + mob_little_oozeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiStickyOozeTimer; + + void Reset() override + { + m_uiStickyOozeTimer = 5000; + } + + void Aggro(Unit* pWho) override + { + m_creature->FixateTarget(pWho); + m_creature->SetInCombatWithZone(); + m_creature->SetSpeedRate(MOVE_RUN, 0.5f); + 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_pInstance && m_pInstance->GetData(TYPE_ROTFACE) != IN_PROGRESS) + { + m_creature->ForcedDespawn(); + return; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_creature->GetFixatedTarget()) + m_creature->FixateTarget(m_creature->getVictim()); + + 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 MANGOS_DLL_DECL mob_big_oozeAI : public ScriptedAI +{ + mob_big_oozeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiStickyOozeTimer; + uint32 m_uiCheckTimer; + bool m_bHasSaid; + + void Reset() override + { + m_uiStickyOozeTimer = 5000; + m_uiCheckTimer = 1000; + m_bHasSaid = false; + } + + void Aggro(Unit* pWho) override + { + m_creature->SetInCombatWithZone(); + m_creature->AddThreat(pWho, 500000.0f); + m_creature->SetSpeedRate(MOVE_RUN, 0.5f); + 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_pInstance && m_pInstance->GetData(TYPE_ROTFACE) != IN_PROGRESS) + { + m_creature->ForcedDespawn(); + return; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Unstable Ooze + if (!m_bHasSaid) + { + if (m_uiCheckTimer <= uiDiff) + { + if (SpellAuraHolderPtr holder = m_creature->GetSpellAuraHolder(SPELL_UNSTABLE_OOZE)) + { + if (holder->GetStackAmount() >= 5) + { + if (m_pInstance) + { + if (Creature* pRotface = m_pInstance->GetSingleCreatureFromStorage(NPC_ROTFACE)) + { + DoScriptText(SAY_OOZE_EXPLODE, pRotface); + m_bHasSaid = true; + } + } + } + } + m_uiCheckTimer = 1000; + } + else + m_uiCheckTimer -= 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); +} + +// Ooze explosion stalker +struct MANGOS_DLL_DECL mob_ooze_explosion_stalkerAI : public ScriptedAI +{ + mob_ooze_explosion_stalkerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pCreature->ForcedDespawn(10000); + } + void Reset() override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_ooze_explosion_stalker(Creature* pCreature) +{ + return new mob_ooze_explosion_stalkerAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_sticky_oozeAI : public ScriptedAI +{ + mob_sticky_oozeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + SetCombatMovement(false); + pCreature->CastSpell(pCreature, SPELL_STICKY_AURA, true); + pCreature->ForcedDespawn(30000); + } + + ScriptedInstance* m_pInstance; + + void Reset() override {} + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_ROTFACE) != IN_PROGRESS) + { + m_creature->ForcedDespawn(); + return; + } + } +}; + +CreatureAI* GetAI_mob_sticky_ooze(Creature* pCreature) +{ + return new mob_sticky_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_rotface_ooze_dummy"; + pNewScript->GetAI = &GetAI_mob_rotface_ooze_dummy; + 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(); + + pNewScript = new Script; + pNewScript->Name = "mob_sticky_ooze"; + pNewScript->GetAI = &GetAI_mob_sticky_ooze; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_ooze_explosion_stalker"; + pNewScript->GetAI = &GetAI_mob_ooze_explosion_stalker; + 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 f89bd8b31f..6ab715d9b7 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,977 @@ /* ScriptData SDName: boss_sindragosa -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum BossSpells +{ + // Sindragosa + SPELL_BERSERK = 26662, + + // Phase 1 + SPELL_TAIL_SMASH = 71077, + SPELL_CLEAVE = 19983, + SPELL_FROST_AURA = 70084, + SPELL_FROST_BREATH = 69649, + SPELL_ICY_GRIP = 70117, + // SPELL_BLISTERING_COLD = 70123, + SPELL_PERMEATING_CHILL = 70109, + SPELL_UNCHAINED_MAGIC = 69762, + SPELL_INSTABILITY = 69766, + // SPELL_BACKLASH = 69770, // deals dmg basing on Instability stacks + + // Phase 2 + + // Ice Tomb related + SPELL_FROST_BEACON = 70126, + SPELL_ICE_TOMB = 69712, // used by Sindragosa, targets marked units and triggers on them 69675? + // SPELL_ICE_TOMB_DUMMY = 69675, // orb flows to the target, dummy effect (triggering the summoning of GO?) + SPELL_ICE_TOMB_TRIGGERED = 70157, // this is the effect of stun etc. + // SPELL_ICE_TOMB_TRIGGERED2 = 69700, // additional effects of immunity to frost and being unattackable/unhealable + // SPELL_ASPHYXIATION = 71665, + + // Frost Bomb related + SPELL_FROST_BOMB = 69846, + 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 Sindragosa + + // Phase 3 + SPELL_MYSTIC_BUFFET = 70128, + + // NPCs + // NPC_ICE_TOMB = 36980, + // NPC_FROST_BOMB = 37186, + + GO_ICE_BLOCK = 201722, + + // Rimefang + SPELL_RIMEFANG_FROST_AURA = 71387, + SPELL_RIMEFANG_ICY_BLAST = 71376, + SPELL_RIMEFANG_FROST_BREATH = 71386, + + // Spinestalker + SPELL_SPINESTALKER_BELLOWING_ROAR = 36922, + SPELL_SPINESTALKER_CLEAVE = 40505, + SPELL_SPINESTALKER_TAIL_SWEEP = 71369 +}; + +// talks +enum +{ + SAY_AGGRO = -1631148, + SAY_UNCHAINED_MAGIC = -1631149, + SAY_BLISTERING_COLD = -1631150, + SAY_RESPIRE = -1631151, + SAY_TAKEOFF = -1631152, + SAY_PHASE_3 = -1631153, + SAY_SLAY_1 = -1631154, + SAY_SLAY_2 = -1631155, + SAY_BERSERK = -1631156, + SAY_DEATH = -1631157, +}; + +static LOCATION SindragosaLoc[]= +{ + {4423.037598f, 2484.436523f, 203.373642f}, // 0 Sindragosa ground airport + {4474.239746f, 2484.243896f, 231.000000f}, // 1 Sindragosa fly o=3.11 + {4474.239746f, 2484.243896f, 203.380402f}, // 2 Sindragosa fly - ground point o=3.11 + {4505.000000f, 2484.243896f, 231.000000f}, // 3 Sindragosa spawn point + {4448.000000f, 2469.243896f, 203.374207f}, // 4 Rimefang land point + {4448.000000f, 2497.243896f, 203.374207f}, // 5 Spinestalker land point +}; + +enum Phase +{ + PHASE_OOC = 0, + PHASE_GROUND = 1, + PHASE_FLYING = 2, + PHASE_AIR = 3, + PHASE_THREE = 4 +}; + +enum Point +{ + POINT_OOC, + POINT_LAND_HOVER_AGGRO, + POINT_LAND_HOVER, + POINT_LAND, + POINT_AIR, + + POINT_SPINESTALKER_LAND, + POINT_RIMEFANG_LAND +}; + +#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 + +struct MANGOS_DLL_DECL boss_sindragosaAI : public base_icc_bossAI +{ + boss_sindragosaAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + pCreature->SetSpeedRate(MOVE_RUN, 1.2f); + SetCombatMovement(false); + SetLevitate(true); + Reset(); + } + + Phase 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_uiFlyingTimer; + uint32 m_uiFrostBeaconTimer; + uint32 m_uiIceTombTimer; + uint32 m_uiFrostBombTimer; + uint8 m_uiFrostBombCount; + + void Reset() override + { + m_uiPhase = PHASE_OOC; + m_uiPhaseTimer = 53000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiCleaveTimer = urand(5000, 15000); + m_uiTailSmashTimer = 20000; + m_uiFrostBreathTimer = 5000; + m_uiIcyGripTimer = 35000; + m_uiUnchainedMagicTimer = urand(15000, 30000); + m_uiIceTombTimer = 0; // Disable + + m_uiFlyingTimer = 60000; // debug code + } + + void SetLevitate(bool bLevitate) + { + if (bLevitate) + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + else + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + + m_creature->SetLevitate(bLevitate); + } + + void EnterEvadeMode() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_SINDRAGOSA, FAIL); + RemoveAurasFromAllPlayers(); + } + m_creature->SummonCreature(NPC_SINDRAGOSA, SindragosaLoc[3].x, SindragosaLoc[3].y, SindragosaLoc[3].z, 3.17f, TEMPSUMMON_DEAD_DESPAWN, 0, true); + m_creature->ForcedDespawn(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_creature->isInCombat()) + { + if (pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster()) + { + if (pWho->IsWithinDistInMap(m_creature, 60.0f)) + AttackStart(pWho); + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SINDRAGOSA, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->SetWalk(false); + m_creature->SetInCombatWithZone(); + m_creature->GetMotionMaster()->MovePoint(POINT_LAND_HOVER_AGGRO, SindragosaLoc[0].x, SindragosaLoc[0].y, SindragosaLoc[0].z + 17.0f, false); + m_uiPhase = PHASE_FLYING; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_SINDRAGOSA, DONE); + RemoveAurasFromAllPlayers(); + } + + DoScriptText(SAY_DEATH, m_creature); + } + + void RemoveAurasFromAllPlayers() + { + Map::PlayerList const& players = m_creature->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + pPlayer->RemoveAurasDueToSpell(SPELL_FROST_BEACON); + pPlayer->RemoveAurasDueToSpell(SPELL_UNCHAINED_MAGIC); + pPlayer->RemoveAurasDueToSpell(SPELL_INSTABILITY); + pPlayer->RemoveAurasDueToSpell(SPELL_FROST_BREATH); + pPlayer->RemoveAurasDueToSpell(SPELL_MYSTIC_BUFFET); + } + } + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + switch (uiData) + { + case POINT_LAND_HOVER_AGGRO: + { + DoCastSpellIfCan(m_creature, SPELL_FROST_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PERMEATING_CHILL, CAST_TRIGGERED); + // no break + } + case POINT_LAND_HOVER: + { + m_creature->SetSpeedRate(MOVE_RUN, 10.0f); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + m_creature->GetMotionMaster()->MovePoint(POINT_LAND, SindragosaLoc[0].x, SindragosaLoc[0].y, SindragosaLoc[0].z, false); + if (uiData == POINT_LAND_HOVER) + m_uiPhaseTimer = 65000; + break; + } + case POINT_LAND: + { + m_creature->SetSpeedRate(MOVE_RUN, 1.2f); + m_creature->SetLevitate(false); + SetCombatMovement(true, true); + m_uiPhase = PHASE_GROUND; + break; + } + case POINT_AIR: + { + m_uiPhase = PHASE_AIR; + + uint8 uiMax = m_bIs25Man ? 5 : 2; + if (m_bIs25Man && m_bIsHeroic) + uiMax = 6; + + DoMark(uiMax); + + m_uiFrostBombTimer = 7000; + m_uiFrostBombCount = 0; + m_uiPhaseTimer = 35000; + break; + } + } + } + + void DoMark(uint8 uiCount) + { + m_uiIceTombTimer = 1000; + // get threat list + std::list targetUnitList; + const ThreatList& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if (!(*itr)->getUnitGuid().IsPlayer()) + continue; + + if (m_creature->getVictim() && + (*itr)->getUnitGuid() == m_creature->getVictim()->GetObjectGuid()) + { + continue; + } + + if (Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + targetUnitList.push_back(pUnit); + } + + // random targets + while (targetUnitList.size() > uiCount) + { + uint32 poz = urand(0, targetUnitList.size() - 1); + for (std::list::iterator itr = targetUnitList.begin(); itr != targetUnitList.end(); ++itr, --poz) + { + if (!*itr) continue; + + if (!poz) + { + targetUnitList.erase(itr); + break; + } + } + } + + // cast + for (std::list::iterator itr = targetUnitList.begin(); itr != targetUnitList.end(); ++itr) + { + if (Unit* pTarget = (*itr)) + m_creature->CastSpell(pTarget, SPELL_FROST_BEACON, true); + } + } + + void UpdateCleave(const uint32 uiDiff) + { + if (m_uiCleaveTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(5000, 15000); + } + else + m_uiCleaveTimer -= uiDiff; + } + + void UpdateTailSmash(const uint32 uiDiff) + { + if (m_uiTailSmashTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_SMASH) == CAST_OK) + m_uiTailSmashTimer = urand(10000, 20000); + } + else + m_uiTailSmashTimer -= uiDiff; + } + + void UpdateFrostBreath(const uint32 uiDiff) + { + if (m_uiFrostBreathTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_BREATH) == CAST_OK) + m_uiFrostBreathTimer = urand(15000, 20000); + } + else + m_uiFrostBreathTimer -= uiDiff; + } + + void UpdateUnchainedMagic(const uint32 uiDiff) + { + if (m_uiUnchainedMagicTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNCHAINED_MAGIC) == CAST_OK) + { + m_uiUnchainedMagicTimer = urand(40000, 60000); + if (m_uiPhase == PHASE_GROUND) + DoScriptText(SAY_UNCHAINED_MAGIC, m_creature); + } + } + else + m_uiUnchainedMagicTimer -= uiDiff; + } + + void UpdateIcyGrip(const uint32 uiDiff) + { + if (m_uiIcyGripTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ICY_GRIP) == CAST_OK) + { + DoScriptText(SAY_BLISTERING_COLD, m_creature); + m_uiIcyGripTimer = 70000; + } + } + else + m_uiIcyGripTimer -= uiDiff; + } + + void UpdateIceTomb(const uint32 uiDiff) + { + if (m_uiIceTombTimer) + { + if (m_uiIceTombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ICE_TOMB) == CAST_OK) + m_uiIceTombTimer = 0; + } + else + m_uiIceTombTimer -= uiDiff; + } + } + + void UpdateFrostBeacon(const uint32 uiDiff) + { + if (m_uiFrostBeaconTimer <= uiDiff) + { + if (Unit* pVictim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_FROST_BEACON, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pVictim, SPELL_FROST_BEACON) == CAST_OK) + { + m_uiFrostBeaconTimer = 15000; + m_uiIceTombTimer = 1000; + } + } + } + else + m_uiFrostBeaconTimer -= uiDiff; + } + + void UpdateFrostBomb(const uint32 uiDiff) + { + if (m_uiFrostBombCount == 4) + return; + if (m_uiFrostBombTimer <= uiDiff) + { + 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 = SindragosaLoc[0].z; + m_creature->CastSpell(x, y, z, SPELL_FROST_BOMB, false); + ++m_uiFrostBombCount; + m_uiFrostBombTimer = 6000; + } + else + m_uiFrostBombTimer -= uiDiff; + } + + 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 = 10 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiBerserkTimer -= uiDiff; + + switch (m_uiPhase) + { + case PHASE_GROUND: + { + // Health Check + if (m_creature->GetHealthPercent() <= 35.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_MYSTIC_BUFFET, CAST_TRIGGERED) == CAST_OK) + { + m_uiPhase = PHASE_THREE; + DoScriptText(SAY_PHASE_3, m_creature); + m_uiFrostBeaconTimer = 10000; + return; + } + } + + // Phase 2 (air) + if (m_uiPhaseTimer <= uiDiff) + { + if (m_creature->GetHealthPercent() <= 85.0f) + { + m_uiPhase = PHASE_FLYING; + DoScriptText(SAY_TAKEOFF, m_creature); + + SetCombatMovement(false, true); + SetLevitate(true); + m_creature->NearTeleportTo(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 17.0f, m_creature->GetOrientation()); + // fly to the air point + m_creature->GetMotionMaster()->MovePoint(POINT_AIR, SindragosaLoc[1].x, SindragosaLoc[1].y, SindragosaLoc[1].z, false); + m_uiFlyingTimer = 60000; + } + } + else + m_uiPhaseTimer -= uiDiff; + + UpdateCleave(uiDiff); + UpdateTailSmash(uiDiff); + UpdateFrostBreath(uiDiff); + UpdateUnchainedMagic(uiDiff); + UpdateIcyGrip(uiDiff); + + DoMeleeAttackIfReady(); + break; + } + case PHASE_THREE: + { + UpdateCleave(uiDiff); + UpdateTailSmash(uiDiff); + UpdateFrostBreath(uiDiff); + UpdateUnchainedMagic(uiDiff); + UpdateIcyGrip(uiDiff); + + UpdateFrostBeacon(uiDiff); + UpdateIceTomb(uiDiff); + + DoMeleeAttackIfReady(); + break; + } + case PHASE_FLYING: + { + // wait for arrival or evade after 60seconds + if (m_uiFlyingTimer <= uiDiff) + { + m_uiFlyingTimer = 60000; + EnterEvadeMode(); + } + else + m_uiFlyingTimer -= uiDiff; + + break; + } + case PHASE_AIR: + { + UpdateIceTomb(uiDiff); + UpdateFrostBomb(uiDiff); + + // Phase One (ground) + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = PHASE_FLYING; + // fly to the ground point + m_creature->GetMotionMaster()->MovePoint(POINT_LAND_HOVER, SindragosaLoc[0].x, SindragosaLoc[0].y, SindragosaLoc[0].z + 17.0f, false); + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + } + } +}; + +CreatureAI* GetAI_boss_sindragosa(Creature* pCreature) +{ + return new boss_sindragosaAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_ice_tombAI : public ScriptedAI +{ + mob_ice_tombAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + m_uiCheckTimer = 1000; + m_IceBlockGUID = ObjectGuid(); + if (GameObject* pIceBlock = pCreature->SummonGameobject(GO_ICE_BLOCK, pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ(), 0.0f, 0)) + m_IceBlockGUID = pIceBlock->GetObjectGuid(); + } + + uint32 m_uiCheckTimer; + ObjectGuid m_IceBlockGUID; + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + + void JustDied(Unit* /*pKiller*/) override + { + if (GameObject* pIceBlock = m_creature->GetMap()->GetGameObject(m_IceBlockGUID)) + pIceBlock->Delete(); + + if (Unit* pCreator = m_creature->GetCreator()) + { + pCreator->RemoveAurasDueToSpell(SPELL_ICE_TOMB_TRIGGERED); + m_creature->ForcedDespawn(5000); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiCheckTimer <= uiDiff) + { + if (Unit* pCreator = m_creature->GetCreator()) + { + if (!pCreator->isAlive()) + { + pCreator->RemoveAurasDueToSpell(SPELL_ICE_TOMB_TRIGGERED); + if (GameObject* pIceBlock = m_creature->GetMap()->GetGameObject(m_IceBlockGUID)) + pIceBlock->Delete(); + m_creature->ForcedDespawn(); + } + } + m_uiCheckTimer = 1000; + } + else + m_uiCheckTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_ice_tomb(Creature* pCreature) +{ + return new mob_ice_tombAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_frost_bombAI : public ScriptedAI +{ + mob_frost_bombAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_FROST_BOMB_VISUAL, CAST_TRIGGERED); + m_uiFrostBombTimer = 6000; + } + + uint32 m_uiFrostBombTimer; + + void Reset() override {} + + void AttackStart(Unit* /*pWho*/) override {} + + void UpdateAI(const uint32 uiDiff) override + { + // Frost Bomb (dmg) + if (m_uiFrostBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FROST_BOMB_DMG) == CAST_OK) + { + m_creature->ForcedDespawn(1000); + m_uiFrostBombTimer = 20000; + } + } + else + m_uiFrostBombTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_frost_bomb(Creature* pCreature) +{ + return new mob_frost_bombAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_rimefangAI : public ScriptedAI +{ + mob_rimefangAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsFlying; + + uint32 m_uiFrostBreathTimer; + uint32 m_uiIcyBlastTimer; + + void Reset() override + { + m_creature->SetRespawnDelay(7*DAY*IN_MILLISECONDS); + + m_uiFrostBreathTimer = urand(5000, 8000); + m_uiIcyBlastTimer = urand(4000, 8000); + m_bIsFlying = true; + } + + void SetLevitate(bool bLevitate) + { + if (bLevitate) + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + else + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + + m_creature->SetLevitate(bLevitate); + } + + void EnterEvadeMode() override + { + SetLevitate(true); + if (Creature* pBrother = m_pInstance->GetSingleCreatureFromStorage(NPC_SPINESTALKER)) + { + if (!pBrother->isAlive()) + pBrother->Respawn(); + } + ScriptedAI::EnterEvadeMode(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_creature->isInCombat()) + { + if (pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster()) + { + if (pWho->IsWithinDistInMap(m_creature, 60.0f)) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + AttackStart(pWho); + } + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + if (Creature* pBrother = m_pInstance->GetSingleCreatureFromStorage(NPC_SPINESTALKER)) + pBrother->SetInCombatWithZone(); + } + + DoCastSpellIfCan(m_creature, SPELL_RIMEFANG_FROST_AURA, CAST_TRIGGERED); + m_creature->GetMotionMaster()->MovePoint(POINT_RIMEFANG_LAND, SindragosaLoc[4].x, SindragosaLoc[4].y, SindragosaLoc[4].z, false); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_RIMEFANG_LAND) + { + if (m_creature->getVictim()) + { + SetLevitate(false); + m_bIsFlying = false; + SetCombatMovement(true); + } + else + EnterEvadeMode(); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + if (Creature* pBrother = m_pInstance->GetSingleCreatureFromStorage(NPC_SPINESTALKER)) + { + if (!pBrother->isAlive() && m_pInstance->GetData(TYPE_SINDRAGOSA) != DONE) + { + if (Creature* pSindr = m_creature->SummonCreature(NPC_SINDRAGOSA, SindragosaLoc[3].x, SindragosaLoc[3].y, SindragosaLoc[3].z, 3.17f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 7*DAY*IN_MILLISECONDS, true)) + { + pSindr->SetCreatorGuid(ObjectGuid()); + pSindr->SetInCombatWithZone(); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bIsFlying || !m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // 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 + if (m_uiIcyBlastTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_RIMEFANG_ICY_BLAST, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_RIMEFANG_ICY_BLAST) == CAST_OK) + m_uiIcyBlastTimer = urand(4000, 8000); + } + } + else + m_uiIcyBlastTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + + +CreatureAI* GetAI_mob_rimefang(Creature* pCreature) +{ + return new mob_rimefangAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_spinestalkerAI : public ScriptedAI +{ + mob_spinestalkerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsFlying; + + uint32 m_uiBellowingRoarTimer; + uint32 m_uiTailSweepTimer; + uint32 m_uiCleaveTimer; + + void Reset() override + { + m_creature->SetRespawnDelay(7*DAY*IN_MILLISECONDS); + + m_uiBellowingRoarTimer = urand(8000, 24000); + m_uiTailSweepTimer = urand(4000, 8000); + m_uiCleaveTimer = urand(5000, 8000); + m_bIsFlying = true; + } + + void SetLevitate(bool bLevitate) + { + if (bLevitate) + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + else + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + + m_creature->SetLevitate(bLevitate); + } + + void EnterEvadeMode() override + { + SetLevitate(true); + if (Creature* pBrother = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG)) + { + if (!pBrother->isAlive()) + pBrother->Respawn(); + } + ScriptedAI::EnterEvadeMode(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_creature->isInCombat()) + { + if (pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster()) + { + if (pWho->IsWithinDistInMap(m_creature, 60.0f)) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + AttackStart(pWho); + } + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + if (Creature* pBrother = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG)) + pBrother->SetInCombatWithZone(); + } + + m_creature->GetMotionMaster()->MovePoint(POINT_SPINESTALKER_LAND, SindragosaLoc[5].x, SindragosaLoc[5].y, SindragosaLoc[5].z, false); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_SPINESTALKER_LAND) + { + if (m_creature->getVictim()) + { + SetLevitate(false); + m_bIsFlying = false; + SetCombatMovement(true); + } + else + EnterEvadeMode(); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + if (Creature* pBrother = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG)) + { + if (!pBrother->isAlive() && m_pInstance->GetData(TYPE_SINDRAGOSA) != DONE) + { + if (Creature* pSindr = m_creature->SummonCreature(NPC_SINDRAGOSA, SindragosaLoc[3].x, SindragosaLoc[3].y, SindragosaLoc[3].z, 3.17f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 7*DAY*IN_MILLISECONDS, true)) + { + pSindr->SetCreatorGuid(ObjectGuid()); + pSindr->SetInCombatWithZone(); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bIsFlying || !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_mob_spinestalker(Creature* pCreature) +{ + return new mob_spinestalkerAI(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 = "mob_rimefang"; + pNewScript->GetAI = &GetAI_mob_rimefang; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_spinestalker"; + pNewScript->GetAI = &GetAI_mob_spinestalker; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_ice_tomb"; + pNewScript->GetAI = &GetAI_mob_ice_tomb; + 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 1e5775b0cc..018af00018 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -14,11 +14,2697 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData +/** +ScriptData SDName: boss_the_lich_king -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel -EndScriptData */ +*/ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum BossSpells +{ + 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_SUMMON_BROKEN_FROSTMOURNE = 72406, + 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, + SPELL_REMORSELESS_WINTER_2 = 72259, + 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 = 72679, // 10man N + SPELL_HARVESTED_SOUL_2 = 74319, // 10man H + SPELL_HARVESTED_SOUL_3 = 74318, // 25man N + SPELL_HARVESTED_SOUL_4 = 74320, // 25man H + + 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, +}; + +// talks +enum +{ + SAY_INTRO_1 = -1631158, + SAY_INTRO_2 = -1631159, + SAY_INTRO_3 = -1631160, + SAY_INTRO_4 = -1631161, + SAY_INTRO_5 = -1631162, + SAY_AGGRO = -1631163, + SAY_REMORSELESS_WINTER = -1631164, + SAY_SHATTER_ARENA = -1631165, + SAY_SUMMON_VALKYR = -1631166, + SAY_HARVEST_SOUL = -1631167, + SAY_FM_TERENAS_AID_1 = -1631168, + SAY_FM_TERENAS_AID_2 = -1631169, + SAY_FM_TERENAS_AID_3 = -1631170, + SAY_FM_PLAYER_ESCAPE = -1631171, + SAY_FM_PLAYER_DEATH = -1631172, + SAY_SPECIAL_1 = -1631173, + SAY_SPECIAL_2 = -1631174, + SAY_LAST_PHASE = -1631175, + SAY_SLAY_1 = -1631176, + SAY_SLAY_2 = -1631177, + SAY_ENRAGE = -1631178, + SAY_OUTRO_1 = -1631179, + SAY_OUTRO_2 = -1631180, + SAY_OUTRO_3 = -1631181, + SAY_OUTRO_4 = -1631182, + SAY_OUTRO_5 = -1631183, + SAY_OUTRO_6 = -1631184, + SAY_OUTRO_7 = -1631185, + SAY_OUTRO_8 = -1631186, + SAY_OUTRO_9 = -1631187, + SAY_OUTRO_10 = -1631188, + SAY_OUTRO_11 = -1631189, + SAY_OUTRO_12 = -1631190, + SAY_OUTRO_13 = -1631191, + SAY_OUTRO_14 = -1631192, +}; + +enum Common +{ + FINAL_ARTHAS_MOVIE = 16, + EQUIP_FROSTMOURNE = 49706, +}; + +enum Phase +{ + PHASE_ONE, // phase one + PHASE_RUNNING_WINTER_ONE, // running to center of platform to cast Remorseless Winter + PHASE_WINTER_ONE, // Remorseless Winter aura and casting spells, summoning orbs and spirits + PHASE_QUAKE_ONE, // casting Quake + PHASE_TWO, // phase two with val'kyrs and some more spells + PHASE_RUNNING_WINTER_TWO, // running to center of platform to cast Remorseless Winter again + PHASE_WINTER_TWO, // second Remorseless Winter phase + PHASE_QUAKE_TWO, // second Quake casting + PHASE_THREE, // phase three, casting Soul Harvest (Frostmourne phase) + PHASE_IN_FROSTMOURNE, // phase three, waiting untill whole raid leaves Frostmourne + PHASE_CUTSCENE, // phase when LK kills raid, Terenas comes etc. + PHASE_DEATH_AWAITS, // strangulating Lich King, raid group finishing him +}; + +enum +{ + POINT_TIRION_INTRO, + POINT_TIRION_OUTRO, + POINT_CENTER_LAND_LICH_KING, + POINT_VALKYR_THROW, + POINT_VALKYR_CENTER, + POINT_TP_TO_FM, // point where strangulate vehicle moves, after reaching player is teleported into frostmourne + POINT_SPIRIT_BOMB, // Spirit Bomb moving down +}; + +static LOCATION SpawnLoc[] = +{ + {463.0f, -2124.0f, 840.86f}, // 0 Lich King Intro + {503.15652f, -2124.516602f, 840.86f}, // 1 Center of the platform + {451.32f, -2087.85f, 840.86f}, // 2 Val'kyr drop point right to Frozen Throne + {449.60f, -2161.71f, 840.86f}, // 3 Val'kyr drop point left to Frozen Throne + {494.313f, -2523.079f, 1049.87f} // 4 center of platform inside Frostmourne +}; + +static LOCATION TirionLoc[] = +{ + {489.5f, -2125.0f, 840.86f}, // 0 POINT_TIRION_INTRO + {495.0f, -2124.516602f, 840.86f}, // 1 POINT_TIRION_OUTRO + {529.85302f, -2124.709961f, 840.86f}, // 2 Teleporter +}; + +#define GOSSIP_TIRION_START_EVENT "We are prepared, Highlord. Let us battle for the fate of Azeroth! For the light of dawn!" + +/** + * Tirion + */ +struct MANGOS_DLL_DECL boss_tirion_iccAI : public base_icc_bossAI +{ + boss_tirion_iccAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint8 m_uiEventStep; + uint32 m_uiEventTimer; + ObjectGuid m_guidTerenas; + ObjectGuid m_guidFrostmourne; + + bool m_bDebuggingEvent; + + void Reset() override + { + m_uiEventTimer = 0; + m_guidTerenas.Clear(); + m_guidFrostmourne.Clear(); + m_bDebuggingEvent = false; + if (m_pInstance && m_pInstance->GetData(TYPE_LICH_KING) != DONE) + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + else + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void EnterEvadeMode() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + base_icc_bossAI::EnterEvadeMode(); + } + } + + void JustReachedHome() override + { + Reset(); + } + + void DoSetDebuggingEvent(bool bStatus) + { + m_bDebuggingEvent = bStatus; + } + + void DoStartEvent() + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->MovePoint(POINT_TIRION_INTRO, TirionLoc[0].x, TirionLoc[0].y, TirionLoc[0].z, false); + } + + void DoPauseEvent() + { + m_uiEventTimer = 0; + } + + void DoNextEventStep(uint32 uiTimer = 1) + { + ++m_uiEventStep; + m_uiEventTimer = uiTimer; + } + + void DoLichKingText(int32 iText) + { + if (m_pInstance) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + DoScriptText(iText, pLichKing); + } + } + + void DoLichKingEmote(uint32 uiEmote) + { + if (m_pInstance) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + pLichKing->HandleEmote(uiEmote); + } + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + switch (uiData) + { + case POINT_TIRION_INTRO: + { + m_uiEventStep = 0; + m_uiEventTimer = 2000; + break; + } + case POINT_TIRION_OUTRO: + { + m_creature->GetMotionMaster()->Clear(); + m_creature->MonsterMoveToDestination(SpawnLoc[1].x + 8.0f, SpawnLoc[1].y, SpawnLoc[1].z, m_creature->GetOrientation(), 8.0f, 05.0f); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SPECIALATTACK1H); + DoNextEventStep(1500); + break; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_uiEventTimer == 0) + return; + + // events + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiEventStep) + { + case 0: + { + SetCombatMovement(false); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + if (m_creature->Attack(pLichKing, true)) + { + m_creature->AddThreat(pLichKing); + m_creature->SetInCombatWith(pLichKing); + } + pLichKing->SetWalk(true); + pLichKing->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + pLichKing->SetStandState(UNIT_STAND_STATE_STAND); + pLichKing->GetMotionMaster()->MovePoint(0, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z); + } + DoLichKingText(SAY_INTRO_1); + DoNextEventStep(14000); + break; + } + case 1: + { + DoScriptText(SAY_INTRO_2, m_creature); + DoNextEventStep(7000); + break; + } + case 2: + { + DoLichKingText(SAY_INTRO_3); + DoNextEventStep(4000); + break; + } + case 3: + { + DoLichKingEmote(EMOTE_ONESHOT_SHOUT); + DoNextEventStep(4000); + break; + } + case 4: + { + DoLichKingEmote(EMOTE_ONESHOT_POINT); + DoNextEventStep(4000); + break; + } + case 5: + { + DoLichKingEmote(EMOTE_ONESHOT_SHOUT); + DoNextEventStep(10000); + break; + } + case 6: + { + DoScriptText(SAY_INTRO_4, m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_POINT); + DoNextEventStep(4000); + break; + } + case 7: + { + SetCombatMovement(true, true); + DoNextEventStep(1000); + break; + } + case 8: + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + pLichKing->CastSpell(m_creature, SPELL_ICE_LOCK, false); + DoScriptText(SAY_INTRO_5, pLichKing); + } + DoNextEventStep(1000); + break; + } + case 9: + { + DoPauseEvent(); // battle with Lich King + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + pLichKing->RemoveAllAuras(); + pLichKing->SetWalk(false); + pLichKing->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, EQUIP_FROSTMOURNE); + pLichKing->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + if (m_bDebuggingEvent) // Debug + DoNextEventStep(5000); + else + { + pLichKing->SetInCombatWithZone(); + if (!pLichKing->SelectHostileTarget()) + pLichKing->AI()->EnterEvadeMode(); + } + } + break; + } + // *** ENDING INTRO *** + case 10: + { + SetCombatMovement(false, true); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + pLichKing->AI()->SetCombatMovement(false, true); + pLichKing->CastSpell(pLichKing, SPELL_FURY_OF_FROSTMOURNE, true); + } + DoScriptText(SAY_LAST_PHASE, m_creature); + DoNextEventStep(17000); + break; + } + case 11: + { + DoLichKingText(SAY_OUTRO_1); + DoNextEventStep(26000); + break; + } + case 12: + { + DoLichKingText(SAY_OUTRO_2); + DoNextEventStep(10000); + break; + } + case 13: + { + DoLichKingText(SAY_OUTRO_3); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + pLichKing->SetFacingToObject(m_creature); + DoNextEventStep(23000); + break; + } + case 14: + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + DoScriptText(SAY_OUTRO_4, pLichKing); + pLichKing->GetMotionMaster()->MovePoint(POINT_CENTER_LAND_LICH_KING, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, false); + } + DoNextEventStep(27000); + break; + } + case 15: + { + DoLichKingText(SAY_OUTRO_5); + DoNextEventStep(12000); + break; + } + case 16: + { + DoScriptText(SAY_OUTRO_6, m_creature); + DoNextEventStep(8000); + break; + } + case 17: + { + DoCastSpellIfCan(m_creature, SPELL_LIGHTS_BLESSING, CAST_TRIGGERED); + DoNextEventStep(5000); + break; + } + case 18: + { + m_creature->RemoveAurasDueToSpell(SPELL_ICE_LOCK); + + // run to Lich King + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_TIRION_OUTRO, TirionLoc[1].x, TirionLoc[1].y, TirionLoc[1].z, false); + } + DoPauseEvent(); // wait for arriving at Lich King and attack him + break; + } + case 19: + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + pLichKing->CastSpell(pLichKing, SPELL_FROSTMOURNE_DESPAWN, false); + pLichKing->CastSpell(pLichKing, SPELL_SUMMON_BROKEN_FROSTMOURNE, false); + DoScriptText(SAY_OUTRO_7, pLichKing); + } + DoNextEventStep(3500); + break; + } + case 20: + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + pLichKing->CastSpell(pLichKing, 73021, false); + pLichKing->CastSpell(pLichKing, SPELL_THROW_FROSTMOURNE, false); + pLichKing->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0); + m_creature->SetFacingToObject(pLichKing); + } + DoNextEventStep(1000); + break; + } + case 21: + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + + float x, y, z; + pLichKing->GetClosePoint(x, y, z, pLichKing->GetObjectBoundingRadius(), 3.0f, pLichKing->GetOrientation()); + if (Creature* pFrostmourne = m_creature->SummonCreature(NPC_FROSTMOURNE, x, y, z, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + pFrostmourne->CastSpell(pFrostmourne, SPELL_BROKEN_FROSTMOURNE, false); + m_guidFrostmourne = pFrostmourne->GetObjectGuid(); + } + } + + DoNextEventStep(4000); + break; + } + case 22: + { + DoScriptText(SAY_OUTRO_8, m_creature); + m_creature->RemoveAllAuras(); + m_creature->GetMotionMaster()->Clear(); + m_creature->MonsterMoveToDestination(TirionLoc[2].x, TirionLoc[2].y, TirionLoc[2].z, m_creature->GetOrientation(), 12.0f, 3.0f); + + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + if (Creature* pFrostmourne = m_pInstance->instance->GetCreature(m_guidFrostmourne)) + { + float x, y, z; + pFrostmourne->GetPosition(x, y, z); + pFrostmourne->CastSpell(pFrostmourne, SPELL_FROSTMOURNE_SPIRITS, false); + pLichKing->CastSpell(pLichKing, SPELL_SOUL_BARRAGE, false); + pLichKing->SetLevitate(true); + pLichKing->GetMotionMaster()->Clear(); + pLichKing->MonsterMoveWithSpeed(x, y, z + 2.0f, 2.0f, false); + } + } + + DoNextEventStep(5000); + break; + } + case 23: + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + float x, y, z; + pLichKing->GetClosePoint(x, y, z, pLichKing->GetObjectBoundingRadius(), 6.0f, pLichKing->GetAngle(m_creature) + 1.0f); + + if (Creature* pTerenas = m_creature->SummonCreature(NPC_MENETHIL, x, y, z, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + m_guidTerenas = pTerenas->GetObjectGuid(); + pTerenas->SetFacingToObject(pLichKing); + DoScriptText(SAY_OUTRO_9, pTerenas); + } + } + + DoNextEventStep(10000); + break; + } + case 24: + { + if (Creature* pTerenas = m_pInstance->instance->GetCreature(m_guidTerenas)) + { + DoScriptText(SAY_OUTRO_10, pTerenas); + pTerenas->CastSpell(pTerenas, SPELL_MASS_RESURRECTION, false); + } + + DoNextEventStep(6000); + break; + } + case 25: + { + DoScriptText(SAY_OUTRO_11, m_creature); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + if (Creature* pTerenas = m_pInstance->instance->GetCreature(m_guidTerenas)) + pTerenas->AI()->AttackStart(pLichKing); + + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true, true); + AttackStart(pLichKing); + } + DoNextEventStep(6000); + break; + } + case 26: + { + DoLichKingText(SAY_OUTRO_12); + DoNextEventStep(9000); + break; + } + case 27: + { + DoLichKingText(SAY_OUTRO_13); + DoPauseEvent(); // wait until Lich King is dead + if (m_bDebuggingEvent) // Debug + DoNextEventStep(10000); + break; + } + case 28: + { + DoNextEventStep(8000); + break; + } + case 29: + { + if (Creature* pFrostmourne = m_pInstance->instance->GetCreature(m_guidFrostmourne)) + pFrostmourne->ForcedDespawn(2000); + if (Creature* pTerenas = m_pInstance->instance->GetCreature(m_guidTerenas)) + pTerenas->ForcedDespawn(2000); + // play cinematic + Map::PlayerList const& list = m_pInstance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = list.begin(); itr != list.end(); ++itr) + { + itr->getSource()->SendMovieStart(FINAL_ARTHAS_MOVIE); + } + DoPauseEvent(); // Finish + if (m_bDebuggingEvent) // Debug + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + pLichKing->SetLevitate(false); + DoSetDebuggingEvent(false); + pLichKing->AI()->EnterEvadeMode(); + } + base_icc_bossAI::EnterEvadeMode(); + } + break; + } + } + } + else + m_uiEventTimer -= uiDiff; + + if (IsCombatMovement()) + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_tirion_icc(Creature* pCreature) +{ + return new boss_tirion_iccAI(pCreature); +} + +bool GossipHello_boss_tirion_icc(Player* pPlayer, Creature* pCreature) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_LICH_KING) != NOT_STARTED && + pInstance->GetData(TYPE_LICH_KING) != FAIL ) + { + return true; + } + + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TIRION_START_EVENT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + if (pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Debug event", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(15290, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_boss_tirion_icc(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + boss_tirion_iccAI* pTirionAI = dynamic_cast(pCreature->AI()); + if (!pTirionAI) + return true; + + pTirionAI->DoSetDebuggingEvent(false); + + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF + 1: + if (pPlayer->isGameMaster()) + pTirionAI->DoSetDebuggingEvent(true); + // no break + case GOSSIP_ACTION_INFO_DEF: + pTirionAI->DoStartEvent(); + break; + } + pPlayer->CLOSE_GOSSIP_MENU(); + return true; +} + + +/** + * The Lich King + */ +struct MANGOS_DLL_DECL boss_the_lich_king_iccAI : public base_icc_bossAI +{ + boss_the_lich_king_iccAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + m_uiPlatformOriginalFlag = 0; + m_bPillarsDestroyed = false; + m_bIsFirstAttempt = true; + } + + Phase 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; + + uint32 m_uiPlatformOriginalFlag; + uint32 m_uiRespawnPlatformTimer; + uint32 m_uiDestroyPillarsTimer; + bool m_bPillarsDestroyed; + bool m_bPlatformDestroyed; + bool m_bIsFirstAttempt; + + void Reset() override + { + m_uiPhase = PHASE_ONE; + 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; + m_uiDestroyPillarsTimer = 3000; + m_uiRespawnPlatformTimer= 3000; + + DoRespawnPlatform(); + SetCombatMovement(true); + + m_bPlatformDestroyed = false; + } + + void Aggro(Unit* /*pWho*/) override + { + if (!m_bIsFirstAttempt) + DoScriptText(SAY_AGGRO, m_creature); // say aggro if this is another attempt + + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_LICH_KING, IN_PROGRESS); + + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION)) + { + if (boss_tirion_iccAI* pTirionAI = dynamic_cast(pTirion->AI())) + { + if (pTirionAI->m_bDebuggingEvent) + m_uiPhase = PHASE_DEATH_AWAITS; + } + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_creature->isInCombat()) + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pWho) override + { + if (pWho->GetTypeId() == TYPEID_PLAYER && m_uiPhase != PHASE_DEATH_AWAITS) + 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); + + m_creature->GetMotionMaster()->MoveFall(); + + // finish event, after around 8 seconds play cinematic + if (m_pInstance) + { + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION)) + { + if (boss_tirion_iccAI* pTirionAI = dynamic_cast(pTirion->AI())) + pTirionAI->DoNextEventStep(); + } + } + } + + void EnterEvadeMode() override + { + if (m_pInstance) + { + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION)) + { + if (boss_tirion_iccAI* pTirionAI = dynamic_cast(pTirion->AI())) + { + if (pTirionAI->m_bDebuggingEvent) + return; + } + } + } + base_icc_bossAI::EnterEvadeMode(); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LICH_KING, FAIL); + m_pInstance->SetData(TYPE_FROSTMOURNE_ROOM, NOT_STARTED); + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION)) + { + pTirion->RemoveAllAuras(); + pTirion->DeleteThreatList(); + pTirion->CombatStop(true); + if (pTirion->isAlive()) + pTirion->GetMotionMaster()->MoveTargetedHome(); + } + } + + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SIT); + m_creature->SetStandState(UNIT_STAND_STATE_SIT); + DoCastSpellIfCan(m_creature, SPELL_SIT_EMOTE_NO_SHEATH, CAST_TRIGGERED); + m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0); + + m_bIsFirstAttempt = false; + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ICE_SPHERE) + { + pSummoned->SetInCombatWithZone(); + + if (Unit* pTarget = SelectTargetForIceSphere()) + { + pSummoned->AddThreat(pTarget, 100000.0f); + pSummoned->AI()->AttackStart(pTarget); + pSummoned->CastSpell(pSummoned, SPELL_ICE_BURST_AURA, true); + pSummoned->CastSpell(pTarget, SPELL_ICE_PULSE, false); + } + } + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + switch (uiData) + { + case POINT_CENTER_LAND_LICH_KING: + { + switch (m_uiPhase) + { + case PHASE_RUNNING_WINTER_ONE: + { + DoScriptText(SAY_REMORSELESS_WINTER, m_creature); + DoCastSpellIfCan(m_creature, SPELL_REMORSELESS_WINTER_1); + m_uiPhase = PHASE_WINTER_ONE; + m_uiPhaseTimer = 62000; + // set phase initial timers + m_uiPainSufferingTimer = 6000; + m_uiRagingSpiritTimer = 20000; + m_uiIceSphereTimer = 6000; + + // on heroic despawn Shadow Traps + if (m_bIsHeroic) + DoDespawnShadowTraps(); + break; + } + case PHASE_RUNNING_WINTER_TWO: + { + DoScriptText(SAY_REMORSELESS_WINTER, m_creature); + DoCastSpellIfCan(m_creature, SPELL_REMORSELESS_WINTER_2); + m_uiRespawnPlatformTimer = 3000; // respawn platform after spell is cast + m_uiPhase = PHASE_WINTER_TWO; + m_uiPhaseTimer = 62000; + // set phase initial timers + m_uiPainSufferingTimer = 6000; + m_uiRagingSpiritTimer = 15000; + m_uiIceSphereTimer = 6000; + break; + } + case PHASE_DEATH_AWAITS: + case PHASE_ONE: // Only possible in debugging + { + DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD); + break; + } + } + break; + } + } + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + // Prevent exploit (Heroic) + if (m_uiPhase == PHASE_IN_FROSTMOURNE) + uiDamage = 0; + } + + void DoDestroyPlatform() + { + if (!m_pInstance) + return; + + if (GameObject* pGoFloor = m_pInstance->GetSingleGameObjectFromStorage(GO_ARTHAS_PLATFORM)) + { + pGoFloor->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_NODESPAWN); + m_uiPlatformOriginalFlag = pGoFloor->GetUInt32Value(GAMEOBJECT_BYTES_1); + pGoFloor->SetUInt32Value(GAMEOBJECT_BYTES_1, 8449); + } + + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_FROSTY_WIND)) + pGo->SetGoState(GO_STATE_READY); + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_SNOW_EDGE)) + pGo->SetGoState(GO_STATE_READY); + + m_bPlatformDestroyed = true; + } + + void DoRespawnPlatform() + { + if (!m_pInstance) + return; + + if (!m_bPlatformDestroyed) + return; + + if (GameObject* pGoFloor = m_pInstance->GetSingleGameObjectFromStorage(GO_ARTHAS_PLATFORM)) + { + pGoFloor->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED | GO_FLAG_NODESPAWN); + pGoFloor->SetUInt32Value(GAMEOBJECT_BYTES_1, m_uiPlatformOriginalFlag); + } + + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_FROSTY_WIND)) + pGo->SetGoState(GO_STATE_ACTIVE); + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_SNOW_EDGE)) + pGo->SetGoState(GO_STATE_ACTIVE); + + m_bPlatformDestroyed = false; + } + + void DoDespawnShadowTraps() + { + std::list lTraps; + GetCreatureListWithEntryInGrid(lTraps, m_creature, NPC_SHADOW_TRAP, 120.0f); + if (!lTraps.empty()) + { + for (std::list::iterator i = lTraps.begin(); i != lTraps.end();) + { + std::list::iterator next = i; + ++next; + if (*i) + (*i)->ForcedDespawn(); + + i = next; + } + } + } + + Unit* SelectTargetForIceSphere() + { + std::list lPotentialTargets; + const ThreatList& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin();itr != threatList.end(); ++itr) + { + if (Unit* pVictim = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (!pVictim->HasAuraOfDifficulty(SPELL_ICE_PULSE)) + lPotentialTargets.push_back((*itr)->getUnitGuid()); + } + } + + if (!lPotentialTargets.empty()) + { + std::list::iterator i = lPotentialTargets.begin(); + std::advance(i, urand(0, lPotentialTargets.size() - 1)); + return m_creature->GetMap()->GetUnit(*i); + } + else + return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_ICE_PULSE, SELECT_FLAG_PLAYER); + } + + void DoPrepareFrostmourneRoom() + { + // Terenas + Spirit Warden + if (!m_bIsHeroic) + { + m_creature->SummonCreature(NPC_TERENAS_FM_NORMAL, SpawnLoc[4].x - 5.0f, SpawnLoc[4].y, SpawnLoc[4].z, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 68000, true); + m_creature->SummonCreature(NPC_SPIRIT_WARDEN, SpawnLoc[4].x + 5.0f, SpawnLoc[4].y, SpawnLoc[4].z, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 68000, true); + } + // Terenas + Spirit Bombs and Spirits + else + { + m_creature->SummonCreature(NPC_TERENAS_FM_HEROIC, SpawnLoc[4].x, SpawnLoc[4].y, SpawnLoc[4].z, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 48000, true); + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_FROSTMOURNE_ROOM, IN_PROGRESS); + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_HARVESTED_SOUL_1 || + pSpell->Id == SPELL_HARVESTED_SOUL_2 || + pSpell->Id == SPELL_HARVESTED_SOUL_3 || + pSpell->Id == SPELL_HARVESTED_SOUL_4) + { + DoScriptText(SAY_FM_PLAYER_DEATH, m_creature); + } + } + + void UpdateInfest(const uint32 uiDiff) + { + if (m_uiInfestTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INFEST) == CAST_OK) + m_uiInfestTimer = urand(20000, 25000); + } + else + m_uiInfestTimer -= uiDiff; + } + + void UpdateSoulReaper(const uint32 uiDiff) + { + if (m_uiSoulReaperTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_REAPER) == CAST_OK) + m_uiSoulReaperTimer = 30000; + } + else + m_uiSoulReaperTimer -= uiDiff; + } + + void UpdateDefile(const uint32 uiDiff) + { + if (m_uiDefileTimer > uiDiff) + { + m_uiDefileTimer -= uiDiff; + return; + } + std::list lPotentialTargets; + const ThreatList& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin();itr != threatList.end(); ++itr) + { + if (Unit* pVictim = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->GetVehicle()) + lPotentialTargets.push_back((*itr)->getUnitGuid()); + } + } + + Unit* pTarget = NULL; + if (!lPotentialTargets.empty()) + { + std::list::iterator i = lPotentialTargets.begin(); + std::advance(i, urand(0, lPotentialTargets.size() - 1)); + pTarget = m_creature->GetMap()->GetUnit(*i); + } + + if (!pTarget) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_DEFILE, SELECT_FLAG_PLAYER); + + if (pTarget && DoCastSpellIfCan(pTarget, SPELL_DEFILE) == CAST_OK) + m_uiDefileTimer = 30000; + } + + void UpdateNecroticPlague(const uint32 uiDiff) + { + if (m_uiNecroticPlagueTimer > uiDiff) + { + m_uiNecroticPlagueTimer -= uiDiff; + return; + } + + std::list lPotentialTargets; + const ThreatList& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin();itr != threatList.end(); ++itr) + { + if (Unit* pVictim = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pVictim != m_creature->getVictim() && + !pVictim->HasAuraOfDifficulty(SPELL_NECROTIC_PLAGUE) && + !pVictim->HasAuraOfDifficulty(SPELL_NECROTIC_PLAGUE_STACK)) + { + lPotentialTargets.push_back((*itr)->getUnitGuid()); + } + } + } + + if (lPotentialTargets.empty()) + return; + std::list::iterator i = lPotentialTargets.begin(); + std::advance(i, urand(0, lPotentialTargets.size() - 1)); + Unit* pTarget = m_creature->GetMap()->GetUnit(*i); + + if (pTarget && DoCastSpellIfCan(pTarget, SPELL_NECROTIC_PLAGUE) == CAST_OK) + m_uiNecroticPlagueTimer = 30000; + } + + void UpdateDestroyPillars(const uint32 uiDiff) + { + if (m_bPillarsDestroyed) + return; + + if (m_uiDestroyPillarsTimer > uiDiff) + { + m_uiDestroyPillarsTimer -= uiDiff; + return; + } + m_bPillarsDestroyed = true; + + if (m_pInstance) + return; + + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_ICESHARD_1)) + pGo->SetGoState(GO_STATE_ACTIVE); + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_ICESHARD_2)) + pGo->SetGoState(GO_STATE_ACTIVE); + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_ICESHARD_3)) + pGo->SetGoState(GO_STATE_ACTIVE); + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_ICESHARD_4)) + pGo->SetGoState(GO_STATE_ACTIVE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase != PHASE_DEATH_AWAITS && m_uiPhase != PHASE_IN_FROSTMOURNE) + { + // check evade + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Berserk + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiBerserkTimer = 30 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_ONE: + { + // check HP + if (m_creature->GetHealthPercent() <= 70.0f) + { + // phase transition + SetCombatMovement(false, true); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_LAND_LICH_KING, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + m_uiPhase = PHASE_RUNNING_WINTER_ONE; + return; + } + + // Infest + UpdateInfest(uiDiff); + + // Necrotic Plague + UpdateNecroticPlague(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_bIsHeroic) + { + 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_WINTER_ONE: + case PHASE_WINTER_TWO: + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // 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_WINTER_ONE ? PHASE_QUAKE_ONE : PHASE_QUAKE_TWO); + m_uiPhaseTimer = 6500; + } + } + else + m_uiPhaseTimer -= uiDiff; + + // destroy pillars + UpdateDestroyPillars(uiDiff); + + // respawning platform + if (m_bPlatformDestroyed) + { + if (m_uiRespawnPlatformTimer <= uiDiff) + { + DoRespawnPlatform(); + } + else + m_uiRespawnPlatformTimer -= 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_TRIGGERED) == 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)) + { + // some targeting issues with script effect spell + // but we dont need it in sd2 ;) + // if (DoCastSpellIfCan(m_creature, SPELL_RAGING_SPIRIT, CAST_TRIGGERED) == CAST_OK) + + pTarget->CastSpell(pTarget, SPELL_SUMMON_RAGING_SPIRIT, true); + m_uiRagingSpiritTimer = (m_uiPhase == PHASE_WINTER_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) + { + DoDestroyPlatform(); + m_uiPhase = (m_uiPhase == PHASE_QUAKE_ONE ? PHASE_TWO : PHASE_THREE); + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true, true); + return; + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + case PHASE_TWO: + { + // check HP + if (m_creature->GetHealthPercent() <= 40.0f) + { + // phase transition + SetCombatMovement(false, true); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_LAND_LICH_KING, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + m_uiPhaseTimer = 60000; + m_uiPhase = PHASE_RUNNING_WINTER_TWO; + } + + // Infest + UpdateInfest(uiDiff); + + // Soul Reaper + UpdateSoulReaper(uiDiff); + + // Defile + UpdateDefile(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) + { + m_uiPhase = PHASE_DEATH_AWAITS; + + // tell Tirion to continue the event + if (m_pInstance) + { + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION)) + { + if (boss_tirion_iccAI* pTirionAI = dynamic_cast(pTirion->AI())) + pTirionAI->DoNextEventStep(); + } + } + + return; + } + + // Soul Reaper + UpdateSoulReaper(uiDiff); + + // Defile + UpdateDefile(uiDiff); + + // Harvest Soul + if (m_uiHarvestSoulTimer <= uiDiff) + { + Unit* pTarget = NULL; + 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; + DoPrepareFrostmourneRoom(); + + if (m_bIsHeroic) + { + m_uiPhase = PHASE_IN_FROSTMOURNE; + SetCombatMovement(false, true); + m_uiFrostmournePhaseTimer = 47000; + m_uiDefileTimer = 1000; + } + } + } + } + else + m_uiHarvestSoulTimer -= uiDiff; + + // Vile Spirits (start moving after 15seconds) + 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) + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_FROSTMOURNE_ROOM) == IN_PROGRESS) + { + m_pInstance->SetData(TYPE_FROSTMOURNE_ROOM, DONE); + m_uiFrostmournePhaseTimer = 2000; // Wait for teleport all players. + } + else + { + m_uiPhase = PHASE_THREE; + m_creature->SetInCombatWithZone(); + SetCombatMovement(true, true); + } + } + } + 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); +} + +/** + * Drudge Ghoul + */ +struct MANGOS_DLL_DECL mob_drudge_ghoulAI : public base_icc_bossAI +{ + mob_drudge_ghoulAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiReadyTimer; + bool m_bIsReady; + bool m_bIsSpawned; + + void Reset() override + { + m_bIsReady = false; + m_bIsSpawned = false; + m_uiReadyTimer = 5000; + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void AttackStart(Unit* pWho) override + { + if (!m_bIsReady) + return; + else + base_icc_bossAI::AttackStart(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->ForcedDespawn(5000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsReady) + { + if (!m_bIsSpawned) + { + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + m_bIsSpawned = true; + } + + if (m_uiReadyTimer <= uiDiff) + { + m_bIsReady = true; + m_creature->SetInCombatWithZone(); + } + else + m_uiReadyTimer -= uiDiff; + + return; + } + + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_drudge_ghoul(Creature* pCreature) +{ + return new mob_drudge_ghoulAI(pCreature); +} + +/** + * Shambling Horror + */ +struct MANGOS_DLL_DECL mob_shambling_horrorAI : public base_icc_bossAI +{ + mob_shambling_horrorAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiShockwaveTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiReadyTimer; + bool m_bHasCastFrenzy; + bool m_bIsReady; + bool m_bIsSpawned; + + void Reset() override + { + m_bIsReady = false; + m_bIsSpawned = false; + m_uiReadyTimer = 5000; + + m_uiShockwaveTimer = 12000; + m_uiEnrageTimer = 6000; + m_bHasCastFrenzy = false; + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void AttackStart(Unit* pWho) override + { + if (!m_bIsReady) + return; + else + base_icc_bossAI::AttackStart(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->ForcedDespawn(5000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsReady) + { + if (!m_bIsSpawned) + { + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + m_bIsSpawned = true; + } + + if (m_uiReadyTimer <= uiDiff) + { + m_bIsReady = true; + m_creature->SetInCombatWithZone(); + } + else + m_uiReadyTimer -= uiDiff; + + return; + } + + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Frenzy on heroic + if (m_bIsHeroic) + { + if (!m_bHasCastFrenzy) + { + if (m_creature->GetHealthPercent() <= 20.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + m_bHasCastFrenzy = true; + } + } + } + + // Enrage + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + m_uiEnrageTimer = 20000; + m_uiShockwaveTimer = urand(5000, 7000); + } + } + else + m_uiEnrageTimer -= uiDiff; + + // Shockwave + if (m_uiShockwaveTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCKWAVE) == CAST_OK) + m_uiShockwaveTimer = 20000; + } + else + m_uiShockwaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_shambling_horror(Creature* pCreature) +{ + return new mob_shambling_horrorAI(pCreature); +} + +/** + * Shadow Trap + */ +struct MANGOS_DLL_DECL mob_shadow_trapAI : public base_icc_bossAI +{ + mob_shadow_trapAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_SHADOW_TRAP_VISUAL, CAST_TRIGGERED); + m_uiShadowTrapTimer = 5000; + } + + uint32 m_uiShadowTrapTimer; + + void Reset() override {} + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + uiDamage = 0; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + // Shadow Trap + if (m_uiShadowTrapTimer) + { + if (m_uiShadowTrapTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_TRAP_AURA) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_TRAP_VISUAL); + m_uiShadowTrapTimer = 0; + } + } + else + m_uiShadowTrapTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_mob_shadow_trap(Creature* pCreature) +{ + return new mob_shadow_trapAI(pCreature); +} + +/** + * Ice Sphere + */ +struct MANGOS_DLL_DECL mob_ice_sphere_iccAI : public base_icc_bossAI +{ + mob_ice_sphere_iccAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_creature->SetWalk(true); + m_creature->SetSpeedRate(MOVE_WALK, 1.1f); + } + + void Reset() override {} + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + } +}; + +CreatureAI* GetAI_mob_ice_sphere_icc(Creature* pCreature) +{ + return new mob_ice_sphere_iccAI(pCreature); +} + +/** + * Raging Spirit + */ +struct MANGOS_DLL_DECL mob_raging_spiritAI : public base_icc_bossAI +{ + mob_raging_spiritAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiSoulShriekTimer; + bool m_bHasCloned; + + void Reset() override + { + m_uiSoulShriekTimer = 8000; + m_bHasCloned = false; + } + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->ForcedDespawn(5000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bHasCloned) + { + if (Unit* pCreator = m_creature->GetCreator()) + { + pCreator->CastSpell(m_creature, SPELL_RAGING_SPIRIT_VISUAL, true); + m_bHasCloned = true; + } + } + + // Soul Shriek + if (m_uiSoulShriekTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_SHRIEK) == CAST_OK) + m_uiSoulShriekTimer = 10000; + } + else + m_uiSoulShriekTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_raging_spirit(Creature* pCreature) +{ + return new mob_raging_spiritAI(pCreature); +} + +/** + * Val'kyr Shadowguard + */ +struct MANGOS_DLL_DECL mob_valkyr_shadowguardAI : public base_icc_bossAI +{ + mob_valkyr_shadowguardAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + m_creature->SetLevitate(true); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->NearTeleportTo(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 15.0f, 0.0f); + } + + uint32 m_uiCatchTimer; + uint32 m_uiLifeSiphonTimer; + bool m_bIsFree; + bool m_bIsCastingLifeSiphon; + + ObjectGuid m_TargetGUID; + + void Reset() override + { + m_bIsFree = true; + m_bIsCastingLifeSiphon = false; + m_uiCatchTimer = 2000; + m_uiLifeSiphonTimer = 2000; + m_TargetGUID = ObjectGuid(); + + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_WINGS_OF_THE_DAMNED, CAST_TRIGGERED); + } + + void AttackStart(Unit* pWho) override + { + if (m_bIsCastingLifeSiphon) + base_icc_bossAI::AttackStart(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->ForcedDespawn(5000); + } + + bool DoCatchTarget() + { + m_TargetGUID = ObjectGuid(); + if (m_pInstance) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + // search for proper target + std::list lPotentialTargets; + ThreatList const& lThreatList = pLichKing->getThreatManager().getThreatList(); + + if (!lThreatList.empty()) + { + for (ThreatList::const_iterator i = lThreatList.begin(); i != lThreatList.end(); ++i) + { + if (Unit* pTmp = m_pInstance->instance->GetUnit((*i)->getUnitGuid())) + { + if (pTmp != pLichKing->getVictim() && + pTmp->GetTypeId() == TYPEID_PLAYER && + !pTmp->GetVehicle() && + pTmp->GetDistance2d(SpawnLoc[1].x, SpawnLoc[1].y) < 52.0f && + pTmp->GetPositionZ() > SpawnLoc[1].z - 2.0f) + { + lPotentialTargets.push_back(pTmp->GetObjectGuid()); + } + } + } + } + + // select random target + if (!lPotentialTargets.empty()) + { + std::list::iterator i = lPotentialTargets.begin(); + std::advance(i, urand(0, lPotentialTargets.size() - 1)); + + m_TargetGUID = (*i); + if (m_TargetGUID != ObjectGuid()) + return true; + } + } + } + + return false; + } + + void DoFlyAway(Unit* pTarget) + { + float curX, curY, curZ; + float destX, destY; + pTarget->GetPosition(curX, curY, curZ); + + // don't fly into Frozen Throne + if (curX < 480.0f) + { + if (curY > -2124.0f) + m_creature->GetMotionMaster()->MovePoint(POINT_VALKYR_THROW, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z + 3.0f, false); + else + m_creature->GetMotionMaster()->MovePoint(POINT_VALKYR_THROW, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z + 3.0f, false); + + return; + } + + // angle to center + float angle = pTarget->GetAngle(SpawnLoc[1].x, SpawnLoc[1].y); + // angle away from center + angle += M_PI_F; + if (angle > 2 * M_PI_F) + angle -= (2 * M_PI_F); + + // don't fly into Frozen Throne + if (angle < 3.8f && angle > 2.3f) + { + if (angle > 3.05f) + angle = 3.8f; + else + angle = 2.3f; + } + + float fDistToCenter = pTarget->GetDistance2d(SpawnLoc[1].x, SpawnLoc[1].y); + float fDist = 60.0f - fDistToCenter; + + pTarget->GetNearPoint2D(destX, destY, fDist, angle); + m_creature->GetMotionMaster()->MovePoint(POINT_VALKYR_THROW, destX, destY, SpawnLoc[1].z + 3.0f, false); + } + + void DoThrowAndGoBack() + { + DoCastSpellIfCan(m_creature, SPELL_EJECT_PASSENGERS, CAST_TRIGGERED); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_VALKYR_CENTER, SpawnLoc[1].x + frand(-3.0f, 3.0f), SpawnLoc[1].y + frand(-3.0f, 3.0f), SpawnLoc[1].z + 12.0f, false); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType == EFFECT_MOTION_TYPE) + { + if (!m_pInstance) + return; + Unit* pTarget = m_pInstance->instance->GetUnit(m_TargetGUID); + if (pTarget && + pTarget->isAlive() && + !pTarget->GetVehicle() && + pTarget->GetDistance2d(SpawnLoc[1].x, SpawnLoc[1].y) < 52.0f && + pTarget->GetPositionZ() > SpawnLoc[1].z - 2.0f) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTarget->CastSpell(m_creature, SPELL_HARVEST_SOUL_VEHICLE, true); + DoFlyAway(pTarget); + return; + } + // try again fast! + m_bIsFree = true; + m_uiCatchTimer = 0; + DoThrowAndGoBack(); + return; + } + + if (uiMovementType != POINT_MOTION_TYPE) + return; + + switch (uiData) + { + case POINT_VALKYR_THROW: + { + DoThrowAndGoBack(); + break; + } + case POINT_VALKYR_CENTER: + { + m_bIsFree = true; + break; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // on heroic start casting Life Siphon at 50% HP + if (!m_bIsCastingLifeSiphon && m_bIsHeroic && m_creature->GetHealthPercent() <= 50.0f) + { + m_bIsCastingLifeSiphon = true; + m_creature->SetInCombatWithZone(); + DoThrowAndGoBack(); + } + + if (!m_bIsFree) + return; + + if (m_pInstance && m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_bIsCastingLifeSiphon) + { + if (m_uiCatchTimer <= uiDiff) + { + if (m_pInstance && DoCatchTarget()) + { + Unit* pTarget = m_pInstance->instance->GetUnit(m_TargetGUID); + if (pTarget) + { + m_creature->GetMotionMaster()->Clear(); + if (DoCastSpellIfCan(pTarget, SPELL_VALKYR_CHARGE, CAST_TRIGGERED) == CAST_OK) + m_bIsFree = false; + } + } + m_uiCatchTimer = urand(1000, 3000); + } + else + m_uiCatchTimer -= uiDiff; + + return; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Life Siphon + if (m_uiLifeSiphonTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_LIFE_SIPHON) == CAST_OK) + m_uiLifeSiphonTimer = 5000; + } + else + m_uiLifeSiphonTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_valkyr_shadowguard(Creature* pCreature) +{ + return new mob_valkyr_shadowguardAI(pCreature); +} + +/** + * Defile + */ +struct MANGOS_DLL_DECL mob_defiler_iccAI : public base_icc_bossAI +{ + mob_defiler_iccAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_DEFILE_AURA, CAST_TRIGGERED); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); // don't turn around + // "lasts 30 seconds" + m_creature->ForcedDespawn(30000); + } + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_defiler_icc(Creature* pCreature) +{ + return new mob_defiler_iccAI(pCreature); +} + +/** + * Vile Spirit + */ +struct MANGOS_DLL_DECL mob_vile_spiritAI : public base_icc_bossAI +{ + mob_vile_spiritAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->SetInCombatWithZone(); + m_creature->GetMotionMaster()->Clear(); + m_creature->NearTeleportTo(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 15.0f, 0.0f); + m_creature->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX() + frand(-3.0f, 3.0f), m_creature->GetPositionY() + frand(-3.0f, 3.0f), m_creature->GetPositionZ(), false); + DoCastSpellIfCan(m_creature, SPELL_SPIRIT_BURST_AURA, CAST_TRIGGERED); + + m_bIsWickedSpirit = m_creature->GetEntry() == NPC_WICKED_SPIRIT; + + if (m_bIsWickedSpirit) + m_creature->ForcedDespawn(41000); + + Reset(); + } + + bool m_bIsReady; + bool m_bIsWickedSpirit; + uint32 m_uiReadyTimer; + uint32 m_uiSummonSpiritBombTimer; + + void Reset() override + { + m_bIsReady = false; + m_uiReadyTimer = m_bIsWickedSpirit ? urand(7000, 15000) : 15000; + m_uiSummonSpiritBombTimer = urand(1000, 10000); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (m_bIsReady) + return; + + if (uiData == 1) + m_creature->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX() + frand(-3.0f, 3.0f), m_creature->GetPositionY() + frand(-3.0f, 3.0f), m_creature->GetPositionZ(), false); + } + + Unit* SelectTarget() + { + if (m_pInstance) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + // search for proper target + std::list lPotentialTargets; + ThreatList const& lThreatList = pLichKing->getThreatManager().getThreatList(); + + if (!lThreatList.empty()) + { + for (ThreatList::const_iterator i = lThreatList.begin(); i != lThreatList.end(); ++i) + { + if (Unit* pTmp = m_pInstance->instance->GetUnit((*i)->getUnitGuid())) + { + if (pTmp != pLichKing->getVictim() && + pTmp->GetTypeId() == TYPEID_PLAYER && + !pTmp->GetVehicle()) + { + lPotentialTargets.push_back(pTmp->GetObjectGuid()); + } + } + } + } + + // select random target + if (!lPotentialTargets.empty()) + { + std::list::iterator i = lPotentialTargets.begin(); + std::advance(i, urand(0, lPotentialTargets.size() - 1)); + + if (Unit* pTarget = m_pInstance->instance->GetUnit(*i)) + return pTarget; + } + } + } + + return NULL; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + { + m_creature->ForcedDespawn(); + return; + } + + if (m_bIsWickedSpirit) + { + // Summon Spirit Bomb + if (m_uiSummonSpiritBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIRIT_BOMB, CAST_TRIGGERED) == CAST_OK) + m_uiSummonSpiritBombTimer = 3000; + } + else + m_uiSummonSpiritBombTimer -= uiDiff; + } + + // start chasing timer + if (!m_bIsReady) + { + if (m_uiReadyTimer <= uiDiff) + { + Unit* pTarget = NULL; + + m_creature->SetInCombatWithZone(); + + if (m_bIsWickedSpirit) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SPIRIT_BURST_AURA, SELECT_FLAG_PLAYER); + else + pTarget = SelectTarget(); + + if (pTarget) + { + DoResetThreat(); + m_creature->AddThreat(pTarget, 100000.0f); + m_bIsReady = true; + m_creature->StopMoving(); + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true); + + if (m_bIsWickedSpirit) + m_creature->SetWalk(true); + + AttackStart(pTarget); + } + } + else + m_uiReadyTimer -= uiDiff; + + } + } +}; + +CreatureAI* GetAI_mob_vile_spirit(Creature* pCreature) +{ + return new mob_vile_spiritAI(pCreature); +} + + +struct MANGOS_DLL_DECL mob_strangulate_vehicleAI : public base_icc_bossAI +{ + mob_strangulate_vehicleAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + SetCombatMovement(false); + m_creature->SetWalk(true); + m_bIsSetUp = false; + m_bHasMoved = false; + m_bHasTeleported = false; + m_uiMoveTimer = 2000; + m_uiTeleportTimer = 6000; + } + + bool m_bIsSetUp; + bool m_bHasMoved; + bool m_bHasTeleported; + uint32 m_uiMoveTimer; + uint32 m_uiTeleportTimer; + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override{} + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + else + { + if (m_pInstance->GetData(TYPE_FROSTMOURNE_ROOM) != IN_PROGRESS) + { + if (Unit* pCreator = m_creature->GetCreator()) + { + pCreator->NearTeleportTo(m_creature->GetPosition(), TELE_TO_NOT_LEAVE_COMBAT); + if (m_pInstance->GetData(TYPE_FROSTMOURNE_ROOM) != DONE + && pCreator->HasAuraOfDifficulty(SPELL_HARVEST_SOUL_TP_FM_N)) + { + pCreator->CastSpell(pCreator, SPELL_HARVESTED_SOUL_1, false); + } + // remove Harvest Soul aura + pCreator->RemoveAurasDueToSpell(SPELL_HARVEST_SOUL_TP_FM_N); + pCreator->RemoveAurasDueToSpell(SPELL_HARVEST_SOUL_TP_FM_H); + m_creature->ForcedDespawn(1000); + return; + } + } + } + + if (!m_bIsSetUp) + { + if (Unit* pCreator = m_creature->GetCreator()) + { + pCreator->CastSpell(m_creature, SPELL_HARVEST_SOUL_VEHICLE, true); + m_bIsSetUp = true; + } + } + + // move timer + if (!m_bHasMoved) + { + if (m_uiMoveTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + { + float x, y, z; + pLichKing->GetNearPoint(m_creature, x, y, z, m_creature->GetObjectBoundingRadius(), 8.0f, pLichKing->GetAngle(m_creature)); + m_creature->GetMotionMaster()->MovePoint(POINT_TP_TO_FM, x, y, z, false); + } + } + m_bHasMoved = true; + } + else + m_uiMoveTimer -= uiDiff; + } + + // teleport timer + if (!m_bHasTeleported) + { + if (m_uiTeleportTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + pLichKing->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + + if (Unit* pCreator = m_creature->GetCreator()) + { + // because it causes player to walk afterwards... + m_creature->SetWalk(false); + + DoCastSpellIfCan(m_creature, SPELL_EJECT_PASSENGERS, CAST_TRIGGERED); + if (pCreator->isAlive()) + { + pCreator->CastSpell(m_creature, SPELL_HARVEST_SOUL_CLONE, true); + pCreator->CastSpell(pCreator, SPELL_FROSTMOURNE_TP_VISUAL, true); + pCreator->CastSpell(pCreator, (m_bIsHeroic ? SPELL_HARVEST_SOUL_TP_FM_H : SPELL_HARVEST_SOUL_TP_FM_N), false); + } + else + { + m_creature->ForcedDespawn(); + return; + } + } + + m_bHasTeleported = true; + } + else + m_uiTeleportTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_mob_strangulate_vehicle(Creature* pCreature) +{ + return new mob_strangulate_vehicleAI(pCreature); +} + +/** + * Terenas Menethil in Frostmourne + */ +struct MANGOS_DLL_DECL npc_terenas_fmAI : public base_icc_bossAI +{ + npc_terenas_fmAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + m_uiSayPhase = 0; + m_uiSayTimer = 6000; + m_uiSummonWickedSpiritsTimer = 7000; + m_uiSummonSpiritBombTimer = 7000; + m_bHasReleasedPlayer = false; + } + + uint32 m_uiSayTimer; + uint32 m_uiSayPhase; + uint32 m_uiSummonWickedSpiritsTimer; + uint32 m_uiSummonSpiritBombTimer; + bool m_bHasReleasedPlayer; + + void Reset() override {} + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_LIGHTS_FAVOR, CAST_TRIGGERED); + m_creature->SetHealthPercent(50.0f); + } + + void EnterEvadeMode() override + { + if (!m_bHasReleasedPlayer) + { + m_bHasReleasedPlayer = true; + DoCastSpellIfCan(m_creature, SPELL_RESTORE_SOUL); + m_uiSayPhase = 5; + m_uiSayTimer = 2000; + } + } + + void JustDied(Unit* pKiller) override + { + if (pKiller->GetEntry() == NPC_SPIRIT_WARDEN) + { + pKiller->CastSpell(pKiller, SPELL_DESTROY_SOUL, true); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FROSTMOURNE_ROOM, FAIL); + + ((Creature*)pKiller)->ForcedDespawn(2000); + } + } + + void DoSummonWickedSpirits(uint32 count) + { + for (uint32 i = 0; i < count; ++i) + { + float x, y, z; + m_creature->GetPosition(x, y, z); + + z += 15.0f; + x += frand(-25.0f, 25.0f); + y += frand(-25.0f, 25.0f); + + m_creature->SummonCreature(NPC_WICKED_SPIRIT, x, y, z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 41000); + } + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (m_bIsHeroic) + uiDamage = 0; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSayTimer <= uiDiff) + { + switch (m_uiSayPhase) + { + case 0: + if (!m_bIsHeroic) + { + if (Creature* pSpirit = GetClosestCreatureWithEntry(m_creature, NPC_SPIRIT_WARDEN, 20.0f)) + { + AttackStart(pSpirit); + pSpirit->AI()->AttackStart(m_creature); + pSpirit->AddThreat(m_creature, 100000.0f); + } + } + else + { + DoSummonWickedSpirits(15); + m_uiSummonWickedSpiritsTimer = 15000; + // summon Spirit Bomb every 2 seconds + // aura doesnt work?;/ + // DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIRIT_BOMBS_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_RESTORE_SOUL_HEROIC); + } + ++m_uiSayPhase; + m_uiSayTimer = 1000; + break; + case 1: + DoScriptText(SAY_FM_TERENAS_AID_1, m_creature); + ++m_uiSayPhase; + m_uiSayTimer = 8000; + break; + case 2: + DoScriptText(SAY_FM_TERENAS_AID_2, m_creature); + ++m_uiSayPhase; + m_uiSayTimer = 12000; + break; + case 3: + DoScriptText(SAY_FM_TERENAS_AID_3, m_creature); + ++m_uiSayPhase; + break; + case 4: + // fight + break; + case 5: + // release soul + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FROSTMOURNE_ROOM, DONE); + + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + DoScriptText(SAY_FM_PLAYER_ESCAPE, pLichKing); + } + m_creature->ForcedDespawn(5000); + ++m_uiSayPhase; + break; + default: + break; + } + } + else + m_uiSayTimer -= uiDiff; + + if (!m_pInstance || m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_bIsHeroic) + { + // Summon Wicked Spirits + if (m_uiSummonWickedSpiritsTimer <= uiDiff) + { + DoSummonWickedSpirits(1); + m_uiSummonWickedSpiritsTimer = 1000; + } + else + m_uiSummonWickedSpiritsTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_terenas_fm(Creature* pCreature) +{ + return new npc_terenas_fmAI(pCreature); +} + + +/** + * Spirit Warden + */ +struct MANGOS_DLL_DECL mob_spirit_wardenAI : public base_icc_bossAI +{ + mob_spirit_wardenAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + Reset(); + } + + uint32 m_uiSoulRipTimer; + uint32 m_uiHarvestedSoulTimer; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_DARK_HUNGER, CAST_TRIGGERED); + m_uiSoulRipTimer = 12000; + m_uiHarvestedSoulTimer = 61000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_LICH_KING) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Soul Rip + if (m_uiSoulRipTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_RIP) == CAST_OK) + m_uiSoulRipTimer = 20000; + } + else + m_uiSoulRipTimer -= uiDiff; + + // Harvest Soul 60sec aura wears off + if (m_uiHarvestedSoulTimer <= uiDiff) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FROSTMOURNE_ROOM, FAIL); + + m_uiHarvestedSoulTimer = 60000; + } + else + m_uiHarvestedSoulTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_spirit_warden(Creature* pCreature) +{ + return new mob_spirit_wardenAI(pCreature); +} + +/** + * Spirit Bomb + */ +struct MANGOS_DLL_DECL mob_spirit_bombAI : public base_icc_bossAI +{ + mob_spirit_bombAI(Creature* pCreature) : base_icc_bossAI(pCreature) + { + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->SetInCombatWithZone(); + + float x, y, z; + m_creature->GetPosition(x, y, z); + + m_creature->NearTeleportTo(x, y, z + 20.0f, 0.0f); + m_creature->GetMotionMaster()->MovePoint(POINT_SPIRIT_BOMB, x, y, z, false); + DoCastSpellIfCan(m_creature, SPELL_SPIRIT_BOMB_VISUAL, CAST_TRIGGERED); + } + + void Reset() override {} + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_SPIRIT_BOMB) + { + DoCastSpellIfCan(m_creature, SPELL_EXPLOSION); + m_creature->ForcedDespawn(1000); + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_spirit_bomb(Creature* pCreature) +{ + return new mob_spirit_bombAI(pCreature); +} + + +void AddSC_boss_lich_king_icc() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_the_lich_king_icc"; + pNewScript->GetAI = &GetAI_boss_the_lich_king_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_tirion_icc"; + pNewScript->GetAI = &GetAI_boss_tirion_icc; + pNewScript->pGossipHello = &GossipHello_boss_tirion_icc; + pNewScript->pGossipSelect = &GossipSelect_boss_tirion_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_ice_sphere_icc"; + pNewScript->GetAI = &GetAI_mob_ice_sphere_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_shambling_horror"; + pNewScript->GetAI = &GetAI_mob_shambling_horror; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_drudge_ghoul"; + pNewScript->GetAI = &GetAI_mob_drudge_ghoul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_shadow_trap"; + pNewScript->GetAI = &GetAI_mob_shadow_trap; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_raging_spirit"; + pNewScript->GetAI = &GetAI_mob_raging_spirit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_valkyr_shadowguard"; + pNewScript->GetAI = &GetAI_mob_valkyr_shadowguard; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_defiler_icc"; + pNewScript->GetAI = &GetAI_mob_defiler_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_vile_spirit"; + pNewScript->GetAI = &GetAI_mob_vile_spirit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_strangulate_vehicle"; + pNewScript->GetAI = &GetAI_mob_strangulate_vehicle; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_terenas_fm"; + pNewScript->GetAI = &GetAI_npc_terenas_fm; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_spirit_warden"; + pNewScript->GetAI = &GetAI_mob_spirit_warden; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_spirit_bomb"; + pNewScript->GetAI = &GetAI_mob_spirit_bomb; + 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 528905ef00..66529fbe99 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,9 +16,1157 @@ /* ScriptData SDName: boss_valithria -SD%Complete: 0% -SDComment: +SD%Complete: 99% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +static LOCATION SpawnLoc[]= +{ + {4240.688477f, 2405.794678f, 364.868591f}, // 0 Valithria Room 1 + {4239.579102f, 2566.753418f, 364.868439f}, // 1 Valithria Room 2 + {4166.216797f, 2564.197266f, 364.873047f}, // 2 Valithria Room 3 + {4165.112305f, 2405.872559f, 364.872925f}, // 3 Valithria Room 4 +}; + +enum BossSpells +{ + 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 - 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 + // 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? ;/ + // 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, + + // Risen Archmage + SPELL_FROSTBOLT_VOLLEY = 70759, + SPELL_MANA_VOID = 71179, + SPELL_VOID_BUFF = 71085, + SPELL_COLUMN_OF_FROST = 70704, + SPELL_COLUMN_OF_FROST_VISUAL = 70715, + SPELL_COLUMN_OF_FROST_TRIG = 70702, + + // Blazing Skeleton + SPELL_FIREBALL = 70754, + SPELL_LAY_WASTE = 69325, + + // Suppresser + SPELL_SUPPRESSION = 70588, // NOTE: must stack from many casters + + // Blistering Zombie + SPELL_CORROSION = 70749, + SPELL_ACID_BURST = 70744, // 750ms cast time. seems like it is cast always before dying + + // Gluttonous Abomination + SPELL_GUT_SPRAY = 71283, + SPELL_ROT_WORM_SPAWNER = 70675, // cast around 30% HP or something? + SPELL_ROT_WORM = 72962, + + NPC_RISEN_ARCHMAGE = 37868, + // NPC_COLUMN_OF_FROST = 37918, + // NPC_MANA_VOID = 38068, + NPC_SUPPRESSER = 37863, + NPC_BLAZING_SKELETON = 36791, + NPC_BLISTERING_ZOMBIE = 37934, + NPC_GLUTTONOUS_ABOMINATION = 37886, + NPC_ROT_WORM = 37907, + + SUMMON_TYPES_NUMBER = 4, + + // 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, +}; + +enum +{ + SAY_AGGRO = -1631140, + SAY_PORTAL = -1631141, + SAY_75_HEALTH = -1631142, + SAY_25_HEALTH = -1631143, + SAY_0_HEALTH = -1631144, + // SAY_PLAYER_DIES = -1631145, + SAY_BERSERK = -1631146, + SAY_VICTORY = -1631147, +}; + +struct MANGOS_DLL_DECL boss_valithria_dreamwalkerAI : public ScriptedAI +{ + boss_valithria_dreamwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_CORRUPTION, CAST_TRIGGERED); + + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + bool m_bIsEnrage; + bool m_bSaidOver25; + bool m_bSaidOver75; + bool m_bIsHealed; + + uint32 m_uiEnrageTimer; + uint32 m_uiHealthCheckTimer; + uint32 m_uiSummonPortalsTimer; + uint32 m_uiOutroTimer; + + uint32 m_uiSummonSuppresserTimer; + uint32 m_uiSummonAbominationTimer; + uint32 m_uiSummonZombieTimer; + uint32 m_uiSummonSkeletonTimer; + uint32 m_uiSummonArchmageTimer; + + uint8 m_uiSummonSuppresserCounter; + uint8 m_uiSummonSkeletonCounter; + + float m_fHP; + + GuidList m_lSummonedAddsGuids; + + void AttackStart(Unit* /*pWho*/) override {} + + void Reset() override + { + m_bIsEnrage = false; + m_bSaidOver25 = false; + m_bSaidOver75 = false; + m_bIsHealed = false; + + m_uiEnrageTimer = 7 * MINUTE * IN_MILLISECONDS; + m_uiHealthCheckTimer = 30000; // no need to check in the beginning of the fight + m_uiOutroTimer = 4000; + m_uiSummonPortalsTimer = 30000; + + m_uiSummonSuppresserTimer = 60000; + m_uiSummonAbominationTimer = 30000; + m_uiSummonZombieTimer = 35000; + m_uiSummonSkeletonTimer = 45000; + m_uiSummonArchmageTimer = 40000; + + m_uiSummonSuppresserCounter = 0; + m_uiSummonSkeletonCounter = 0; + + m_lSummonedAddsGuids.clear(); + + m_creature->SetHealth(m_creature->GetMaxHealth() / 2.0f); + m_fHP = 50.0f; + + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_0_HEALTH, m_creature); + + if (m_pInstance) + { + DoRemoveAdds(); + m_pInstance->SetData(TYPE_VALITHRIA, FAIL); + } + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (m_fHP > 98.0f && m_creature->GetHealthPercent() == 100.0f) + uiDamage = 0; + } + + void DoSummonAdd(uint32 uiEntry) + { + uint32 loc = urand(0, m_bIs25Man ? 3 : 1); + m_creature->SummonCreature(uiEntry, SpawnLoc[loc].x, SpawnLoc[loc].y, SpawnLoc[loc].z, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + + // some additional control of summoning adds (anti flood system) + if (!m_bIsEnrage) + { + if (m_uiSummonAbominationTimer < 5000) + m_uiSummonAbominationTimer += 5000; + else if (m_uiSummonZombieTimer < 5000) + m_uiSummonZombieTimer += 5000; + + if (m_uiSummonArchmageTimer < 5000) + m_uiSummonArchmageTimer += 5000; + else if (m_uiSummonSkeletonTimer < 5000) + m_uiSummonSkeletonTimer += 5000; + } + } + + void DoRemoveAdds() + { + for (GuidList::iterator i = m_lSummonedAddsGuids.begin(); i != m_lSummonedAddsGuids.end(); ++i) + { + if (Creature* pTmp = m_creature->GetMap()->GetCreature(*i)) + pTmp->ForcedDespawn(); + } + + std::list lWorms; + GetCreatureListWithEntryInGrid(lWorms, m_creature, NPC_ROT_WORM, 100.0f); + for (std::list::iterator i = lWorms.begin(); i != lWorms.end(); ++i) + (*i)->ForcedDespawn(); + } + + Unit* SelectRandomPlayer(float range) + { + Map* pMap = m_creature->GetMap(); + Map::PlayerList const& playerlist = pMap->GetPlayers(); + if (playerlist.isEmpty()) + return NULL; + + std::vector list; + list.clear(); + + for (Map::PlayerList::const_iterator i = playerlist.begin(); i != playerlist.end(); ++i) + { + if (Player* player = i->getSource()) + { + if (player->isGameMaster()) + continue; + + if (!player->IsInMap(m_creature)) + continue; + + if (player->isAlive() && player->IsWithinDistInMap(m_creature, range)) + list.push_back((Unit*)player); + } + } + + if (list.empty()) + return NULL; + else + return list[urand(0, list.size() - 1)]; + } + + void JustSummoned(Creature* pCreature) override + { + m_lSummonedAddsGuids.push_back(pCreature->GetObjectGuid()); + if (pCreature->GetEntry() == NPC_SUPPRESSER) + pCreature->FixateTarget(m_creature); + else + { + pCreature->AddThreat(m_creature, 5000); + pCreature->AI()->AttackStart(m_creature); + } + pCreature->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_VALITHRIA) != IN_PROGRESS) + return; + + // Outro + if (m_bIsHealed) + { + if (m_uiOutroTimer <= uiDiff) + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_VALITHRIA, DONE); + + if (Creature* pDummy = m_pInstance->GetSingleCreatureFromStorage(NPC_GREEN_DRAGON_COMBAT_TRIGGER)) + { + // Set Valithria credit + pDummy->CastSpell(pDummy, SPELL_ACHIEVEMENT_CREDIT, true); + } + } + + DoRemoveAdds(); // just to be sure + m_uiOutroTimer = 30000; + m_creature->ForcedDespawn(1000); + } + else + m_uiOutroTimer -= uiDiff; + + return; + } + + // Health Check + if (m_uiHealthCheckTimer <= uiDiff) + { + m_fHP = m_creature->GetHealthPercent(); + + // when reached 75% health + if (!m_bSaidOver75) + { + if (m_fHP > 75.0f) + { + DoScriptText(SAY_75_HEALTH, m_creature); + m_bSaidOver75 = true; + } + } + + // when reached 25% health + if (!m_bSaidOver25) + { + if (m_fHP < 25.0f) + { + DoScriptText(SAY_25_HEALTH, m_creature); + m_bSaidOver25 = true; + } + } + + // check if encounter is completed + if (m_fHP > 99.0f && m_creature->GetHealth() == m_creature->GetMaxHealth()) + { + if (DoCastSpellIfCan(m_creature, SPELL_DREAMWALKER_RAGE) == CAST_OK) + { + DoScriptText(SAY_VICTORY, m_creature); + m_creature->RemoveAllAuras(); + m_bIsHealed = true; + return; + } + } + + m_uiHealthCheckTimer = 1000; + } + else + m_uiHealthCheckTimer -= uiDiff; + + // Enrage + // After 7 minutes summoning of Suppressers is much faster + if (!m_bIsEnrage) + { + if (m_uiEnrageTimer <= uiDiff) + { + DoScriptText(SAY_BERSERK, m_creature); + m_bIsEnrage = true; + } + else + m_uiEnrageTimer -= uiDiff; + } + + // Summon Portals + if (m_uiSummonPortalsTimer <= uiDiff) + { + uint8 uiMaxPortals = m_bIs25Man ? 8 : 4; + + // this way makes sure that spell is cast + // this should be done via ScriptEffect spell, but we don't need it in SD2 + for (uint8 i = 0; i < uiMaxPortals; ++i) + m_creature->CastSpell(m_creature, m_bIsHeroic ? SPELL_NIGHTMARE_PORTAL_PRE : SPELL_DREAM_PORTAL_PRE, true); + + if (!m_bIsHeroic) + DoScriptText(SAY_PORTAL, m_creature); + + m_uiSummonPortalsTimer = 45000; + } + else + m_uiSummonPortalsTimer -= uiDiff; + + // Summon adds + + // Summon Suppresser + if (m_uiSummonSuppresserTimer <= uiDiff) + { + for (uint32 i = 0; i < urand(1, m_bIs25Man ? 3 : 2) + m_uiSummonSuppresserCounter; ++i) + DoSummonAdd(NPC_SUPPRESSER); + + // 5s faster each summoning + m_uiSummonSuppresserTimer = 60000 - (m_uiSummonSuppresserCounter * 5000); + if (m_uiSummonSuppresserCounter < 10) + ++m_uiSummonSuppresserCounter; + } + else + m_uiSummonSuppresserTimer -= uiDiff; + + // Summon Blazing Skeleton + if (m_uiSummonSkeletonTimer <= uiDiff) + { + DoSummonAdd(NPC_BLAZING_SKELETON); + // 5s faster each summoning + m_uiSummonSkeletonTimer = 60000 - (m_uiSummonSkeletonCounter * 5000); + if (m_uiSummonSkeletonCounter < 10) + ++m_uiSummonSkeletonCounter; + } + else + m_uiSummonSkeletonTimer -= uiDiff; + + // Summon Abomination + if (m_uiSummonAbominationTimer <= uiDiff) + { + DoSummonAdd(NPC_GLUTTONOUS_ABOMINATION); + m_uiSummonAbominationTimer = urand(30000, 60000); + } + else + m_uiSummonAbominationTimer -= uiDiff; + + // Summon Zombie + if (m_uiSummonZombieTimer <= uiDiff) + { + DoSummonAdd(NPC_BLISTERING_ZOMBIE); + m_uiSummonZombieTimer = urand(25000, 50000); + } + else + m_uiSummonZombieTimer -= uiDiff; + + // Summon Archmage + if (m_uiSummonArchmageTimer <= uiDiff) + { + DoSummonAdd(NPC_RISEN_ARCHMAGE); + m_uiSummonArchmageTimer = urand(20000, 50000); + } + else + m_uiSummonArchmageTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_valithria_dreamwalker(Creature* pCreature) +{ + return new boss_valithria_dreamwalkerAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_valithria_dream_phaseAI : public ScriptedAI +{ + mob_valithria_dream_phaseAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->HandleEmoteState(EMOTE_STATE_FLYGRABCLOSED); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + void Reset() override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} + void AttackStart(Unit* /*pWho*/) override {} + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_VALITHRIA) == IN_PROGRESS) + { + Creature* pValithria = m_pInstance->GetSingleCreatureFromStorage(NPC_VALITHRIA); + if (pValithria && pValithria->isAlive()) + { + pValithria->DealDamage(pValithria, uiDamage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + + uiDamage = 0; + } +}; + +CreatureAI* GetAI_mob_valithria_dream_phase(Creature* pCreature) +{ + return new mob_valithria_dream_phaseAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_valithria_combat_triggerAI : public ScriptedAI +{ + mob_valithria_combat_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + SetCombatMovement(false); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiCheckTimer; + uint32 m_uiResetTimer; + + void Reset() override + { + m_uiCheckTimer = 2000; + m_uiResetTimer = 0; + + if (m_pInstance && m_pInstance->GetData(TYPE_VALITHRIA) != DONE) + { + m_creature->SummonCreature(NPC_VALITHRIA, TEMPSUMMON_MANUAL_DESPAWN, 0); + } + } + + void AttackStart(Unit* /*pWho*/) override {} + void EnterEvadeMode() override {} + + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance) + return; + + uint32 uiState = m_pInstance->GetData(TYPE_VALITHRIA); + if (uiState == IN_PROGRESS || uiState == DONE) + return; + + if (pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->GetDistance(pWho) < 50.0f) + { + Creature* pGreenDragon = m_pInstance->GetSingleCreatureFromStorage(NPC_VALITHRIA); + if (pGreenDragon && pGreenDragon->isAlive()) + { + DoScriptText(SAY_AGGRO, pGreenDragon); + DoCastSpellIfCan(pGreenDragon, SPELL_IMMUNITY, CAST_TRIGGERED); + m_pInstance->SetData(TYPE_VALITHRIA, IN_PROGRESS); + m_creature->SetInCombatWithZone(); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_VALITHRIA) == DONE) + return; + + if (m_uiResetTimer) + { + if (m_uiResetTimer <= uiDiff) + { + if (Creature* pGreenDragon = m_pInstance->GetSingleCreatureFromStorage(NPC_VALITHRIA)) + { + pGreenDragon->ForcedDespawn(); + Reset(); + } + m_uiResetTimer = 0; + } + else + m_uiResetTimer -= uiDiff; + + return; + } + + if (m_uiCheckTimer <= uiDiff) + { + if (Creature* pGreenDragon = m_pInstance->GetSingleCreatureFromStorage(NPC_VALITHRIA)) + { + if (!pGreenDragon->isAlive()) + m_uiResetTimer = 60000; + } + + m_uiCheckTimer = 2000; + } + else + m_uiCheckTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_valithria_combat_trigger(Creature* pCreature) +{ + return new mob_valithria_combat_triggerAI(pCreature); +}; + +// Gluttonous Abomination +struct MANGOS_DLL_DECL mob_gluttonous_abominationAI : public ScriptedAI +{ + mob_gluttonous_abominationAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiGutSprayTimer; + + void Reset() override + { + m_uiGutSprayTimer = urand(3000, 5000); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_ROT_WORM_SPAWNER, CAST_TRIGGERED); + } + + void JustSummoned(Creature* pCreature) override + { + pCreature->SetInCombatWithZone(); + pCreature->CastSpell(pCreature, SPELL_ROT_WORM, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Gut Spray + if (m_uiGutSprayTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GUT_SPRAY) == CAST_OK) + m_uiGutSprayTimer = urand(5000, 10000); + } + else + m_uiGutSprayTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_gluttonous_abomination(Creature* pCreature) +{ + return new mob_gluttonous_abominationAI(pCreature); +}; + +// Blistering Zombie +struct MANGOS_DLL_DECL mob_blistering_zombieAI : public ScriptedAI +{ + mob_blistering_zombieAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + bool m_bHasDied; + + void Reset() override + { + m_bHasDied = false; + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_CORROSION, CAST_TRIGGERED); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (uiDamage > m_creature->GetHealth()) + { + uiDamage = 0; + SetCombatMovement(false, true); + if (!m_bHasDied) + { + if (DoCastSpellIfCan(m_creature, SPELL_ACID_BURST) == CAST_OK) + { + m_bHasDied = true; + m_creature->ForcedDespawn(1000); // 750ms need for cast spell + } + } + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_bHasDied) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_blistering_zombie(Creature* pCreature) +{ + return new mob_blistering_zombieAI(pCreature); +}; + +// Risen Archmage +struct MANGOS_DLL_DECL mob_risen_archmageAI : public ScriptedAI +{ + mob_risen_archmageAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiFrostboltVolleyTimer; + uint32 m_uiColumnOfFrostTimer; + uint32 m_uiManaVoidTimer; + + void Reset() override + { + m_uiFrostboltVolleyTimer = urand(3000, 5000); + m_uiColumnOfFrostTimer = urand(3000, 5000); + m_uiManaVoidTimer = urand(5000, 10000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Frostbolt Volley + if (m_uiFrostboltVolleyTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FROSTBOLT_VOLLEY) == CAST_OK) + m_uiFrostboltVolleyTimer = urand(5000, 15000); + } + else + m_uiFrostboltVolleyTimer -= uiDiff; + + // Column of Frost + if (m_uiColumnOfFrostTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_COLUMN_OF_FROST) == CAST_OK) + m_uiColumnOfFrostTimer = urand(10000, 15000); + } + } + else + m_uiColumnOfFrostTimer -= uiDiff; + + // Mana Void + if (m_uiManaVoidTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MANA_VOID) == CAST_OK) + m_uiManaVoidTimer = urand(10000, 15000); + } + } + else + m_uiManaVoidTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_risen_archmage(Creature* pCreature) +{ + return new mob_risen_archmageAI(pCreature); +}; + +// Blazing Skeleton +struct MANGOS_DLL_DECL mob_blazing_skeletonAI : public ScriptedAI +{ + mob_blazing_skeletonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 m_uiFireballTimer; + uint32 m_uiLayWasteTimer; + + void Reset() override + { + m_uiFireballTimer = urand(3000, 5000); + m_uiLayWasteTimer = urand(15000, 30000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Fireball + if (m_uiFireballTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIREBALL) == CAST_OK) + m_uiFireballTimer = urand(3000, 5000); + } + } + else + m_uiFireballTimer -= uiDiff; + + // Lay Waste + if (m_uiLayWasteTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LAY_WASTE) == CAST_OK) + m_uiLayWasteTimer = urand(20000, 25000); + } + else + m_uiLayWasteTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_blazing_skeleton(Creature* pCreature) +{ + return new mob_blazing_skeletonAI(pCreature); +}; + +// Suppresser +struct MANGOS_DLL_DECL mob_suppresserAI : public ScriptedAI +{ + mob_suppresserAI(Creature* pCreature) : ScriptedAI(pCreature){} + + void Reset() override {} + + void AttackStart(Unit* pWho) override + { + 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, m_creature->GetAngle(pWho)); + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + if (m_creature->GetDistance2d(m_creature->getVictim()) < 21.0f) + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUPPRESSION); + } +}; + +CreatureAI* GetAI_mob_suppresser(Creature* pCreature) +{ + return new mob_suppresserAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_dream_portal_preAI : public ScriptedAI +{ + mob_dream_portal_preAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_uiSummonTimer = 10000; + } + + uint32 m_uiSummonTimer; + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSummonTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DREAM_PORTAL, CAST_TRIGGERED) == CAST_OK) + { + m_uiSummonTimer = 1000; + m_creature->ForcedDespawn(500); + } + } + else + m_uiSummonTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_dream_portal_pre(Creature* pCreature) +{ + return new mob_dream_portal_preAI(pCreature); +}; + +bool GossipHello_mob_dream_portal(Player* pPlayer, Creature* pCreature) +{ + pPlayer->CastSpell(pPlayer, SPELL_DREAM_STATE, true); + pCreature->ForcedDespawn(); + return true; +} + +struct MANGOS_DLL_DECL mob_dream_cloudAI : public ScriptedAI +{ + mob_dream_cloudAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->SetRespawnDelay(15); + Reset(); + } + + bool m_bHasCast; + uint32 m_uiTimeToReset; + + void Reset() override + { + m_bHasCast = false; + DoCastSpellIfCan(m_creature, SPELL_DREAM_CLOUD_VISUAL, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override {} + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bHasCast) + return; + + if (pWho->GetTypeId() == TYPEID_PLAYER) + { + if (m_creature->GetDistance(pWho) < 5.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_EMERALD_VIGOR) == CAST_OK) + { + m_bHasCast = true; + m_uiTimeToReset = 30000; // simulating respawn + m_creature->RemoveAllAuras(); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bHasCast) + { + if (m_uiTimeToReset <= uiDiff) + { + Reset(); + } + else + m_uiTimeToReset -= uiDiff; + } + } +}; + +CreatureAI* GetAI_mob_dream_cloud(Creature* pCreature) +{ + return new mob_dream_cloudAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_nightmare_portal_preAI : public ScriptedAI +{ + mob_nightmare_portal_preAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_uiSummonTimer = 15000; + } + + uint32 m_uiSummonTimer; + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSummonTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NIGHTMARE_PORTAL, CAST_TRIGGERED) == CAST_OK) + { + m_uiSummonTimer = 1000; + m_creature->ForcedDespawn(500); + } + } + else + m_uiSummonTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_nightmare_portal_pre(Creature* pCreature) +{ + return new mob_nightmare_portal_preAI(pCreature); +}; + +bool GossipHello_mob_nightmare_portal(Player* pPlayer, Creature* pCreature) +{ + pPlayer->CastSpell(pPlayer, SPELL_DREAM_STATE, true); + pCreature->ForcedDespawn(); + return true; +} + +struct MANGOS_DLL_DECL mob_nightmare_cloudAI : public ScriptedAI +{ + mob_nightmare_cloudAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + bool m_bHasCast; + uint32 m_uiTimeToReset; + + void Reset() override + { + m_bHasCast = false; + DoCastSpellIfCan(m_creature, SPELL_NIGHTMARE_CLOUD_VISUAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_NIGHTMARE_CLOUD, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override {} + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bHasCast) + return; + + if (pWho->GetTypeId() == TYPEID_PLAYER) + { + if (m_creature->GetDistance(pWho) < 5.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWISTED_NIGHTMARES) == CAST_OK) + { + m_bHasCast = true; + m_uiTimeToReset = 30000; // simulating respawn + m_creature->RemoveAllAuras(); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bHasCast) + { + if (m_uiTimeToReset <= uiDiff) + { + Reset(); + } + else + m_uiTimeToReset -= uiDiff; + } + } +}; + +CreatureAI* GetAI_mob_nightmare_cloud(Creature* pCreature) +{ + return new mob_nightmare_cloudAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_mana_voidAI : public ScriptedAI +{ + mob_mana_voidAI(Creature* pCreature) : ScriptedAI(pCreature) + { + DoCastSpellIfCan(m_creature, SPELL_VOID_BUFF, CAST_TRIGGERED); + m_creature->ForcedDespawn(30000); + } + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; + +CreatureAI* GetAI_mob_mana_void(Creature* pCreature) +{ + return new mob_mana_voidAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_column_of_frostAI : public ScriptedAI +{ + mob_column_of_frostAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_uiColumnOfFrostTimer = 3000; + DoCastSpellIfCan(m_creature, SPELL_COLUMN_OF_FROST_VISUAL, CAST_TRIGGERED); + } + + uint32 m_uiColumnOfFrostTimer; + + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 uiDiff) override + { + // Column of Frost + if (m_uiColumnOfFrostTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_COLUMN_OF_FROST_TRIG) == CAST_OK) + { + m_uiColumnOfFrostTimer = 2000; + m_creature->ForcedDespawn(1000); + } + } + else + m_uiColumnOfFrostTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_column_of_frost(Creature* pCreature) +{ + return new mob_column_of_frostAI(pCreature); +}; + +void AddSC_boss_valithria_dreamwalker() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_valithria_dreamwalker"; + pNewScript->GetAI = &GetAI_boss_valithria_dreamwalker; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_valithria_dream_phase"; + pNewScript->GetAI = &GetAI_mob_valithria_dream_phase; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_valithria_combat_trigger"; + pNewScript->GetAI = &GetAI_mob_valithria_combat_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_gluttonous_abomination"; + pNewScript->GetAI = &GetAI_mob_gluttonous_abomination; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_blistering_zombie"; + pNewScript->GetAI = &GetAI_mob_blistering_zombie; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_risen_archmage"; + pNewScript->GetAI = &GetAI_mob_risen_archmage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_blazing_skeleton"; + pNewScript->GetAI = &GetAI_mob_blazing_skeleton; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_suppresser"; + pNewScript->GetAI = &GetAI_mob_suppresser; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_nightmare_portal_pre"; + pNewScript->GetAI = &GetAI_mob_nightmare_portal_pre; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_nightmare_portal"; + pNewScript->pGossipHello = &GossipHello_mob_nightmare_portal; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_nightmare_cloud"; + pNewScript->GetAI = &GetAI_mob_nightmare_cloud; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_dream_portal_pre"; + pNewScript->GetAI = &GetAI_mob_dream_portal_pre; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_dream_portal"; + pNewScript->pGossipHello = &GossipHello_mob_dream_portal; + + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_dream_cloud"; + pNewScript->GetAI = &GetAI_mob_dream_cloud; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_mana_void"; + pNewScript->GetAI = &GetAI_mob_mana_void; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_column_of_frost"; + pNewScript->GetAI = &GetAI_mob_column_of_frost; + 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 669cd21989..b0abfbd701 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,3 +22,66 @@ SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" + +/* +enum +{ + // saurfang & bronzebeard + SPELL_BATTLE_FURY = 69637, + SPELL_CLEAVE = 15284, + SPELL_RENDING_THROW = 70309, + SPELL_TASTE_BLOOD = 69634, + NPC_BRONZEBEARD = 36948, + NPC_SAURFANG = 36939, + + // all troops + SPELL_EXPERIENCED = 71188, + SPELL_VETERAN = 71193, + SPELL_ELITE = 71195, + SPELL_DESPERATE_RESOLVE = 72536, + + // sergeant + SPELL_BLADESTORM = 69652, + SPELL_WOUNDING_STRIKE = 69651, + NPC_KORKRON_SERGEANT = 36960, + NPC_SKYBREAKER_SERGEANT = 36961, + + // soldiers + SPELL_BURNING_PITCH = 71335, + NPC_KORKRON_REAVER = 36957, + NPC_SKYBREKER_MARINE = 36950, + + // axethrower / rifleman + SPELL_HURL_AXE = 72539, + NPC_KORKRON_AXETHROWER = 36968, + SPELL_SHOOT = 70162, + NPC_SKYBREAKER_RIFLEMAN = 36969, + + // rocketeer / mortar soldier + SPELL_ROCKET_ARTILLERY = 69679, + NPC_KORKRON_ROCKETEER = 36982, + NPC_SKYBREAKER_MORTAR = 36978, + + SPELL_BELOW_ZERO = 69705, + NPC_KORKRON_BATTLEMAGE = 37117, + NPC_SKYBREAKER_SORCERER = 37116, + + // cannons + NPC_ALY_GUNSHIP_CANNON = 36838, + NPC_HORDE_GUNSHIP_CANNON= 36839, +}; + +enum AI +{ + AI_MELEE = 0, + AI_RANGED = 1, +}; + +#define GOSSIP_ITEM "????! " + +Transport *Gunship_A = new Transport; +Transport *Gunship_H = new Transport;*/ + +void AddSC_gunship_battle() +{ +} \ No newline at end of file diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h new file mode 100644 index 0000000000..fa4cbb638e --- /dev/null +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h @@ -0,0 +1,362 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * 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 +#include "BSW_instance.h" +#include "BSW_ai.h" + +enum +{ + TYPE_TELEPORT = 0, + TYPE_ICC_INTRO = 1, + TYPE_MARROWGAR = 2, + TYPE_LADY_DEATHWHISPER = 3, + TYPE_FLIGHT_WAR = 4, + TYPE_DEATHBRINGER_SAURFANG = 5, + TYPE_FESTERGUT = 6, + TYPE_ROTFACE = 7, + TYPE_PROFESSOR_PUTRICIDE = 8, + TYPE_BLOOD_PRINCE_COUNCIL = 9, + TYPE_QUEEN_LANATHEL = 10, + TYPE_VALITHRIA = 11, + TYPE_SINDRAGOSA = 12, + TYPE_LICH_KING = 13, + TYPE_FROSTMOURNE_ROOM = 14, + TYPE_KINGS_OF_ICC = 15, + TYPE_ICECROWN_QUESTS = 16, + TYPE_STINKY = 17, + TYPE_PRECIOUS = 18, + MAX_ENCOUNTERS, + + NPC_DAMNED = 37011, + NPC_HIGHLORD_TIRION_FORDRING_LH = 37119, + NPC_THE_LICH_KING_LH = 37181, + NPC_HIGHLORD_BOLVAR_FORDRAGON_LH = 37183, + NPC_SAURFANG_LH = 37187, + NPC_MURADIN_LH = 37200, + + 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_VALITHRIA_QUEST = 38589, + NPC_SINDRAGOSA = 36853, + NPC_LICH_KING = 36597, + + NPC_QUEEN_LANATHEL_INTRO = 38004, + NPC_BLOOD_ORB_CONTROL = 38008, + + NPC_MURADIN = 36948, + + NPC_TIRION = 38995, + NPC_MENETHIL = 38579, + + NPC_FROSTMOURNE_TRIGGER = 38584, + NPC_FROSTMOURNE_HOLDER = 27880, + + NPC_STINKY = 37025, + NPC_PRECIOUS = 37217, + + NPC_RIMEFANG = 37533, + NPC_SPINESTALKER = 37534, + + NPC_GREEN_DRAGON_COMBAT_TRIGGER = 38752, + + GO_TELEPORT_GOSSIP_MESSAGE = 99323, + TELEPORT_GOSSIP_MESSAGE = 99322, + + GO_INSTANCE_PORTAL = 202347, + + GO_ICEWALL_1 = 201911, + GO_ICEWALL_2 = 201910, + + GO_MARROWGAR_DOOR = 201857, + + GO_ORATORY_DOOR = 201563, + GO_DEATHWHISPER_ELEVATOR = 202220, //5653 + + GO_SAURFANG_DOOR = 201825, + + GO_GAS_RELEASE_VALVE = 201616, //72479 + + GO_ORANGE_PLAGUE = 201371, //72536 + GO_GREEN_PLAGUE = 201370, //72537 + + GO_DRINK_ME_TABLE = 201584, + + GO_SCIENTIST_DOOR_GREEN = 201614, //72530 + GO_SCIENTIST_DOOR_ORANGE = 201613, //72531 + GO_SCIENTIST_DOOR_COLLISION = 201612, + GO_SCIENTIST_DOOR = 201372, //72541 + + GO_ORANGE_TUBES = 201617, + GO_GREEN_TUBES = 201618, + + GO_BLOODWING_DOOR = 201920, //72532 + GO_CRIMSON_HALL_DOOR = 201376, //72532 + GO_COUNCIL_DOOR_1 = 201377, //72533 + GO_COUNCIL_DOOR_2 = 201378, //72534 + + GO_BLOODPRINCE_DOOR = 201746, + GO_ICECROWN_GRATE = 201755, + + GO_FROSTWING_DOOR = 201919, + GO_GREEN_DRAGON_DOOR_1 = 201375, //1202 + GO_GREEN_DRAGON_DOOR_2 = 201374, //1200 + GO_VALITHRIA_DOOR_1 = 201381, //1618 + GO_VALITHRIA_DOOR_2 = 201382, //1482 + GO_VALITHRIA_DOOR_3 = 201383, //1335 + GO_VALITHRIA_DOOR_4 = 201380, //1558 + + GO_SINDRAGOSA_DOOR_1 = 201369, //1619 + GO_SINDRAGOSA_DOOR_2 = 201379, + + GO_SINDRAGOSA_ENTRANCE = 201373, + GO_SINDRAGOSA_ICE_WALL = 202396, + + GO_FROZENTRONE_TR = 202223, //72061 + + GO_SAURFANG_CACHE_10 = 202239, + GO_SAURFANG_CACHE_25 = 202240, + GO_SAURFANG_CACHE_10_H = 202238, + GO_SAURFANG_CACHE_25_H = 202241, + + GO_GUNSHIP_ARMORY_A_10 = 201872, // + GO_GUNSHIP_ARMORY_A_25 = 201873, // + GO_GUNSHIP_ARMORY_A_10H = 201874, // + GO_GUNSHIP_ARMORY_A_25H = 201875, // + + GO_GUNSHIP_ARMORY_H_10 = 202177, // + GO_GUNSHIP_ARMORY_H_25 = 202178, // + GO_GUNSHIP_ARMORY_H_10H = 202179, // + GO_GUNSHIP_ARMORY_H_25H = 202180, // + + GO_DREAMWALKER_CACHE_10 = 201959, // + GO_DREAMWALKER_CACHE_25 = 202339, // + GO_DREAMWALKER_CACHE_10_H = 202338, // + GO_DREAMWALKER_CACHE_25_H = 202340, // + + GO_PLAGUE_SIGIL = 202182, + GO_FROSTWING_SIGIL = 202181, + GO_BLOODWING_SIGIL = 202183, + + GO_ICESHARD_1 = 202142, //8304 + GO_ICESHARD_2 = 202141, //8364 + GO_ICESHARD_3 = 202143, //8310 + GO_ICESHARD_4 = 202144, //9007 + + GO_FROSTY_WIND = 202188, // + GO_FROSTY_EDGE = 202189, // + GO_SNOW_EDGE = 202190, // + GO_ARTHAS_PLATFORM = 202161, // + GO_ARTHAS_PRECIPICE = 202078, // + + TYPE_EVENT_TIMER = 99, + TYPE_EVENT = 100, + TYPE_EVENT_NPC = 101, + MAP_NUM = 631, + DATA_DIRECTION = 1001, + DATA_BLOOD_INVOCATION = 1002, + DESPAWN_TIME = 300000, + SPELL_SHADOWS_EDGE = 71168, + +}; + +enum AchievementCriteriaIds +{ + // Lord Marrowgar + CRITERIA_BONED_10N = 12775, + CRITERIA_BONED_25N = 12962, + CRITERIA_BONED_10H = 13393, + CRITERIA_BONED_25H = 13394, + + // Lady Deathwhisper + CRITERIA_FULL_HOUSE_10N = 12776, + CRITERIA_FULL_HOUSE_25N = 12997, + CRITERIA_FULL_HOUSE_10H = 12995, + CRITERIA_FULL_HOUSE_25H = 12998, + + // Gunship Battle + CRITERIA_IM_ON_A_BOAT_10N = 12777, + CRITERIA_IM_ON_A_BOAT_25N = 13080, + CRITERIA_IM_ON_A_BOAT_10H = 13079, + CRITERIA_IM_ON_A_BOAT_25H = 13081, + + // Deathbringer Saurfang + CRITERIA_IVE_GONE_AND_MADE_A_MESS_10N = 12778, + CRITERIA_IVE_GONE_AND_MADE_A_MESS_25N = 13036, + CRITERIA_IVE_GONE_AND_MADE_A_MESS_10H = 13035, + CRITERIA_IVE_GONE_AND_MADE_A_MESS_25H = 13037, + + // Festergut + CRITERIA_FLU_SHOT_SHORTAGE_10N = 12977, + CRITERIA_FLU_SHOT_SHORTAGE_25N = 12982, + CRITERIA_FLU_SHOT_SHORTAGE_10H = 12986, + CRITERIA_FLU_SHOT_SHORTAGE_25H = 12967, + + // Rotface + CRITERIA_DANCES_WITH_OOZES_10N = 12984, + CRITERIA_DANCES_WITH_OOZES_25N = 12966, + CRITERIA_DANCES_WITH_OOZES_10H = 12985, + CRITERIA_DANCES_WITH_OOZES_25H = 12983, + + // Professor Putricide + CRITERIA_NAUSEA_10N = 12987, + CRITERIA_NAUSEA_25N = 12968, + CRITERIA_NAUSEA_10H = 12988, + CRITERIA_NAUSEA_25H = 12981, + + // Blood Prince Council + CRITERIA_ORB_WHISPERER_10N = 13033, + CRITERIA_ORB_WHISPERER_25N = 12969, + CRITERIA_ORB_WHISPERER_10H = 13034, + CRITERIA_ORB_WHISPERER_25H = 13032, + + // Blood-Queen Lana'thel + CRITERIA_KILL_LANA_THEL_10M = 13340, + CRITERIA_KILL_LANA_THEL_25M = 13360, + + // Valithria Dreamwalker + CRITERIA_PORTAL_JOCKEY_10N = 12978, + CRITERIA_PORTAL_JOCKEY_25N = 12971, + CRITERIA_PORTAL_JOCKEY_10H = 12979, + CRITERIA_PORTAL_JOCKEY_25H = 12980, + + // Sindragosa + CRITERIA_ALL_YOU_CAN_EAT_10N = 12822, + CRITERIA_ALL_YOU_CAN_EAT_25N = 12972, + CRITERIA_ALL_YOU_CAN_EAT_10V = 12996, + CRITERIA_ALL_YOU_CAN_EAT_25V = 12989, + + // Lich King - Been Waiting a Long Time For This + CRITERIA_BEEN_WAITING_A_LONG_TIME_10N = 13246, + CRITERIA_BEEN_WAITING_A_LONG_TIME_25N = 13244, + CRITERIA_BEEN_WAITING_A_LONG_TIME_10H = 13247, + CRITERIA_BEEN_WAITING_A_LONG_TIME_25H = 13245, +}; + +enum Achievements +{ + ACHIEVE_BONED = 0, + ACHIEVE_FULL_HOUSE = 1, + ACHIEVE_IM_ON_A_BOAT = 2, + ACHIEVE_IVE_GONE_AND_MADE_A_MESS = 3, + ACHIEVE_FLU_SHOT_SHORTAGE = 4, + ACHIEVE_DANCES_WITH_OOZES = 5, + ACHIEVE_NAUSEA = 6, + ACHIEVE_ORB_WHISPERER = 7, + ACHIEVE_PORTAL_JOCKEY = 8, + ACHIEVE_ALL_YOU_CAN_EAT = 9, + ACHIEVE_BEEN_WAITING_A_LONG_TIME = 10, + ACHIEVE_MAX_COUNT = 11, +}; + +class MANGOS_DLL_DECL instance_icecrown_citadel : public ScriptedInstance +{ +public: + instance_icecrown_citadel(Map* pMap); + ~instance_icecrown_citadel() {} + + void Initialize() override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + + bool IsEncounterInProgress() const override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return strSaveData.c_str(); } + void Load(const char* chrIn) override; + +private: + + Difficulty m_uiMapDifficulty; + std::string strSaveData; + + //Creatures GUID + uint32 m_auiEncounter[MAX_ENCOUNTERS]; + + bool m_bAchievCriteria[ACHIEVE_MAX_COUNT]; + + // uint32 m_uiCouncilInvocation; + + // uint32 m_auiEvent; + // uint32 m_auiEventTimer; + // uint32 m_uiDirection; + + // uint32 m_uiStinkystate; + // uint32 m_uiPreciousstate; + uint32 m_uiGunshipArmoryA_ID; + uint32 m_uiGunshipArmoryH_ID; + uint32 m_uiValithriaCache; + uint32 m_uiSaurfangCache; +}; + +struct MANGOS_DLL_DECL base_icc_bossAI : public ScriptedAI +{ + base_icc_bossAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Difficulty uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + bool m_bIs25Man; + + void Reset() override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} + + Unit* SelectRandomRangedTarget(Unit* pSource) + { + Unit* pResult = NULL; + std::list lTargets; + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + + for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + { + if (!(*i)->getUnitGuid().IsPlayer()) + continue; + + if (Unit* pTmp = m_creature->GetMap()->GetUnit((*i)->getUnitGuid())) + lTargets.push_back(pTmp); + } + + if (!lTargets.empty()) + { + uint8 max = m_bIs25Man ? 8 : 3; + std::list::iterator iter; + + lTargets.sort(ObjectDistanceOrderReversed(pSource)); + iter = lTargets.begin(); + + if (max >= lTargets.size()) + max = lTargets.size() - 1; + + std::advance(iter, urand(0, max)); + pResult = (*iter); + } + + return pResult; + } +}; + +#endif diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_lights_hammer.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_lights_hammer.cpp new file mode 100644 index 0000000000..e14639cb9e --- /dev/null +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_lights_hammer.cpp @@ -0,0 +1,330 @@ +/* Copyright (C) 2013 by boxa for ScriptDev2_R2 + * This program is free software; you can redistribute it and/or modify + * 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: icecrown_lights_hammer +SD%Complete: 100% +SDComment: ICC start event +SDCategory: Icecrown Citadel +EndScriptData */ + +/* ContentData +npc_tirion_fordring_lh +npc_the_damned_lh +EndContentData */ + +#include "precompiled.h" +#include "icecrown_citadel.h" + +/*###### +## npc_tirion_fordring_lh +######*/ + +enum +{ + // Highlord Tirion Fordring + SAY_TIRION_INTRO_1 = -1020500, + SAY_TIRION_INTRO_2 = -1020501, + SAY_TIRION_INTRO_3 = -1020502, + SAY_TIRION_INTRO_4 = -1020503, + SAY_TIRION_INTRO_H_5 = -1020504, + SAY_TIRION_INTRO_A_5 = -1020505, + // The Lich King + SAY_LK_INTRO_1 = -1020506, + SAY_LK_INTRO_2 = -1020507, + SAY_LK_INTRO_3 = -1020508, + SAY_LK_INTRO_4 = -1020509, + SAY_LK_INTRO_5 = -1020510, + // Highlord Bolvar Fordragon + SAY_BOLVAR_INTRO_1 = -1020511, + // High Overlord Saurfang + SAY_SAURFANG_INTRO_1 = -1020512, + SAY_SAURFANG_INTRO_2 = -1020513, + SAY_SAURFANG_INTRO_3 = -1020514, + SAY_SAURFANG_INTRO_4 = -1020515, + // Muradin Bronzebeard + SAY_MURADIN_INTRO_1 = -1020516, + SAY_MURADIN_INTRO_2 = -1020517, + SAY_MURADIN_INTRO_3 = -1020518, + // Emotions + EMOTE_EXCLAMATION = -1020519, + EMOTE_POINT_NOSHEATHE = -1020520, + EMOTE_TALK = -1020521, + // Npcs + NPC_ALLIANCE_COMMANDER = 37190, + NPC_KORKRON_GENERAL = 37189, + // Dialogue steps + SELECT_NEXT_DIALOGUE = 1, + SAURFANG_INTRO_END = 2, + MURADIN_INTRO_END = 3, +}; + +static const DialogueEntry iccIntroDialogue[] = +{ + // Common + {SAY_TIRION_INTRO_1, NPC_HIGHLORD_TIRION_FORDRING_LH, 4000}, + {EMOTE_EXCLAMATION, NPC_HIGHLORD_TIRION_FORDRING_LH, 9000}, + {SAY_TIRION_INTRO_2, NPC_HIGHLORD_TIRION_FORDRING_LH, 5000}, + {EMOTE_EXCLAMATION, NPC_HIGHLORD_TIRION_FORDRING_LH, 11000}, + {SAY_TIRION_INTRO_3, NPC_HIGHLORD_TIRION_FORDRING_LH, 4000}, + {SAY_LK_INTRO_1, NPC_THE_LICH_KING_LH, 10}, + {EMOTE_POINT_NOSHEATHE, NPC_HIGHLORD_TIRION_FORDRING_LH, 13000}, + {SAY_TIRION_INTRO_4, NPC_HIGHLORD_TIRION_FORDRING_LH, 8000}, + {SAY_LK_INTRO_2, NPC_THE_LICH_KING_LH, 13000}, + {SAY_LK_INTRO_3, NPC_THE_LICH_KING_LH, 9000}, + {SAY_LK_INTRO_4, NPC_THE_LICH_KING_LH, 21000}, + {SAY_LK_INTRO_5, NPC_THE_LICH_KING_LH, 5000}, + {SAY_BOLVAR_INTRO_1, NPC_HIGHLORD_BOLVAR_FORDRAGON_LH, 6000}, + {SELECT_NEXT_DIALOGUE, 0, 0}, + // Horde + {SAY_SAURFANG_INTRO_1, NPC_SAURFANG_LH, 6000}, + {SAY_TIRION_INTRO_H_5, NPC_HIGHLORD_TIRION_FORDRING_LH, 8000}, + {SAY_SAURFANG_INTRO_2, NPC_SAURFANG_LH, 10000}, + {SAY_SAURFANG_INTRO_3, NPC_SAURFANG_LH, 9000}, + {SAY_SAURFANG_INTRO_4, NPC_SAURFANG_LH, 11000}, + {SAURFANG_INTRO_END, 0, 0}, + // Alliance + {SAY_MURADIN_INTRO_1, NPC_MURADIN_LH, 2000}, + {EMOTE_TALK, NPC_MURADIN_LH, 2000}, + {EMOTE_EXCLAMATION, NPC_MURADIN_LH, 8000}, + {SAY_TIRION_INTRO_A_5, NPC_HIGHLORD_TIRION_FORDRING_LH, 3000}, + {SAY_MURADIN_INTRO_2, NPC_MURADIN_LH, 4000}, + {SAY_MURADIN_INTRO_3, NPC_MURADIN_LH, 7000}, + {MURADIN_INTRO_END, 0, 0}, + {0, 0, 0}, +}; + +struct MANGOS_DLL_DECL npc_tirion_fordring_lhAI : public ScriptedAI, private DialogueHelper +{ + npc_tirion_fordring_lhAI(Creature* pCreature) : ScriptedAI(pCreature), DialogueHelper(iccIntroDialogue) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + ScriptedInstance* m_pInstance; + + enum + { + STAGE_IDLE = 0, + STAGE_WAIT = 1, + STAGE_START = 2 + }; + + uint32 m_stage; + + void Reset() override + { + m_stage = (m_pInstance && m_pInstance->GetData(TYPE_ICC_INTRO) != DONE) ? STAGE_WAIT : STAGE_IDLE; + + if (m_stage != STAGE_IDLE) + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + else // if already completed intro + { + HideChiefAndFollowers(NPC_SAURFANG_LH, NPC_KORKRON_GENERAL); + HideChiefAndFollowers(NPC_MURADIN_LH, NPC_ALLIANCE_COMMANDER); + } + } + + void HideChiefAndFollowers(uint32 chiefId, uint32 followerId) + { + if (!m_pInstance) + return; + + Creature* pChief = m_pInstance->GetSingleCreatureFromStorage(chiefId); + if (!pChief) + return; + + pChief->SetVisibility(VISIBILITY_OFF); + + std::list followers; + GetCreatureListWithEntryInGrid(followers, pChief, followerId, 10.0f); + + if (followers.empty()) + return; + + for (std::list::const_iterator itr = followers.begin(); itr != followers.end(); ++itr) + { + if (Creature* pFollower = *itr) + pFollower->SetVisibility(VISIBILITY_OFF); + } + } + + void MoveToInstanceExit(uint32 chiefId, uint32 followerId) + { + if (!m_pInstance) + return; + + m_stage = STAGE_IDLE; + + Creature* pChief = m_pInstance->GetSingleCreatureFromStorage(chiefId); + if (!pChief) + return; + + if (GameObject* pPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_INSTANCE_PORTAL)) + { + std::list followers; + GetCreatureListWithEntryInGrid(followers, pChief, followerId, 10.0f); + + if (!followers.empty()) + { + for (std::list::const_iterator itr = followers.begin(); itr != followers.end(); ++itr) + { + if (Creature* pFollower = *itr) + { + pFollower->SetWalk(false); + pFollower->addUnitState(UNIT_STAT_IGNORE_PATHFINDING); + pFollower->GetMotionMaster()->MoveFollow(pChief, 5.0f, pFollower->GetAngle(pChief)); + pFollower->ForcedDespawn(15000); + } + } + } + + pChief->SetWalk(false); + pChief->GetMotionMaster()->MovePoint(0, pPortal->GetPositionX(), pPortal->GetPositionY(), pPortal->GetPositionZ()); + } + + pChief->ForcedDespawn(15000); + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_pInstance->SetData(TYPE_ICC_INTRO, DONE); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + if (!m_pInstance) + return; + + if (m_stage != STAGE_IDLE && eventType == AI_EVENT_CUSTOM_A && pSender->GetEntry() == NPC_DAMNED) + { + if (m_stage++ == STAGE_START) + StartNextDialogueText(SAY_TIRION_INTRO_1); + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case SELECT_NEXT_DIALOGUE: + if (Player* pPlayer = m_pInstance->GetPlayerInMap()) + StartNextDialogueText(pPlayer->GetTeam() == HORDE ? SAY_SAURFANG_INTRO_1 : SAY_MURADIN_INTRO_1); + else + m_stage = STAGE_IDLE; + break; + case SAURFANG_INTRO_END: + MoveToInstanceExit(NPC_SAURFANG_LH, NPC_KORKRON_GENERAL); + break; + case MURADIN_INTRO_END: + MoveToInstanceExit(NPC_MURADIN_LH, NPC_ALLIANCE_COMMANDER); + break; + } + } + + void UpdateAI(uint32 const uiDiff) override + { + if (m_pInstance && m_stage != STAGE_IDLE) + DialogueUpdate(uiDiff); + } +}; + +CreatureAI* GetAI_npc_tirion_fordring_lh(Creature* pCreature) +{ + return new npc_tirion_fordring_lhAI(pCreature); +} + +/*###### +## npc_the_damned_lh +######*/ + +enum +{ + SPELL_BONE_FLURRY = 59697, + SPELL_SHATTERED_BONES = 70961 +}; + +struct MANGOS_DLL_DECL npc_the_damned_lhAI : public ScriptedAI +{ + npc_the_damned_lhAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + TTimer m_boneFlurryTimer; + bool onceShatteredBones; + + void Reset() override + { + m_boneFlurryTimer.Reset(10000, 15000); + onceShatteredBones = false; + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (!onceShatteredBones && uiDamage >= m_creature->GetHealth()) + { + onceShatteredBones = true; + m_creature->CastSpell(m_creature, SPELL_SHATTERED_BONES, false); + uiDamage = 0; + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_ICC_INTRO) != DONE) + { + if (Creature* pFordring = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING_LH)) + SendAIEvent(AI_EVENT_CUSTOM_A, NULL, pFordring); + } + } + + void UpdateAI(uint32 const uiDiff) override + { + if (!SelectVictim()) + return; + + if (m_boneFlurryTimer.Expired(uiDiff)) + { + if (DoCastSpellIfCan(m_creature, SPELL_BONE_FLURRY) == CAST_OK) + m_boneFlurryTimer.Reset(20000, 25000); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_the_damned_lh(Creature* pCreature) +{ + return new npc_the_damned_lhAI(pCreature); +} + +/*###### +## Register scripts +######*/ + +void AddSC_icecrown_lights_hammer() +{ + AutoScript s; + s.newScript("npc_tirion_fordring_lh")->GetAI = &GetAI_npc_tirion_fordring_lh; + s.newScript("npc_the_damned_lh")->GetAI = &GetAI_npc_the_damned_lh; +} diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_spire.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_spire.cpp new file mode 100644 index 0000000000..15cf935f6a --- /dev/null +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_spire.cpp @@ -0,0 +1,185 @@ +/* Copyright (C) 2006 - 2013 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: icecrown_spire +SD%Complete: 100% +SDComment: by /dev/rsa +SDCategory: Icecrown Citadel - mobs +EndScriptData */ + +#include "precompiled.h" +#include "icecrown_citadel.h" +enum +{ + SPELL_BERSERK = 47008, + SPELL_FROST_BREATH = 70116, + SPELL_BLIZZARD = 70362, + SPELL_CLEAVE = 70361, + + SPELL_STOMP = 64652, + SPELL_DEATH_PLAGUE = 72865, +// SPELL_DEATH_PLAGUE = 72879, + + SPELL_ACHIEVEMENT_CREDIT = 72959, + +}; + +struct MANGOS_DLL_DECL mob_spire_frostwyrmAI : public BSWScriptedAI +{ + mob_spire_frostwyrmAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* pInstance; + uint8 m_uiStage; + + void Reset() override + { + m_creature->SetRespawnDelay(DAY); + m_uiStage = 0; + resetTimers(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiStage) + { + case 0: + break; + case 1: + doCast(SPELL_BERSERK); + m_uiStage = 2; + break; + case 2: + default: + break; + } + + timedCast(SPELL_CLEAVE, uiDiff); + timedCast(SPELL_BLIZZARD, uiDiff); + timedCast(SPELL_FROST_BREATH, uiDiff); + + if (m_creature->GetHealthPercent() < 10.0f && m_uiStage == 0) + m_uiStage = 1; + + timedCast(SPELL_BERSERK, uiDiff); + + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_mob_spire_frostwyrm(Creature* pCreature) +{ + return new mob_spire_frostwyrmAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_frost_giantAI : public BSWScriptedAI +{ + mob_frost_giantAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* pInstance; + uint8 m_uiStage; + + void Aggro(Unit* /*pWho*/) override + { + if (pInstance) + pInstance->SetData(TYPE_FLIGHT_WAR, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (!pInstance) + return; + if (pKiller->GetTypeId() == TYPEID_PLAYER || pKiller->GetCharmerOrOwnerOrSelf()->GetTypeId() == TYPEID_PLAYER ) + pInstance->SetData(TYPE_FLIGHT_WAR, DONE); + + // Temporary + // Untill Gunship Battle will be implemented + m_creature->CastSpell(m_creature, SPELL_ACHIEVEMENT_CREDIT, false); + } + + void JustReachedHome() override + { + if (pInstance) pInstance->SetData(TYPE_FLIGHT_WAR, FAIL); + } + + void Reset() override + { + m_creature->SetRespawnDelay(7*DAY); + m_uiStage = 0; + resetTimers(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiStage) + { + case 0: + break; + case 1: + doCast(SPELL_BERSERK); + m_uiStage = 2; + break; + case 2: + default: + break; + } + timedCast(SPELL_STOMP, uiDiff); + timedCast(SPELL_DEATH_PLAGUE, uiDiff); + + if (m_creature->GetHealthPercent() < 2.0f && m_uiStage == 0) + m_uiStage = 1; + + timedCast(SPELL_BERSERK, uiDiff); + + DoMeleeAttackIfReady(); + + } +}; + +CreatureAI* GetAI_mob_frost_giant(Creature* pCreature) +{ + return new mob_frost_giantAI(pCreature); +} + +void AddSC_icecrown_spire() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_spire_frostwyrm"; + pNewScript->GetAI = &GetAI_mob_spire_frostwyrm; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_frost_giant"; + pNewScript->GetAI = &GetAI_mob_frost_giant; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_teleport.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_teleport.cpp new file mode 100644 index 0000000000..53db2eab06 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_teleport.cpp @@ -0,0 +1,152 @@ +/* Copyright (C) 2006 - 2013 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: icecrown_teleport +SD%Complete: 100% +SDComment: by /dev/rsa +SDCategory: Icecrown Citadel +EndScriptData */ +#include "precompiled.h" +#include "icecrown_citadel.h" + +enum +{ + PORTALS_COUNT = 7 +}; + +struct t_Locations +{ + int textNum; + uint32 spellID; + bool state; + bool active; + uint32 encounter; +}; + +static t_Locations PortalLoc[]= +{ + {-3631600, 70781, true, true, TYPE_TELEPORT}, + {-3631601, 70856, false, true, TYPE_MARROWGAR}, + {-3631602, 70857, false, true, TYPE_LADY_DEATHWHISPER}, + {-3631603, 70858, false, true, TYPE_LADY_DEATHWHISPER /*TYPE_FLIGHT_WAR*/}, + {-3631604, 70859, false, true, TYPE_DEATHBRINGER_SAURFANG}, + {-3631606, 70861, false, true, TYPE_VALITHRIA}, + {-3631607, 70860, false, true, TYPE_KINGS_OF_ICC} +}; + + +bool GOGossipSelect_go_icecrown_teleporter(Player* pPlayer, GameObject* pGo, uint32 sender, uint32 action) +{ + if (sender != GOSSIP_SENDER_MAIN) + return false; + + if (pPlayer->IsInCombat()) + return false; + + pPlayer->CastSpell(pPlayer, PortalLoc[action].spellID, false); + + pPlayer->CLOSE_GOSSIP_MENU(); + return true; +} + +bool GOGossipHello_go_icecrown_teleporter(Player* pPlayer, GameObject* pGo) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + + if (!pInstance || !pPlayer) + return false; + if (pPlayer->isInCombat()) + return true; + + for (uint8 i = 0; i < PORTALS_COUNT; ++i) + { + if (PortalLoc[i].active == true && (PortalLoc[i].state == true || pInstance->GetData(PortalLoc[i].encounter) == DONE || pPlayer->isGameMaster())) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_TAXI, PortalLoc[i].textNum, GOSSIP_SENDER_MAIN, i); + } + + pPlayer->SEND_GOSSIP_MENU(TELEPORT_GOSSIP_MESSAGE, pGo->GetObjectGuid()); + return true; +} + +bool GOHello_go_plague_sigil(Player* pPlayer, GameObject* pGo) +{ + instance_icecrown_citadel* pInstance = (instance_icecrown_citadel*)pGo->GetInstanceData(); + + if(!pInstance) + return false; + + if (pInstance->GetData(TYPE_FESTERGUT) == DONE && + pInstance->GetData(TYPE_ROTFACE) == DONE) + { + pInstance->DoOpenDoor(GO_SCIENTIST_DOOR_ORANGE, true); + pInstance->DoOpenDoor(GO_SCIENTIST_DOOR_GREEN, true); + pInstance->DoOpenDoor(GO_SCIENTIST_DOOR_COLLISION); + } + return true; +} + +bool GOHello_go_bloodwing_sigil(Player* player, GameObject* pGo) +{ + instance_icecrown_citadel* pInstance = (instance_icecrown_citadel*)pGo->GetInstanceData(); + + if (!pInstance) + return false; + + if (pInstance->GetData(TYPE_DEATHBRINGER_SAURFANG) == DONE) + pInstance->DoOpenDoor(GO_BLOODWING_DOOR); + + return true; +} + +bool GOHello_go_frostwing_sigil(Player* pPlayer, GameObject* pGo) +{ + instance_icecrown_citadel* pInstance = (instance_icecrown_citadel*)pGo->GetInstanceData(); + if (!pInstance) + return false; + + if (pInstance->GetData(TYPE_DEATHBRINGER_SAURFANG) == DONE) + pInstance->DoOpenDoor(GO_FROSTWING_DOOR); + + return true; +} + + +void AddSC_icecrown_teleporter() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "go_icecrown_teleporter"; + pNewScript->pGossipHelloGO = &GOGossipHello_go_icecrown_teleporter; + pNewScript->pGossipSelectGO = &GOGossipSelect_go_icecrown_teleporter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_plague_sigil"; + pNewScript->pGOUse = &GOHello_go_plague_sigil; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_bloodwing_sigil"; + pNewScript->pGOUse = &GOHello_go_bloodwing_sigil; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_frostwing_sigil"; + pNewScript->pGOUse = &GOHello_go_frostwing_sigil; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp new file mode 100644 index 0000000000..7095767264 --- /dev/null +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp @@ -0,0 +1,612 @@ +/* Copyright (C) 2006 - 2013 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: instance_icecrown_citadel +SD%Complete: 90% +SDComment: by michalpolko with special thanks to: + mangosR2 team and all who are supporting us with feedback, testing and fixes + TrinityCore for some info about spells IDs + everybody whom I forgot to mention here ;) + +SDCategory: Icecrown Citadel +EndScriptData */ + +#include "precompiled.h" +#include "icecrown_citadel.h" +#include "World.h" + +/* +static LOCATION SpawnLoc[]= +{ + {-446.788971f, 2003.362915f, 191.233948f}, // 0 Horde ship enter + {-428.140503f, 2421.336914f, 191.233078f}, // 1 Alliance ship enter +}; +*/ + +instance_icecrown_citadel::instance_icecrown_citadel(Map* pMap) : ScriptedInstance(pMap) +{ + m_uiMapDifficulty = pMap->GetDifficulty(); + Initialize(); +} + +void instance_icecrown_citadel::Initialize() +{ + for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + m_auiEncounter[i] = NOT_STARTED; + + for (uint8 i = 0; i < ACHIEVE_MAX_COUNT; ++i) + m_bAchievCriteria[i] = false; + + // m_auiEvent = 0; + // m_auiEventTimer = 1000; + // m_uiCouncilInvocation = 0; + // m_uiDirection = 0; + // m_uiStinkystate = NOT_STARTED; + // m_uiPreciousstate = NOT_STARTED; + + switch (m_uiMapDifficulty) + { + case RAID_DIFFICULTY_10MAN_NORMAL: + m_uiGunshipArmoryH_ID = GO_GUNSHIP_ARMORY_H_10; + m_uiGunshipArmoryA_ID = GO_GUNSHIP_ARMORY_A_10; + m_uiValithriaCache = GO_DREAMWALKER_CACHE_10; + m_uiSaurfangCache = GO_SAURFANG_CACHE_10; + break; + case RAID_DIFFICULTY_10MAN_HEROIC: + m_uiGunshipArmoryH_ID = GO_GUNSHIP_ARMORY_H_10H; + m_uiGunshipArmoryA_ID = GO_GUNSHIP_ARMORY_A_10H; + m_uiValithriaCache = GO_DREAMWALKER_CACHE_10_H; + m_uiSaurfangCache = GO_SAURFANG_CACHE_10_H; + break; + case RAID_DIFFICULTY_25MAN_NORMAL: + m_uiGunshipArmoryH_ID = GO_GUNSHIP_ARMORY_H_25; + m_uiGunshipArmoryA_ID = GO_GUNSHIP_ARMORY_A_25; + m_uiValithriaCache = GO_DREAMWALKER_CACHE_25; + m_uiSaurfangCache = GO_SAURFANG_CACHE_25; + break; + case RAID_DIFFICULTY_25MAN_HEROIC: + m_uiGunshipArmoryH_ID = GO_GUNSHIP_ARMORY_H_25H; + m_uiGunshipArmoryA_ID = GO_GUNSHIP_ARMORY_A_25H; + m_uiValithriaCache = GO_DREAMWALKER_CACHE_25_H; + m_uiSaurfangCache = GO_SAURFANG_CACHE_25_H; + break; + default: + break; + } +} + +bool instance_icecrown_citadel::IsEncounterInProgress() const +{ + for (uint8 i = TYPE_MARROWGAR; i < MAX_ENCOUNTERS; ++i) + { + if (GetData(i) == IN_PROGRESS) + return true; + } + + return false; +} + +void instance_icecrown_citadel::OnPlayerEnter(Player* pPlayer) +{ + // Summon Sindragosa in reload case + if ((GetData(TYPE_SINDRAGOSA) == NOT_STARTED || GetData(TYPE_SINDRAGOSA) == FAIL) + && !GetSingleCreatureFromStorage(NPC_SINDRAGOSA)) + { + Creature* pBrother = GetSingleCreatureFromStorage(NPC_RIMEFANG); + if (pBrother && !pBrother->isAlive()) + { + pBrother = GetSingleCreatureFromStorage(NPC_SPINESTALKER); + if (pBrother && !pBrother->isAlive()) + pPlayer->SummonCreature(NPC_SINDRAGOSA, 4505.0f, 2484.243896f, 231.0f, 3.17f, TEMPSUMMON_DEAD_DESPAWN, 0, true); + } + } +} + +void instance_icecrown_citadel::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_HIGHLORD_TIRION_FORDRING_LH: + case NPC_THE_LICH_KING_LH: + case NPC_HIGHLORD_BOLVAR_FORDRAGON_LH: + case NPC_SAURFANG_LH: + case NPC_MURADIN_LH: + 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_QUEEN_LANATHEL: + case NPC_QUEEN_LANATHEL_INTRO: + case NPC_VALITHRIA: + case NPC_VALITHRIA_QUEST: + case NPC_SINDRAGOSA: + case NPC_LICH_KING: + case NPC_TIRION: + case NPC_RIMEFANG: + case NPC_SPINESTALKER: + case NPC_STINKY: + case NPC_PRECIOUS: + case NPC_GREEN_DRAGON_COMBAT_TRIGGER: + case NPC_FROSTMOURNE_TRIGGER: + case NPC_FROSTMOURNE_HOLDER: + case NPC_BLOOD_ORB_CONTROL: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} + +void instance_icecrown_citadel::OnObjectCreate(GameObject* pGo) +{ + switch(pGo->GetEntry()) + { + case GO_ICEWALL_1: + if (GetData(TYPE_MARROWGAR) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ICEWALL_2: + if (GetData(TYPE_MARROWGAR) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DEATHWHISPER_ELEVATOR: + if (!pGo->isSpawned() && GetData(TYPE_LADY_DEATHWHISPER) == DONE) + { + pGo->SetRespawnTime(30); + pGo->Refresh(); + pGo->SetUInt32Value(GAMEOBJECT_LEVEL, 0); + pGo->SetGoState(GO_STATE_READY); + } + break; + case GO_SAURFANG_DOOR: + if (GetData(TYPE_DEATHBRINGER_SAURFANG) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ORANGE_PLAGUE: + if (GetData(TYPE_FESTERGUT) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GREEN_PLAGUE: + if (GetData(TYPE_ROTFACE) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SCIENTIST_DOOR_GREEN: + if (GetData(TYPE_ROTFACE) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + break; + case GO_SCIENTIST_DOOR_ORANGE: + if (GetData(TYPE_FESTERGUT) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + break; + case GO_SCIENTIST_DOOR_COLLISION: + if (GetData(TYPE_FESTERGUT) == DONE && GetData(TYPE_ROTFACE) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SCIENTIST_DOOR: + if (GetData(TYPE_FESTERGUT) == DONE && GetData(TYPE_ROTFACE) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ORANGE_TUBES: + if (GetData(TYPE_FESTERGUT) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GREEN_TUBES: + if (GetData(TYPE_ROTFACE) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_CRIMSON_HALL_DOOR: + if (GetData(TYPE_BLOOD_PRINCE_COUNCIL) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_COUNCIL_DOOR_1: + if (GetData(TYPE_BLOOD_PRINCE_COUNCIL) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_COUNCIL_DOOR_2: + if (GetData(TYPE_BLOOD_PRINCE_COUNCIL) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GREEN_DRAGON_DOOR_1: + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GREEN_DRAGON_DOOR_2: + if (GetData(TYPE_VALITHRIA) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SINDRAGOSA_DOOR_1: + case GO_SINDRAGOSA_DOOR_2: + case GO_SINDRAGOSA_ENTRANCE: + if (GetData(TYPE_VALITHRIA) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DRINK_ME_TABLE: + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; + case GO_ARTHAS_PLATFORM: + pGo->SetUInt32Value(GAMEOBJECT_PARENTROTATION, 5535469); + break; + case GO_ARTHAS_PRECIPICE: + pGo->SetUInt32Value(GAMEOBJECT_PARENTROTATION, 4178312); + break; + case GO_INSTANCE_PORTAL: + case GO_SAURFANG_CACHE_10: + case GO_SAURFANG_CACHE_25: + case GO_SAURFANG_CACHE_10_H: + case GO_SAURFANG_CACHE_25_H: + case GO_GUNSHIP_ARMORY_A_10: + case GO_GUNSHIP_ARMORY_A_25: + case GO_GUNSHIP_ARMORY_A_10H: + case GO_GUNSHIP_ARMORY_A_25H: + case GO_GUNSHIP_ARMORY_H_10: + case GO_GUNSHIP_ARMORY_H_25: + case GO_GUNSHIP_ARMORY_H_10H: + case GO_GUNSHIP_ARMORY_H_25H: + case GO_DREAMWALKER_CACHE_10: + case GO_DREAMWALKER_CACHE_25: + case GO_DREAMWALKER_CACHE_10_H: + case GO_DREAMWALKER_CACHE_25_H: + 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_GAS_RELEASE_VALVE: + case GO_MARROWGAR_DOOR: + case GO_BLOODPRINCE_DOOR: + case GO_ICECROWN_GRATE: + case GO_VALITHRIA_DOOR_1: + case GO_VALITHRIA_DOOR_2: + case GO_VALITHRIA_DOOR_3: + case GO_VALITHRIA_DOOR_4: + case GO_FROSTWING_DOOR: + case GO_BLOODWING_DOOR: + case GO_ORATORY_DOOR: + case GO_SINDRAGOSA_ICE_WALL: + break; + default: + return; + } + + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_icecrown_citadel::SetData(uint32 uiType, uint32 uiData) +{ + + bool bChange = bool(GetData(uiType) != uiData); + + switch(uiType) + { + case TYPE_TELEPORT: + break; + case TYPE_ICC_INTRO: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_MARROWGAR: + DoUseDoorOrButton(GO_MARROWGAR_DOOR); + + if (uiData == DONE) + { + DoUseDoorOrButton(GO_ICEWALL_1); + DoUseDoorOrButton(GO_ICEWALL_2); + // door to Deathwhisper are already open + //DoUseDoorOrButton(GO_ORATORY_DOOR); + } + break; + case TYPE_LADY_DEATHWHISPER: + DoUseDoorOrButton(GO_ORATORY_DOOR); + + if (uiData == DONE) + { + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_DEATHWHISPER_ELEVATOR)) + { + pGo->SetRespawnTime(30); + pGo->Refresh(); + pGo->SetUInt32Value(GAMEOBJECT_LEVEL, 0); + pGo->SetGoState(GO_STATE_READY); + } + } + break; + case TYPE_FLIGHT_WAR: + break; + case TYPE_DEATHBRINGER_SAURFANG: + if (uiData == DONE) + { + DoUseDoorOrButton(GO_SAURFANG_DOOR); + + if (GameObject* pChest = GetSingleGameObjectFromStorage(m_uiSaurfangCache)) + { + if (pChest && !pChest->isSpawned()) + pChest->SetRespawnTime(7 * DAY); + } + } + break; + case TYPE_FESTERGUT: + switch (uiData) + { + case IN_PROGRESS: + DoCloseDoor(GO_ORANGE_PLAGUE); + break; + case DONE: + DoOpenDoor(GO_ORANGE_TUBES); + DoOpenDoor(GO_SCIENTIST_DOOR_ORANGE); + // no break + default: + DoOpenDoor(GO_ORANGE_PLAGUE); + break; + } + break; + case TYPE_ROTFACE: + switch (uiData) + { + case IN_PROGRESS: + DoCloseDoor(GO_GREEN_PLAGUE); + break; + case DONE: + DoOpenDoor(GO_GREEN_TUBES); + DoOpenDoor(GO_SCIENTIST_DOOR_GREEN); + // no break + default: + DoOpenDoor(GO_GREEN_PLAGUE); + break; + } + break; + case TYPE_PROFESSOR_PUTRICIDE: + if (uiData == DONE && GetData(TYPE_SINDRAGOSA) == DONE && GetData(TYPE_QUEEN_LANATHEL) == DONE) + m_auiEncounter[TYPE_KINGS_OF_ICC] = DONE; + + switch (uiData) + { + case IN_PROGRESS: + case SPECIAL: + DoCloseDoor(GO_SCIENTIST_DOOR); + break; + case NOT_STARTED: + case FAIL: + case DONE: + DoOpenDoor(GO_SCIENTIST_DOOR); + break; + default: + break; + } + + break; + case TYPE_BLOOD_PRINCE_COUNCIL: + DoUseDoorOrButton(GO_CRIMSON_HALL_DOOR); + + if (bChange && uiData == IN_PROGRESS) + { + if (Creature* prince = GetSingleCreatureFromStorage(NPC_TALDARAM)) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_ENGAGE, prince->GetObjectGuid()); + if (Creature* prince = GetSingleCreatureFromStorage(NPC_VALANAR)) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_ENGAGE, prince->GetObjectGuid()); + if (Creature* prince = GetSingleCreatureFromStorage(NPC_KELESETH)) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_ENGAGE, prince->GetObjectGuid()); + } + else if (bChange) + { + if (Creature* prince = GetSingleCreatureFromStorage(NPC_TALDARAM)) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_DISENGAGE, prince->GetObjectGuid()); + if (Creature* prince = GetSingleCreatureFromStorage(NPC_VALANAR)) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_DISENGAGE, prince->GetObjectGuid()); + if (Creature* prince = GetSingleCreatureFromStorage(NPC_KELESETH)) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_DISENGAGE, prince->GetObjectGuid()); + } + + if (uiData == DONE) + { + DoUseDoorOrButton(GO_COUNCIL_DOOR_1); + DoUseDoorOrButton(GO_COUNCIL_DOOR_2); + } + break; + case TYPE_QUEEN_LANATHEL: + DoUseDoorOrButton(GO_BLOODPRINCE_DOOR); + + if (uiData == DONE) + { + DoUseDoorOrButton(GO_ICECROWN_GRATE); + + if (GetData(TYPE_PROFESSOR_PUTRICIDE) == DONE && GetData(TYPE_SINDRAGOSA) == DONE) + m_auiEncounter[TYPE_KINGS_OF_ICC] = DONE; + } + break; + case TYPE_VALITHRIA: + DoUseDoorOrButton(GO_GREEN_DRAGON_DOOR_1); + DoUseDoorOrButton(GO_VALITHRIA_DOOR_1); + DoUseDoorOrButton(GO_VALITHRIA_DOOR_2); + + if (instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL || + instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC) + { + DoUseDoorOrButton(GO_VALITHRIA_DOOR_3); + DoUseDoorOrButton(GO_VALITHRIA_DOOR_4); + } + + if (Creature* valithria = GetSingleCreatureFromStorage(NPC_VALITHRIA)) + { + if (bChange && uiData == IN_PROGRESS) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_ENGAGE, valithria->GetObjectGuid()); + else if (bChange) + UpdateSpecialEncounterState(ENCOUNTER_FRAME_DISENGAGE, valithria->GetObjectGuid()); + } + + if (uiData == DONE) + { + DoUseDoorOrButton(GO_GREEN_DRAGON_DOOR_2); + + DoUseDoorOrButton(GO_SINDRAGOSA_DOOR_1); + DoUseDoorOrButton(GO_SINDRAGOSA_DOOR_2); + DoUseDoorOrButton(GO_SINDRAGOSA_ENTRANCE); + + if (GameObject* pChest = GetSingleGameObjectFromStorage(m_uiValithriaCache)) + { + if (pChest && !pChest->isSpawned()) + pChest->SetRespawnTime(7 * DAY); + } + } + + break; + case TYPE_SINDRAGOSA: + DoUseDoorOrButton(GO_SINDRAGOSA_ENTRANCE); + DoUseDoorOrButton(GO_SINDRAGOSA_ICE_WALL); + + if (uiData == DONE && GetData(TYPE_PROFESSOR_PUTRICIDE) == DONE && GetData(TYPE_QUEEN_LANATHEL) == DONE) + m_auiEncounter[TYPE_KINGS_OF_ICC] = DONE; + break; + case TYPE_LICH_KING: + case TYPE_FROSTMOURNE_ROOM: + break; + default: + script_error_log("Instance Icecrown Citadel: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; + } + + m_auiEncounter[uiType] = uiData; + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + saveStream << GetData(i) << " "; + + strSaveData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_icecrown_citadel::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTERS) + return m_auiEncounter[uiType]; + + script_error_log("Instance Icecrown Citadel: ERROR GetData for type %u does not exist/not implemented.", uiType); + return 0; +} + +bool instance_icecrown_citadel::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const +{ + switch(uiCriteriaId) + { + case CRITERIA_BONED_10N: + case CRITERIA_BONED_25N: + case CRITERIA_BONED_10H: + case CRITERIA_BONED_25H: + return m_bAchievCriteria[ACHIEVE_BONED]; + case CRITERIA_FULL_HOUSE_10N: + case CRITERIA_FULL_HOUSE_25N: + case CRITERIA_FULL_HOUSE_10H: + case CRITERIA_FULL_HOUSE_25H: + return m_bAchievCriteria[ACHIEVE_FULL_HOUSE]; + case CRITERIA_IM_ON_A_BOAT_10N: + case CRITERIA_IM_ON_A_BOAT_25N: + case CRITERIA_IM_ON_A_BOAT_10H: + case CRITERIA_IM_ON_A_BOAT_25H: + return m_bAchievCriteria[ACHIEVE_IM_ON_A_BOAT]; + case CRITERIA_IVE_GONE_AND_MADE_A_MESS_10N: + case CRITERIA_IVE_GONE_AND_MADE_A_MESS_25N: + case CRITERIA_IVE_GONE_AND_MADE_A_MESS_10H: + case CRITERIA_IVE_GONE_AND_MADE_A_MESS_25H: + return m_bAchievCriteria[ACHIEVE_IVE_GONE_AND_MADE_A_MESS]; + case CRITERIA_FLU_SHOT_SHORTAGE_10N: + case CRITERIA_FLU_SHOT_SHORTAGE_25N: + case CRITERIA_FLU_SHOT_SHORTAGE_10H: + case CRITERIA_FLU_SHOT_SHORTAGE_25H: + return m_bAchievCriteria[ACHIEVE_FLU_SHOT_SHORTAGE]; + case CRITERIA_DANCES_WITH_OOZES_10N: + case CRITERIA_DANCES_WITH_OOZES_25N: + case CRITERIA_DANCES_WITH_OOZES_10H: + case CRITERIA_DANCES_WITH_OOZES_25H: + return m_bAchievCriteria[ACHIEVE_DANCES_WITH_OOZES]; + case CRITERIA_NAUSEA_10N: + case CRITERIA_NAUSEA_25N: + case CRITERIA_NAUSEA_10H: + case CRITERIA_NAUSEA_25H: + return m_bAchievCriteria[ACHIEVE_NAUSEA]; + case CRITERIA_ORB_WHISPERER_10N: + case CRITERIA_ORB_WHISPERER_25N: + case CRITERIA_ORB_WHISPERER_10H: + case CRITERIA_ORB_WHISPERER_25H: + return m_bAchievCriteria[ACHIEVE_ORB_WHISPERER]; + case CRITERIA_PORTAL_JOCKEY_10N: + case CRITERIA_PORTAL_JOCKEY_25N: + case CRITERIA_PORTAL_JOCKEY_10H: + case CRITERIA_PORTAL_JOCKEY_25H: + return m_bAchievCriteria[ACHIEVE_PORTAL_JOCKEY]; + case CRITERIA_ALL_YOU_CAN_EAT_10N: + case CRITERIA_ALL_YOU_CAN_EAT_25N: + case CRITERIA_ALL_YOU_CAN_EAT_10V: + case CRITERIA_ALL_YOU_CAN_EAT_25V: + return m_bAchievCriteria[ACHIEVE_ALL_YOU_CAN_EAT]; + case CRITERIA_BEEN_WAITING_A_LONG_TIME_10N: + case CRITERIA_BEEN_WAITING_A_LONG_TIME_25N: + case CRITERIA_BEEN_WAITING_A_LONG_TIME_10H: + case CRITERIA_BEEN_WAITING_A_LONG_TIME_25H: + return m_bAchievCriteria[ACHIEVE_BEEN_WAITING_A_LONG_TIME]; + default: + return false; + } +} + +void instance_icecrown_citadel::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < ACHIEVE_MAX_COUNT) + m_bAchievCriteria[uiType] = bIsMet; +} + +void instance_icecrown_citadel::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + + for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + { + loadStream >> m_auiEncounter[i]; + + if (GetData(i) == IN_PROGRESS && i >= 1) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +InstanceData* GetInstanceData_instance_icecrown_citadel(Map* pMap) +{ + return new instance_icecrown_citadel(pMap); +} + + +void AddSC_instance_icecrown_citadel() +{ + AutoScript("instance_icecrown_citadel")->GetInstanceData = &GetInstanceData_instance_icecrown_citadel; +} diff --git a/scripts/northrend/naxxramas/boss_anubrekhan.cpp b/scripts/northrend/naxxramas/boss_anubrekhan.cpp index 7805a5aa7a..9eb3a2a0f2 100644 --- a/scripts/northrend/naxxramas/boss_anubrekhan.cpp +++ b/scripts/northrend/naxxramas/boss_anubrekhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Anubrekhan -SD%Complete: 70 -SDComment: +SD%Complete: 100 +SDComment: Intro text usage is not very clear. Requires additional research. SDCategory: Naxxramas EndScriptData */ @@ -36,35 +36,52 @@ 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_CORPSE_SCARAB = 16698, NPC_CRYPT_GUARD = 16573 }; +static const DialogueEntry aIntroDialogue[] = +{ + {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 MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI { - boss_anubrekhanAI(Creature* pCreature) : ScriptedAI(pCreature) + 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(); + SummonCryptGuards(); } instance_naxxramas* m_pInstance; + DialogueHelper m_introDialogue; bool m_bIsRegularMode; uint32 m_uiImpaleTimer; @@ -72,18 +89,20 @@ struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI uint32 m_uiSummonTimer; bool m_bHasTaunted; - void Reset() + GuidList m_lSummonedGuidList; + + 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 = urand(70000, 120000); // Random time between 70 seconds and 2 minutes for initial cast + 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 +110,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; @@ -102,52 +121,109 @@ struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI if (m_pInstance) m_pInstance->SetData(TYPE_ANUB_REKHAN, IN_PROGRESS); + + for (GuidList::const_iterator itr = m_lSummonedGuidList.begin(); itr != m_lSummonedGuidList.end(); ++itr) + { + if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) + pSummoned->SetInCombatWithZone(); + } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ANUB_REKHAN, DONE); + + m_lSummonedGuidList.clear(); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ANUB_REKHAN, FAIL); + + DespawnSummonedCreatures(); + SummonCryptGuards(); } - 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 { + switch(pSummoned->GetEntry()) + { + case NPC_CRYPT_GUARD: + if (m_creature->isInCombat()) + DoScriptText(EMOTE_CRYPT_GUARD, pSummoned); + case NPC_CORPSE_SCARAB: + m_lSummonedGuidList.push_back(pSummoned->GetObjectGuid()); + if (m_creature->isInCombat()) + pSummoned->SetInCombatWithZone(); + break; + } + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + + void DespawnSummonedCreatures() + { + for (GuidList::const_iterator itr = m_lSummonedGuidList.begin(); itr != m_lSummonedGuidList.end(); ++itr) + { + if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) + pSummoned->ForcedDespawn(); + } + m_lSummonedGuidList.clear(); + } + + void SummonCryptGuards() // Only 25Players + { + if (m_bIsRegularMode) + return; + if (Creature* pSummoned = m_creature->SummonCreature(NPC_CRYPT_GUARD, 3301.05f, -3503.52f, 287.078f, 2.33316f, TEMPSUMMON_DEAD_DESPAWN, 0)) + m_lSummonedGuidList.push_back(pSummoned->GetObjectGuid()); + if (Creature* pSummoned = m_creature->SummonCreature(NPC_CRYPT_GUARD, 3301.42f, -3448.52f, 287.078f, 3.92752f, TEMPSUMMON_DEAD_DESPAWN, 0)) + m_lSummonedGuidList.push_back(pSummoned->GetObjectGuid()); + } + + 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; // Impale if (m_uiImpaleTimer < uiDiff) { - //Cast Impale on a random target - //Do NOT cast it when we are afflicted by locust swarm - if (!m_creature->HasAura(SPELL_LOCUSTSWARM) || !m_creature->HasAura(SPELL_LOCUSTSWARM_H)) + // Cast Impale on a random target + // Do NOT cast it when we are afflicted by locust swarm + if (!m_creature->HasAura(SPELL_LOCUSTSWARM) && !m_creature->HasAura(SPELL_LOCUSTSWARM_H)) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_IMPALE : SPELL_IMPALE_H); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, m_bIsRegularMode ? SPELL_IMPALE : SPELL_IMPALE_H, SELECT_FLAG_PLAYER)) + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_IMPALE : SPELL_IMPALE_H); } m_uiImpaleTimer = 15000; @@ -158,20 +234,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 = m_bIsRegularMode ? 16000 : 20000; + m_uiLocustSwarmTimer = urand(70000, 120000); + } } 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(); } @@ -184,9 +270,10 @@ CreatureAI* GetAI_boss_anubrekhan(Creature* pCreature) void AddSC_boss_anubrekhan() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_anubrekhan"; - NewScript->GetAI = &GetAI_boss_anubrekhan; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_anubrekhan"; + pNewScript->GetAI = &GetAI_boss_anubrekhan; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_faerlina.cpp b/scripts/northrend/naxxramas/boss_faerlina.cpp index f1e63af0c0..62cad6376b 100644 --- a/scripts/northrend/naxxramas/boss_faerlina.cpp +++ b/scripts/northrend/naxxramas/boss_faerlina.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,7 +16,7 @@ /* ScriptData SDName: Boss_Faerlina -SD%Complete: 50 +SD%Complete: 100 SDComment: SDCategory: Naxxramas EndScriptData */ @@ -26,26 +26,29 @@ EndScriptData */ enum { - SAY_GREET = -1533009, - SAY_AGGRO1 = -1533010, - SAY_AGGRO2 = -1533011, - SAY_AGGRO3 = -1533012, - SAY_AGGRO4 = -1533013, - SAY_SLAY1 = -1533014, - SAY_SLAY2 = -1533015, - SAY_DEATH = -1533016, - - EMOTE_BOSS_GENERIC_FRENZY = -1000005, - - //SOUND_RANDOM_AGGRO = 8955, //soundId containing the 4 aggro sounds, we not using this - - SPELL_POSIONBOLT_VOLLEY = 28796, - H_SPELL_POSIONBOLT_VOLLEY = 54098, - SPELL_ENRAGE = 28798, - H_SPELL_ENRAGE = 54100, - - SPELL_RAINOFFIRE = 28794 //Not sure if targeted AoEs work if casted directly upon a pPlayer + SAY_GREET = -1533009, + SAY_AGGRO_1 = -1533010, + SAY_AGGRO_2 = -1533011, + SAY_AGGRO_3 = -1533012, + SAY_AGGRO_4 = -1533013, + SAY_SLAY_1 = -1533014, + SAY_SLAY_2 = -1533015, + SAY_DEATH = -1533016, + + EMOTE_BOSS_GENERIC_FRENZY = -1000005, + + // SOUND_RANDOM_AGGRO = 8955, // soundId containing the 4 aggro sounds, we not using this + + SPELL_POSIONBOLT_VOLLEY = 28796, + SPELL_POSIONBOLT_VOLLEY_H = 54098, + SPELL_ENRAGE = 28798, + SPELL_ENRAGE_H = 54100, + SPELL_RAIN_OF_FIRE = 28794, + SPELL_RAIN_OF_FIRE_H = 54099, + SPELL_WIDOWS_EMBRACE = 28732, + SPELL_WIDOWS_EMBRACE_H = 54097, }; + struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI { boss_faerlinaAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -64,30 +67,30 @@ 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_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_AGGRO2, m_creature); break; - case 2: DoScriptText(SAY_AGGRO3, m_creature); break; - case 3: DoScriptText(SAY_AGGRO4, m_creature); break; + case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; + case 3: DoScriptText(SAY_AGGRO_4, m_creature); break; } if (m_pInstance) 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; @@ -96,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_SLAY1:SAY_SLAY2, m_creature); + 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); @@ -109,13 +112,42 @@ 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); } - void UpdateAI(const uint32 uiDiff) + // 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) override + { + // Check if we hit with Widow's Embrave + if (pSpellEntry->Id == SPELL_WIDOWS_EMBRACE || pSpellEntry->Id == SPELL_WIDOWS_EMBRACE_H) + { + bool bIsFrenzyRemove = false; + + // If we remove the Frenzy, the Enrage Timer is reseted to 60s + if (m_creature->HasAura(m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H)) + { + m_uiEnrageTimer = 60000; + m_creature->RemoveAurasDueToSpell(m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H); + + bIsFrenzyRemove = true; + } + + // Achievement 'Momma said Knock you out': If we removed OR delayed the frenzy, the criteria is failed + if ((bIsFrenzyRemove || m_uiEnrageTimer < 30000) && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_KNOCK_YOU_OUT, false); + + // In any case we prevent Frenzy and Poison Bolt Volley for Widow's Embrace Duration (30s) + // We do this be setting the timers to at least bigger than 30s + m_uiEnrageTimer = std::max(m_uiEnrageTimer, (uint32)30000); + m_uiPoisonBoltVolleyTimer = std::max(m_uiPoisonBoltVolleyTimer, urand(33000, 38000)); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -123,8 +155,8 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI // Poison Bolt Volley if (m_uiPoisonBoltVolleyTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_POSIONBOLT_VOLLEY); - m_uiPoisonBoltVolleyTimer = 11000; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_POSIONBOLT_VOLLEY : SPELL_POSIONBOLT_VOLLEY_H) == CAST_OK) + m_uiPoisonBoltVolleyTimer = 11000; } else m_uiPoisonBoltVolleyTimer -= uiDiff; @@ -133,23 +165,24 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI if (m_uiRainOfFireTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_RAINOFFIRE); - - m_uiRainOfFireTimer = 16000; + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_RAIN_OF_FIRE : SPELL_RAIN_OF_FIRE_H) == CAST_OK) + m_uiRainOfFireTimer = 16000; + } } else m_uiRainOfFireTimer -= uiDiff; - //Enrage_Timer + // Enrage Timer if (m_uiEnrageTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H) == CAST_OK) { DoScriptText(EMOTE_BOSS_GENERIC_FRENZY, m_creature); - m_uiEnrageTimer = 61000; + m_uiEnrageTimer = 60000; } } - else + else m_uiEnrageTimer -= uiDiff; DoMeleeAttackIfReady(); @@ -163,9 +196,10 @@ CreatureAI* GetAI_boss_faerlina(Creature* pCreature) void AddSC_boss_faerlina() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_faerlina"; - NewScript->GetAI = &GetAI_boss_faerlina; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_faerlina"; + pNewScript->GetAI = &GetAI_boss_faerlina; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_four_horsemen.cpp b/scripts/northrend/naxxramas/boss_four_horsemen.cpp index 49a7a57326..6a929d3224 100644 --- a/scripts/northrend/naxxramas/boss_four_horsemen.cpp +++ b/scripts/northrend/naxxramas/boss_four_horsemen.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, - H_SPELL_VOIDZONE = 57463, - SPELL_SHADOW_BOLT = 57374, - H_SPELL_SHADOW_BOLT = 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, - H_SPELL_UNHOLY_SHADOW = 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, - H_SPELL_HOLY_WRATH = 57466, + SPELL_HOLY_WRATH_H = 57466, SPELL_HOLY_BOLT = 57376, - H_SPELL_HOLY_BOLT = 57465, + 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 { - 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 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 { 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(); } @@ -180,37 +228,107 @@ CreatureAI* GetAI_boss_lady_blaumeux(Creature* pCreature) struct MANGOS_DLL_DECL 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(); + } - void Reset() + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + 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 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; + + // 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(); } }; @@ -222,72 +340,101 @@ CreatureAI* GetAI_boss_rivendare_naxx(Creature* pCreature) struct MANGOS_DLL_DECL 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 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; - // 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(); } @@ -300,73 +447,119 @@ CreatureAI* GetAI_boss_thane_korthazz(Creature* pCreature) struct MANGOS_DLL_DECL 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(); + } - uint32 Mark_Timer; - uint32 HolyWrath_Timer; - bool ShieldWall1; - bool ShieldWall2; + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - void Reset() + bool m_bIsCornerMovement; + uint32 m_uiMarkTimer; + uint32 m_uiHolyWrathTimer; + uint32 m_uiHolyBoltTimer; + + 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 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 { - //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(); } @@ -379,25 +572,25 @@ CreatureAI* GetAI_boss_sir_zeliek(Creature* pCreature) void AddSC_boss_four_horsemen() { - Script* NewScript; - - NewScript = new Script; - NewScript->Name = "boss_lady_blaumeux"; - NewScript->GetAI = &GetAI_boss_lady_blaumeux; - NewScript->RegisterSelf(); - - NewScript = new Script; - NewScript->Name = "boss_rivendare_naxx"; - NewScript->GetAI = &GetAI_boss_rivendare_naxx; - NewScript->RegisterSelf(); - - NewScript = new Script; - NewScript->Name = "boss_thane_korthazz"; - NewScript->GetAI = &GetAI_boss_thane_korthazz; - NewScript->RegisterSelf(); - - NewScript = new Script; - NewScript->Name = "boss_sir_zeliek"; - NewScript->GetAI = &GetAI_boss_sir_zeliek; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lady_blaumeux"; + pNewScript->GetAI = &GetAI_boss_lady_blaumeux; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_rivendare_naxx"; + pNewScript->GetAI = &GetAI_boss_rivendare_naxx; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_thane_korthazz"; + pNewScript->GetAI = &GetAI_boss_thane_korthazz; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_sir_zeliek"; + pNewScript->GetAI = &GetAI_boss_sir_zeliek; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_gluth.cpp b/scripts/northrend/naxxramas/boss_gluth.cpp index e0475b5ed3..d2b2de7528 100644 --- a/scripts/northrend/naxxramas/boss_gluth.cpp +++ b/scripts/northrend/naxxramas/boss_gluth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,53 +27,31 @@ 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 { @@ -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; @@ -197,9 +236,10 @@ CreatureAI* GetAI_boss_gluth(Creature* pCreature) void AddSC_boss_gluth() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_gluth"; - NewScript->GetAI = &GetAI_boss_gluth; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_gluth"; + pNewScript->GetAI = &GetAI_boss_gluth; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_gothik.cpp b/scripts/northrend/naxxramas/boss_gothik.cpp index 155043ded7..a2bda6c501 100644 --- a/scripts/northrend/naxxramas/boss_gothik.cpp +++ b/scripts/northrend/naxxramas/boss_gothik.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Gothik -SD%Complete: 60 -SDComment: Only base implemented. Todo: control adds at summon. Handle case of raid not splitted in two sides +SD%Complete: 95 +SDComment: Prevent Gothik from turning and "in combat state" while on balcony SDCategory: Naxxramas EndScriptData */ @@ -40,13 +40,13 @@ enum PHASE_SPEECH = 0, PHASE_BALCONY = 1, - PHASE_GROUND = 2, - PHASE_END = 3, + PHASE_STOP_SUMMONING = 2, + PHASE_TELEPORTING = 3, + PHASE_STOP_TELEPORTING = 4, - MAX_WAVES = 19, - - SPELL_TELEPORT_LEFT = 28025, // guesswork - SPELL_TELEPORT_RIGHT = 28026, // could be defined as dead or live side, left or right facing north + // Right is right side from gothik (eastern) + SPELL_TELEPORT_RIGHT = 28025, + SPELL_TELEPORT_LEFT = 28026, SPELL_HARVESTSOUL = 28679, SPELL_SHADOWBOLT = 29317, @@ -81,43 +81,81 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI instance_naxxramas* m_pInstance; bool m_bIsRegularMode; - uint8 m_uiPhase; - - uint8 m_uiSpeechCount; - uint32 m_uiSpeechTimer; + GuidList m_lSummonedAddGuids; + GuidList m_lTraineeSummonPosGuids; + GuidList m_lDeathKnightSummonPosGuids; + GuidList m_lRiderSummonPosGuids; - uint8 m_uiSummonCount; - uint32 m_uiSummonTimer; + uint8 m_uiPhase; + uint8 m_uiSpeech; + uint32 m_uiTraineeTimer; + uint32 m_uiDeathKnightTimer; + uint32 m_uiRiderTimer; uint32 m_uiTeleportTimer; uint32 m_uiShadowboltTimer; + uint32 m_uiHarvestSoulTimer; + uint32 m_uiPhaseTimer; + uint32 m_uiControlZoneTimer; + uint32 m_uiSpeechTimer; - void Reset() + void Reset() override { - m_uiPhase = PHASE_SPEECH; + // Remove immunity + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false); - m_uiSpeechCount = 0; - m_uiSpeechTimer = 5000; - - m_uiSummonCount = 0; - m_uiSummonTimer = 5000; + 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_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; + + // Despawn Adds + for (GuidList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); itr++) + { + if (Creature* pCreature = m_creature->GetMap()->GetCreature(*itr)) + pCreature->ForcedDespawn(); + } - m_uiTeleportTimer = 15000; - m_uiShadowboltTimer = 2500; + m_lSummonedAddGuids.clear(); + m_lTraineeSummonPosGuids.clear(); + m_lDeathKnightSummonPosGuids.clear(); + m_lRiderSummonPosGuids.clear(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - m_creature->SetInCombatWithZone(); - - DoScriptText(SAY_SPEECH_1, m_creature); - if (!m_pInstance) return; m_pInstance->SetData(TYPE_GOTHIK, IN_PROGRESS); + // Make immune + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, true); + m_pInstance->SetGothTriggers(); + PrepareSummonPlaces(); + } + + bool IsCentralDoorClosed() + { + return m_pInstance && m_pInstance->GetData(TYPE_GOTHIK) != SPECIAL; + } + + void ProcessCentralDoor() + { + if (IsCentralDoorClosed()) + { + m_pInstance->SetData(TYPE_GOTHIK, SPECIAL); + DoScriptText(EMOTE_GATE, m_creature); + } } bool HasPlayersInLeftSide() @@ -127,11 +165,11 @@ 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()) { - if (!m_pInstance->IsInRightSideGothArea(pPlayer)) + if (!m_pInstance->IsInRightSideGothArea(pPlayer) && pPlayer->isAlive()) return true; } } @@ -139,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); @@ -153,188 +191,255 @@ 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); } - void SummonAdds(bool bRightSide, uint32 uiSummonEntry) + void PrepareSummonPlaces() { std::list lSummonList; - m_pInstance->GetGothSummonPointCreatures(lSummonList, bRightSide); + m_pInstance->GetGothSummonPointCreatures(lSummonList, true); if (lSummonList.empty()) return; - uint8 uiCount = 2; + // Trainees and Rider + uint8 index = 0; + uint8 uiTraineeCount = m_bIsRegularMode ? 2 : 3; + lSummonList.sort(ObjectDistanceOrder(m_creature)); + for (std::list::iterator itr = lSummonList.begin(); itr != lSummonList.end(); ++itr) + { + if (*itr) + { + if (uiTraineeCount == 0) + break; + if (index == 1) + m_lRiderSummonPosGuids.push_back((*itr)->GetObjectGuid()); + else + { + m_lTraineeSummonPosGuids.push_back((*itr)->GetObjectGuid()); + --uiTraineeCount; + } + index++; + } + } - switch(uiSummonEntry) + // DeathKnights + uint8 uiDeathKnightCount = m_bIsRegularMode ? 1 : 2; + lSummonList.sort(ObjectDistanceOrderReversed(m_creature)); + for (std::list::iterator itr = lSummonList.begin(); itr != lSummonList.end(); ++itr) { - case NPC_UNREL_TRAINEE: - lSummonList.sort(ObjectDistanceOrder(m_creature)); - break; - case NPC_UNREL_DEATH_KNIGHT: - case NPC_UNREL_RIDER: - uiCount = 1; - lSummonList.sort(ObjectDistanceOrderReversed(m_creature)); - break; + if (*itr) + { + if (uiDeathKnightCount == 0) + break; + m_lDeathKnightSummonPosGuids.push_back((*itr)->GetObjectGuid()); + --uiDeathKnightCount; + } } + } - for(std::list::iterator itr = lSummonList.begin(); itr != lSummonList.end(); ++itr) + void SummonAdds(bool /*bRightSide*/, uint32 uiSummonEntry) + { + GuidList* plSummonPosGuids; + switch (uiSummonEntry) { - if (uiCount == 0) - break; + case NPC_UNREL_TRAINEE: plSummonPosGuids = &m_lTraineeSummonPosGuids; break; + case NPC_UNREL_DEATH_KNIGHT: plSummonPosGuids = &m_lDeathKnightSummonPosGuids; break; + case NPC_UNREL_RIDER: plSummonPosGuids = &m_lRiderSummonPosGuids; break; + default: + return; + } + if (plSummonPosGuids->empty()) + return; - m_creature->SummonCreature(uiSummonEntry, (*itr)->GetPositionX(), (*itr)->GetPositionY(), (*itr)->GetPositionZ(), (*itr)->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - --uiCount; + 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 SummonedCreatureJustDied(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override + { + m_lSummonedAddGuids.push_back(pSummoned->GetObjectGuid()); + if (!IsCentralDoorClosed()) + pSummoned->SetInCombatWithZone(); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override { + m_lSummonedAddGuids.remove(pSummoned->GetObjectGuid()); + if (!m_pInstance) return; if (Creature* pAnchor = m_pInstance->GetClosestAnchorForGoth(pSummoned, true)) { - switch(pSummoned->GetEntry()) + 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") - case NPC_UNREL_TRAINEE: m_creature->CastSpell(pAnchor, SPELL_A_TO_ANCHOR_1, true, NULL, NULL, pSummoned->GetGUID()); break; - case NPC_UNREL_DEATH_KNIGHT: m_creature->CastSpell(pAnchor, SPELL_B_TO_ANCHOR_1, true, NULL, NULL, pSummoned->GetGUID()); break; - case NPC_UNREL_RIDER: m_creature->CastSpell(pAnchor, SPELL_C_TO_ANCHOR_1, true, NULL, NULL, pSummoned->GetGUID()); break; + // 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; } } } - 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_SPEECH: - { if (m_uiSpeechTimer < uiDiff) { - m_uiSpeechTimer = 5000; - ++m_uiSpeechCount; - - switch(m_uiSpeechCount) + switch (m_uiSpeech) { - case 1: DoScriptText(SAY_SPEECH_2, m_creature); break; - case 2: DoScriptText(SAY_SPEECH_3, m_creature); break; - case 3: DoScriptText(SAY_SPEECH_4, m_creature); break; - case 4: m_uiPhase = PHASE_BALCONY; 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++; } else m_uiSpeechTimer -= uiDiff; + // No break here + + case PHASE_BALCONY: // Do summoning + if (m_uiTraineeTimer < uiDiff) + { + SummonAdds(true, NPC_UNREL_TRAINEE); + m_uiTraineeTimer = 20 * IN_MILLISECONDS; + } + else + m_uiTraineeTimer -= uiDiff; + if (m_uiDeathKnightTimer < uiDiff) + { + SummonAdds(true, NPC_UNREL_DEATH_KNIGHT); + m_uiDeathKnightTimer = 25 * IN_MILLISECONDS; + } + else + m_uiDeathKnightTimer -= uiDiff; + if (m_uiRiderTimer < uiDiff) + { + SummonAdds(true, NPC_UNREL_RIDER); + m_uiRiderTimer = 30 * IN_MILLISECONDS; + } + else + m_uiRiderTimer -= uiDiff; + + if (m_uiPhaseTimer < uiDiff) + { + m_uiPhase = PHASE_STOP_SUMMONING; + m_uiPhaseTimer = 27 * IN_MILLISECONDS; + } + else + m_uiPhaseTimer -= uiDiff; + break; - } - case PHASE_BALCONY: - { - if (m_uiSummonTimer < uiDiff) + + case PHASE_STOP_SUMMONING: + if (m_uiPhaseTimer < uiDiff) { - if (m_uiSummonCount >= MAX_WAVES) + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT_RIGHT, CAST_TRIGGERED) == CAST_OK) { + m_uiPhase = m_pInstance ? PHASE_TELEPORTING : PHASE_STOP_TELEPORTING; + DoScriptText(SAY_TELEPORT, m_creature); DoScriptText(EMOTE_TO_FRAY, m_creature); - DoCastSpellIfCan(m_creature, SPELL_TELEPORT_RIGHT); - m_uiPhase = PHASE_GROUND; - return; - } - // npc, npc, npc, timer - static uint32 const auiSummonData[MAX_WAVES][4] = - { - {NPC_UNREL_TRAINEE, 0, 0, 20000}, - {NPC_UNREL_TRAINEE, 0, 0, 20000}, - {NPC_UNREL_TRAINEE, 0, 0, 10000}, - {NPC_UNREL_DEATH_KNIGHT, 0, 0, 10000}, - {NPC_UNREL_TRAINEE, 0, 0, 15000}, - {NPC_UNREL_DEATH_KNIGHT, 0, 0, 10000}, - {NPC_UNREL_TRAINEE, 0, 0, 15000}, - {NPC_UNREL_DEATH_KNIGHT, NPC_UNREL_TRAINEE, 0, 10000}, - {NPC_UNREL_RIDER, 0, 0, 10000}, - {NPC_UNREL_TRAINEE, 0, 0, 5000}, - {NPC_UNREL_DEATH_KNIGHT, 0, 0, 15000}, - {NPC_UNREL_TRAINEE, NPC_UNREL_RIDER, 0, 10000}, - {NPC_UNREL_DEATH_KNIGHT, NPC_UNREL_DEATH_KNIGHT, 0, 10000}, - {NPC_UNREL_TRAINEE, 0, 0, 10000}, - {NPC_UNREL_RIDER, 0, 0, 5000}, - {NPC_UNREL_DEATH_KNIGHT, 0, 0, 5000}, - {NPC_UNREL_TRAINEE, 0, 0, 20000}, - {NPC_UNREL_RIDER, NPC_UNREL_DEATH_KNIGHT, NPC_UNREL_TRAINEE, 15000}, - {NPC_UNREL_TRAINEE, 0, 0, 30000}, - }; - - SummonAdds(true, auiSummonData[m_uiSummonCount][0]); - - if (auiSummonData[m_uiSummonCount][1]) - SummonAdds(true, auiSummonData[m_uiSummonCount][1]); - - if (auiSummonData[m_uiSummonCount][2]) - SummonAdds(true, auiSummonData[m_uiSummonCount][2]); - - m_uiSummonTimer = auiSummonData[m_uiSummonCount][3]; - - ++m_uiSummonCount; + // Remove Immunity + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false); + + DoResetThreat(); + m_creature->SetInCombatWithZone(); + } } else - m_uiSummonTimer -= uiDiff; + m_uiPhaseTimer -= uiDiff; break; - } - case PHASE_GROUND: - case PHASE_END: - { - if (m_uiPhase == PHASE_GROUND) + + case PHASE_TELEPORTING: // Phase is only reached if m_pInstance is valid + if (m_uiTeleportTimer < uiDiff) { - if (m_creature->GetHealthPercent() < 30.0f) + uint32 uiTeleportSpell = m_pInstance->IsInRightSideGothArea(m_creature) ? SPELL_TELEPORT_LEFT : SPELL_TELEPORT_RIGHT; + if (DoCastSpellIfCan(m_creature, uiTeleportSpell) == CAST_OK) { - if (m_pInstance->IsInRightSideGothArea(m_creature)) - { - DoScriptText(EMOTE_GATE, m_creature); - m_pInstance->SetData(TYPE_GOTHIK, SPECIAL); - m_uiPhase = PHASE_END; - m_uiShadowboltTimer = 2000; - return; - } + m_uiTeleportTimer = 20 * IN_MILLISECONDS; + m_uiShadowboltTimer = 2 * IN_MILLISECONDS; } + } + else + m_uiTeleportTimer -= uiDiff; - if (m_uiTeleportTimer < uiDiff) - { - uint32 uiTeleportSpell = m_pInstance->IsInRightSideGothArea(m_creature) ? SPELL_TELEPORT_LEFT : SPELL_TELEPORT_RIGHT; - - if (DoCastSpellIfCan(m_creature, uiTeleportSpell) == CAST_OK) - { - DoResetThreat(); - m_uiTeleportTimer = 15000; - m_uiShadowboltTimer = 2000; - return; - } - } - else - m_uiTeleportTimer -= uiDiff; + if (m_creature->GetHealthPercent() <= 30.0f) + { + m_uiPhase = PHASE_STOP_TELEPORTING; + ProcessCentralDoor(); + // as the doors now open, recheck whether mobs are standing around + m_uiControlZoneTimer = 1; } + // no break here - if (m_uiShadowboltTimer < uiDiff) + case PHASE_STOP_TELEPORTING: + if (m_uiHarvestSoulTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOWBOLT: SPELL_SHADOWBOLT_H) == CAST_OK) - m_uiShadowboltTimer = 1500; + if (DoCastSpellIfCan(m_creature, SPELL_HARVESTSOUL) == CAST_OK) + m_uiHarvestSoulTimer = 15 * IN_MILLISECONDS; } else - m_uiShadowboltTimer -= uiDiff; + m_uiHarvestSoulTimer -= uiDiff; + + if (m_uiShadowboltTimer) + { + if (m_uiShadowboltTimer <= uiDiff) + m_uiShadowboltTimer = 0; + else + m_uiShadowboltTimer -= uiDiff; + } + // Shadowbold cooldown finished, cast when ready + else if (!m_creature->IsNonMeleeSpellCasted(true)) + { + // Select valid target + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, SPELL_SHADOWBOLT, SELECT_FLAG_IN_LOS)) + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOWBOLT : SPELL_SHADOWBOLT_H); + } - DoMeleeAttackIfReady(); // possibly no melee at all break; + } + + // Control Check, if Death zone empty + if (m_uiControlZoneTimer) + { + if (m_uiControlZoneTimer <= uiDiff) + { + m_uiControlZoneTimer = 0; + + if (m_pInstance && !HasPlayersInLeftSide()) + { + ProcessCentralDoor(); + for (GuidList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); itr++) + { + if (Creature* pCreature = m_pInstance->instance->GetCreature(*itr)) + { + if (!pCreature->isInCombat()) + pCreature->SetInCombatWithZone(); + } + } + } } + else + m_uiControlZoneTimer -= uiDiff; } } }; @@ -344,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; @@ -354,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: @@ -384,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)) @@ -405,19 +510,19 @@ bool EffectDummyCreature_spell_anchor(Unit* pCaster, uint32 uiSpellId, SpellEffe case SPELL_B_TO_SKULL: case SPELL_C_TO_SKULL: { - if (Creature* pGoth = pInstance->instance->GetCreature(pInstance->GetData64(NPC_GOTHIK))) + if (Creature* pGoth = pInstance->GetSingleCreatureFromStorage(NPC_GOTHIK)) { uint32 uiNpcEntry = NPC_SPECT_TRAINEE; if (uiSpellId == SPELL_B_TO_SKULL) - uiNpcEntry = NPC_SPECT_DEATH_KNIGTH; + uiNpcEntry = NPC_SPECT_DEATH_KNIGHT; else if (uiSpellId == SPELL_C_TO_SKULL) uiNpcEntry = NPC_SPECT_RIDER; - pGoth->SummonCreature(uiNpcEntry, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), pCreatureTarget->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + pGoth->SummonCreature(uiNpcEntry, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), pCreatureTarget->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); if (uiNpcEntry == NPC_SPECT_RIDER) - pGoth->SummonCreature(NPC_SPECT_HORSE, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), pCreatureTarget->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + pGoth->SummonCreature(NPC_SPECT_HORSE, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), pCreatureTarget->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); } return true; } @@ -428,15 +533,15 @@ bool EffectDummyCreature_spell_anchor(Unit* pCaster, uint32 uiSpellId, SpellEffe void AddSC_boss_gothik() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_gothik"; - newscript->GetAI = &GetAI_boss_gothik; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_gothik"; + pNewScript->GetAI = &GetAI_boss_gothik; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "spell_anchor"; - newscript->pEffectDummyCreature = &EffectDummyCreature_spell_anchor; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "spell_anchor"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_anchor; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_grobbulus.cpp b/scripts/northrend/naxxramas/boss_grobbulus.cpp index ba9dad6a02..c057bd7222 100644 --- a/scripts/northrend/naxxramas/boss_grobbulus.cpp +++ b/scripts/northrend/naxxramas/boss_grobbulus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Grobbulus -SD%Complete: 0 -SDComment: Place holder +SD%Complete: 80 +SDComment: Timer need more care; Spells of Adds (Posion Cloud) need Mangos Fixes, and further handling SDCategory: Naxxramas EndScriptData */ @@ -33,4 +33,189 @@ Enrages 26527*/ enum { EMOTE_SPRAY_SLIME = -1533021, + EMOTE_INJECTION = -1533158, + + SPELL_SLIME_STREAM = 28137, + SPELL_MUTATING_INJECTION = 28169, + SPELL_POISON_CLOUD = 28240, + SPELL_SLIME_SPRAY = 28157, + SPELL_SLIME_SPRAY_H = 54364, + SPELL_BERSERK = 26662, + + NPC_FALLOUT_SLIME = 16290 +}; + +struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI +{ + boss_grobbulusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_naxxramas*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + Reset(); + } + + instance_naxxramas* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiInjectionTimer; + uint32 m_uiPoisonCloudTimer; + uint32 m_uiSlimeSprayTimer; + uint32 m_uiBerserkTimeSecs; + uint32 m_uiBerserkTimer; + uint32 m_uiSlimeStreamTimer; + + 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 + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GROBBULUS, IN_PROGRESS); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GROBBULUS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GROBBULUS, FAIL); + } + + // This custom selecting function, because we only want to select players without mutagen aura + bool DoCastMutagenInjection() + { + if (m_creature->IsNonMeleeSpellCasted(true)) + return false; + + 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->HasAura(SPELL_MUTATING_INJECTION)) + suitableTargets.push_back(pTarget); + } + } + + if (suitableTargets.empty()) + return false; + + Unit* pTarget = suitableTargets[urand(0, suitableTargets.size() - 1)]; + if (DoCastSpellIfCan(pTarget, SPELL_MUTATING_INJECTION) == CAST_OK) + { + DoScriptText(EMOTE_INJECTION, m_creature, pTarget); + return true; + } + else + return false; + } + + 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_OOC_DESPAWN, 10 * IN_MILLISECONDS); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Slime Stream + if (!m_uiSlimeStreamTimer) + { + if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + { + if (DoCastSpellIfCan(m_creature, SPELL_SLIME_STREAM) == CAST_OK) + // Give some time, to re-reach grobbulus + m_uiSlimeStreamTimer = 3 * IN_MILLISECONDS; + } + } + else + { + if (m_uiSlimeStreamTimer < uiDiff) + m_uiSlimeStreamTimer = 0; + else + m_uiSlimeStreamTimer -= uiDiff; + } + + // Berserk + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; + } + + // SlimeSpray + if (m_uiSlimeSprayTimer < uiDiff) + { + 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); + DoScriptText(EMOTE_SPRAY_SLIME, m_creature); + } + } + else + m_uiSlimeSprayTimer -= uiDiff; + + // Mutagen Injection + if (m_uiInjectionTimer < uiDiff) + { + if (DoCastMutagenInjection()) + { + // 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; + else + m_uiInjectionTimer = urand(10 * IN_MILLISECONDS, 13 * IN_MILLISECONDS) - 8 * (m_uiBerserkTimeSecs * IN_MILLISECONDS - m_uiBerserkTimer) / m_uiBerserkTimeSecs; + } + } + else + m_uiInjectionTimer -= uiDiff; + + // Poison Cloud + if (m_uiPoisonCloudTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POISON_CLOUD) == CAST_OK) + m_uiPoisonCloudTimer = 15 * IN_MILLISECONDS; + } + else + m_uiPoisonCloudTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } }; + +CreatureAI* GetAI_boss_grobbulus(Creature* pCreature) +{ + return new boss_grobbulusAI(pCreature); +} + +void AddSC_boss_grobbulus() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_grobbulus"; + pNewScript->GetAI = &GetAI_boss_grobbulus; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/naxxramas/boss_heigan.cpp b/scripts/northrend/naxxramas/boss_heigan.cpp index f160fb883d..a843ee286d 100644 --- a/scripts/northrend/naxxramas/boss_heigan.cpp +++ b/scripts/northrend/naxxramas/boss_heigan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -42,10 +42,8 @@ enum EMOTE_TELEPORT = -1533136, EMOTE_RETURN = -1533137, - SPELL_ERUPTION = 29371, //Spell used by floor pieces to cause damage to players - - //Spells by boss - SPELL_DECREPIT_FEVER_N = 29998, + // Spells by boss + SPELL_DECREPIT_FEVER = 29998, SPELL_DECREPIT_FEVER_H = 55011, SPELL_DISRUPTION = 29310, SPELL_TELEPORT = 30211, @@ -78,24 +76,22 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI { m_uiPhaseEruption = 0; m_uiFeverTimer = 4000; - m_uiEruptionTimer = m_uiPhase == PHASE_GROUND ? urand(8000, 12000) : urand(2000, 3000); + m_uiEruptionTimer = m_uiPhase == PHASE_GROUND ? 15000 : 7500; m_uiDisruptionTimer = 5000; m_uiStartChannelingTimer = 1000; 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 { - m_creature->SetInCombatWithZone(); - - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -106,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); @@ -119,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; @@ -151,7 +147,7 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI // Fever if (m_uiFeverTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DECREPIT_FEVER_N : SPELL_DECREPIT_FEVER_H); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DECREPIT_FEVER : SPELL_DECREPIT_FEVER_H); m_uiFeverTimer = 21000; } else @@ -166,9 +162,9 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI else m_uiDisruptionTimer -= uiDiff; } - else //Platform Phase + else // Platform Phase { - if (m_uiPhaseTimer <= uiDiff) // return to fight + if (m_uiPhaseTimer < uiDiff) // Return to fight { m_creature->InterruptNonMeleeSpells(true); DoScriptText(EMOTE_RETURN, m_creature); @@ -183,7 +179,7 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI if (m_uiStartChannelingTimer) { - if (m_uiStartChannelingTimer <=uiDiff) + if (m_uiStartChannelingTimer <= uiDiff) { DoScriptText(SAY_CHANNELING, m_creature); DoCastSpellIfCan(m_creature, SPELL_PLAGUE_CLOUD); @@ -197,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; @@ -210,6 +206,28 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI m_uiTauntTimer -= uiDiff; DoMeleeAttackIfReady(); + + // Handling of the erruptions, this is not related to melee attack or spell-casting + if (!m_pInstance) + return; + + // Eruption + if (m_uiEruptionTimer < uiDiff) + { + for (uint8 uiArea = 0; uiArea < MAX_HEIGAN_TRAP_AREAS; ++uiArea) + { + // Actually this is correct :P + if (uiArea == (m_uiPhaseEruption % 6) || uiArea == 6 - (m_uiPhaseEruption % 6)) + continue; + + m_pInstance->DoTriggerHeiganTraps(m_creature, uiArea); + } + + m_uiEruptionTimer = m_uiPhase == PHASE_GROUND ? 10000 : 3000; + ++m_uiPhaseEruption; + } + else + m_uiEruptionTimer -= uiDiff; } }; @@ -220,10 +238,10 @@ CreatureAI* GetAI_boss_heigan(Creature* pCreature) void AddSC_boss_heigan() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_heigan"; - NewScript->GetAI = &GetAI_boss_heigan; - NewScript->RegisterSelf(); -} + Script* pNewScript; + pNewScript = new Script; + pNewScript->Name = "boss_heigan"; + pNewScript->GetAI = &GetAI_boss_heigan; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/naxxramas/boss_kelthuzad.cpp b/scripts/northrend/naxxramas/boss_kelthuzad.cpp index 4629551d45..79bd73edb8 100644 --- a/scripts/northrend/naxxramas/boss_kelthuzad.cpp +++ b/scripts/northrend/naxxramas/boss_kelthuzad.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -30,19 +30,9 @@ EndScriptData */ enum { - //when shappiron dies. dialog between kel and lich king (in this order) - SAY_SAPP_DIALOG1 = -1533084, - SAY_SAPP_DIALOG2_LICH = -1533085, - SAY_SAPP_DIALOG3 = -1533086, - SAY_SAPP_DIALOG4_LICH = -1533087, - SAY_SAPP_DIALOG5 = -1533088, + SAY_SUMMON_MINIONS = -1533105, // start of phase 1 - //when cat dies - SAY_CAT_DIED = -1533089, - - 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, @@ -56,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, @@ -65,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, @@ -83,6 +73,8 @@ enum MAX_SOLDIER_COUNT = 71, MAX_ABOMINATION_COUNT = 8, MAX_BANSHEE_COUNT = 8, + + ACHIEV_REQ_KILLED_ABOMINATIONS = 18, }; static float M_F_ANGLE = 0.2f; // to adjust for map rotation @@ -113,6 +105,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI uint32 m_uiGuardiansCount; uint32 m_uiGuardiansCountMax; uint32 m_uiGuardiansTimer; + uint32 m_uiLichKingAnswerTimer; uint32 m_uiFrostBoltTimer; uint32 m_uiFrostBoltNovaTimer; uint32 m_uiChainsTimer; @@ -130,30 +123,33 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI uint32 m_uiAbominationCount; uint32 m_uiSummonIntroTimer; uint32 m_uiIntroPackCount; + uint32 m_uiKilledAbomination; - std::set m_lIntroMobsSet; - std::set 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; m_uiSoldierCount = 0; m_uiBansheeCount = 0; m_uiAbominationCount = 0; + m_uiKilledAbomination = 0; m_uiPhase = PHASE_INTRO; // it may be some spell should be used instead, to control the intro phase @@ -161,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; @@ -170,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(); @@ -179,7 +175,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI m_pInstance->SetData(TYPE_KELTHUZAD, DONE); } - void JustReachedHome() + void JustReachedHome() override { DespawnIntroCreatures(); DespawnAdds(); @@ -188,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; @@ -200,7 +196,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI { if (m_pInstance) { - for(std::set::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(); @@ -214,7 +210,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI { if (m_pInstance) { - for(std::set::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)) { @@ -232,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 @@ -251,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); @@ -264,8 +260,8 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI MaNGOS::NormalizeMapCoord(fY); uint32 uiNpcEntry = NPC_SOUL_WEAVER; - - for(uint8 uiI = 0; uiI < 14; ++uiI) + + for (uint8 uiI = 0; uiI < 14; ++uiI) { if (uiI > 0) { @@ -302,15 +298,15 @@ 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: { DoScriptText(EMOTE_GUARDIAN, m_creature); - m_lAddsSet.insert(pSummoned->GetGUID()); + m_lAddsSet.insert(pSummoned->GetObjectGuid()); ++m_uiGuardiansCount; pSummoned->SetInCombatWithZone(); @@ -321,12 +317,12 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI case NPC_SOUL_WEAVER: { if (m_uiIntroPackCount < 7) - m_lIntroMobsSet.insert(pSummoned->GetGUID()); + m_lIntroMobsSet.insert(pSummoned->GetObjectGuid()); else { - m_lAddsSet.insert(pSummoned->GetGUID()); + m_lAddsSet.insert(pSummoned->GetObjectGuid()); - if(m_pInstance) + if (m_pInstance) { float fX, fY, fZ; m_pInstance->GetChamberCenterCoords(fX, fY, fZ); @@ -339,26 +335,33 @@ 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: - case NPC_UNSTOPPABLE_ABOM: case NPC_SOUL_WEAVER: - m_lAddsSet.erase(pSummoned->GetGUID()); + m_lAddsSet.erase(pSummoned->GetObjectGuid()); + break; + case NPC_UNSTOPPABLE_ABOM: + m_lAddsSet.erase(pSummoned->GetObjectGuid()); + + ++m_uiKilledAbomination; + if (m_uiKilledAbomination >= ACHIEV_REQ_KILLED_ABOMINATIONS) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_GET_ENOUGH, true); + break; } } - 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; @@ -395,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; @@ -462,9 +465,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI if (m_uiManaDetonationTimer < uiDiff) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && pTarget->getPowerType() == POWER_MANA) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANA_DETONATION, SELECT_FLAG_PLAYER | SELECT_FLAG_POWER_MANA)) { if (DoCastSpellIfCan(pTarget, SPELL_MANA_DETONATION) == CAST_OK) { @@ -528,10 +529,6 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI { m_uiPhase = PHASE_GUARDIANS; DoScriptText(SAY_REQUEST_AID, m_creature); - - // here Lich King should respond to Kel'Thuzad but I don't know which creature to make talk - // so for now just make Kel'Thuzad says it. - DoScriptText(SAY_ANSWER_REQUEST, m_creature); } } else if (m_uiPhase == PHASE_GUARDIANS && m_uiGuardiansCount < m_uiGuardiansCountMax) @@ -544,6 +541,18 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI } else m_uiGuardiansTimer -= uiDiff; + + if (m_uiLichKingAnswerTimer && m_pInstance) + { + if (m_uiLichKingAnswerTimer <= uiDiff) + { + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICHKING)) + DoScriptText(SAY_ANSWER_REQUEST, pLichKing); + m_uiLichKingAnswerTimer = 0; + } + else + m_uiLichKingAnswerTimer -= uiDiff; + } } DoMeleeAttackIfReady(); @@ -558,10 +567,10 @@ CreatureAI* GetAI_boss_kelthuzad(Creature* pCreature) void AddSC_boss_kelthuzad() { - Script* NewScript; + Script* pNewScript; - NewScript = new Script; - NewScript->Name = "boss_kelthuzad"; - NewScript->GetAI = &GetAI_boss_kelthuzad; - NewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_kelthuzad"; + pNewScript->GetAI = &GetAI_boss_kelthuzad; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_loatheb.cpp b/scripts/northrend/naxxramas/boss_loatheb.cpp index 9e7ce1aef1..70c300102d 100644 --- a/scripts/northrend/naxxramas/boss_loatheb.cpp +++ b/scripts/northrend/naxxramas/boss_loatheb.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,7 +97,13 @@ struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI pSummoned->AddThreat(pTarget); } - void UpdateAI(const uint32 uiDiff) + 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) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -113,7 +119,7 @@ struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI else m_uiBerserkTimer -= uiDiff; } - + // Inevitable Doom if (m_uiInevitableDoomTimer < uiDiff) { @@ -142,7 +148,7 @@ struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI m_uiNecroticAuraTimer = 3000; break; } - m_uiNecroticAuraCount++; + ++m_uiNecroticAuraCount; } else m_uiNecroticAuraTimer -= uiDiff; @@ -164,7 +170,7 @@ struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI } else m_uiDeathbloomTimer -= uiDiff; - + DoMeleeAttackIfReady(); } }; @@ -176,9 +182,10 @@ CreatureAI* GetAI_boss_loatheb(Creature* pCreature) void AddSC_boss_loatheb() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_loatheb"; - NewScript->GetAI = &GetAI_boss_loatheb; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_loatheb"; + pNewScript->GetAI = &GetAI_boss_loatheb; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_maexxna.cpp b/scripts/northrend/naxxramas/boss_maexxna.cpp index d1d30448f2..724b3a4244 100644 --- a/scripts/northrend/naxxramas/boss_maexxna.cpp +++ b/scripts/northrend/naxxramas/boss_maexxna.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 */ @@ -31,7 +31,8 @@ enum EMOTE_SPRAY = -1533148, EMOTE_BOSS_GENERIC_FRENZY = -1000005, - SPELL_WEBWRAP = 28622, //Spell is normally used by the webtrap on the wall NOT by Maexxna + SPELL_WEBWRAP = 28622, + SPELL_WEBWRAP_2 = 28673, // purpose unknown SPELL_WEBSPRAY = 29484, SPELL_WEBSPRAY_H = 54125, @@ -45,56 +46,98 @@ 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 { npc_web_wrapAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 m_uiVictimGUID; + ObjectGuid m_victimGuid; + uint32 m_uiWebWrapTimer; - void Reset() + void Reset() override { - m_uiVictimGUID = 0; + 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) { - m_uiVictimGUID = pVictim->GetGUID(); - pVictim->CastSpell(pVictim, SPELL_WEBWRAP, true); + // 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(); + m_uiWebWrapTimer = uiEffectMiscValue == 200 ? 1000 : 2000; } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - if (m_uiVictimGUID) + if (m_victimGuid) { - if (Player* pVictim = m_creature->GetMap()->GetPlayer(m_uiVictimGUID)) + if (Player* pVictim = m_creature->GetMap()->GetPlayer(m_victimGuid)) { if (pVictim->isAlive()) pVictim->RemoveAurasDueToSpell(SPELL_WEBWRAP); } } } + + 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 @@ -116,103 +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); } - void DoCastWebWrap() + void JustSummoned(Creature* pSummoned) override { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - std::vector targets; - - // This spell doesn't work if we only have 1 player on threat list - if (tList.size() < 2) - return; - - // 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* target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - // only on alive players - if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); + 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); + } + } - // cut down to size if we have more than 3 targets - while(targets.size() > 3) - targets.erase(targets.begin()+rand()%targets.size()); + 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; - int i = 0; + 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); - for(std::vector::iterator iter = targets.begin(); iter!= targets.end(); ++iter, ++i) + // Summon a second web wrap on heroic + if (!m_bIsRegularMode) { - // Teleport the 3 targets to a location on the wall and summon a Web Wrap on them - switch(i) - { - case 0: - DoTeleportPlayer((*iter), LOC_X1, LOC_Y1, LOC_Z1, (*iter)->GetOrientation()); - 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: - DoTeleportPlayer((*iter), LOC_X2, LOC_Y2, LOC_Z2, (*iter)->GetOrientation()); - 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: - DoTeleportPlayer((*iter), LOC_X3, LOC_Y3, LOC_Z3, (*iter)->GetOrientation()); - 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; @@ -220,8 +238,9 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI // Web Wrap if (m_uiWebWrapTimer < uiDiff) { - DoCastWebWrap(); - DoScriptText(EMOTE_SPIN_WEB, m_creature); + if (DoCastWebWrap()) + DoScriptText(EMOTE_SPIN_WEB, m_creature); + m_uiWebWrapTimer = 40000; } else @@ -230,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; @@ -242,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; @@ -251,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; @@ -262,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; @@ -293,15 +312,15 @@ CreatureAI* GetAI_boss_maexxna(Creature* pCreature) void AddSC_boss_maexxna() { - Script* NewScript; + Script* pNewScript; - NewScript = new Script; - NewScript->Name = "boss_maexxna"; - NewScript->GetAI = &GetAI_boss_maexxna; - NewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_maexxna"; + pNewScript->GetAI = &GetAI_boss_maexxna; + pNewScript->RegisterSelf(); - NewScript = new Script; - NewScript->Name = "npc_web_wrap"; - NewScript->GetAI = &GetAI_npc_web_wrap; - NewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_web_wrap"; + pNewScript->GetAI = &GetAI_npc_web_wrap; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_noth.cpp b/scripts/northrend/naxxramas/boss_noth.cpp index b175f4b56a..0ff7f8602b 100644 --- a/scripts/northrend/naxxramas/boss_noth.cpp +++ b/scripts/northrend/naxxramas/boss_noth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Noth -SD%Complete: 60 -SDComment: Summons need tuning, timers need tuning, need to add berserk "phase" after last skeleton phase +SD%Complete: 80 +SDComment: Summons need verify, need better phase-switch support (unattackable?) SDCategory: Naxxramas EndScriptData */ @@ -52,6 +52,8 @@ enum SPELL_CURSE_PLAGUEBRINGER = 29213, SPELL_CURSE_PLAGUEBRINGER_H = 54835, + SPELL_BERSERK = 26662, // guesswork, but very common berserk spell in naxx + SPELL_SUMMON_WARRIOR_1 = 29247, SPELL_SUMMON_WARRIOR_2 = 29248, SPELL_SUMMON_WARRIOR_3 = 29249, @@ -102,22 +104,20 @@ 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; - m_uiPhaseTimer = 110000; + m_uiPhaseTimer = 90000; m_uiBlinkTimer = 25000; m_uiCurseTimer = 4000; - m_uiSummonTimer = 30000; + m_uiSummonTimer = 12000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - m_creature->SetInCombatWithZone(); - - 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,43 +146,56 @@ 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); + if (pCaster != m_creature) + return; + + if (SpellEffectEntry const* pSpellEffect = pSpell->GetSpellEffect(EFFECT_INDEX_0)) + { + if (pSpellEffect->Effect == 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; if (m_uiPhase == PHASE_GROUND) { - if (m_uiPhaseTimer < uiDiff) + if (m_uiPhaseTimer) // After PHASE_SKELETON_3 we won't have a balcony phase { - // TODO: avoid teleport when skeleton phases is ended - - if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT) == CAST_OK) + if (m_uiPhaseTimer <= uiDiff) { - DoScriptText(EMOTE_TELEPORT, m_creature); - m_creature->GetMotionMaster()->MoveIdle(); - m_uiPhaseTimer = 70000; - m_uiPhase = PHASE_BALCONY; - ++m_uiPhaseSub; - return; + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT) == CAST_OK) + { + DoScriptText(EMOTE_TELEPORT, m_creature); + m_creature->GetMotionMaster()->MoveIdle(); + m_uiPhase = PHASE_BALCONY; + ++m_uiPhaseSub; + + switch (m_uiPhaseSub) // Set Duration of Skeleton phase + { + case PHASE_SKELETON_1: m_uiPhaseTimer = 70000; break; + case PHASE_SKELETON_2: m_uiPhaseTimer = 97000; break; + case PHASE_SKELETON_3: m_uiPhaseTimer = 120000; break; + } + return; + } } + else + m_uiPhaseTimer -= uiDiff; } - else - m_uiPhaseTimer -= uiDiff; - if (m_bIsRegularMode) + if (!m_bIsRegularMode) // Blink is used only in 25man { if (m_uiBlinkTimer < uiDiff) { @@ -191,7 +204,7 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI SPELL_BLINK_1, SPELL_BLINK_2, SPELL_BLINK_3, SPELL_BLINK_4 }; - if (DoCastSpellIfCan(m_creature, auiSpellBlink[urand(0,3)]) == CAST_OK) + if (DoCastSpellIfCan(m_creature, auiSpellBlink[urand(0, 3)]) == CAST_OK) { DoResetThreat(); m_uiBlinkTimer = 25000; @@ -221,8 +234,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 { @@ -236,7 +249,7 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI DoMeleeAttackIfReady(); } - else + else // PHASE_BALCONY { if (m_uiPhaseTimer < uiDiff) { @@ -244,8 +257,18 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI { DoScriptText(EMOTE_TELEPORT_RETURN, m_creature); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_uiPhaseTimer = 90000; + switch (m_uiPhaseSub) + { + case PHASE_SKELETON_1: m_uiPhaseTimer = 110000; break; + case PHASE_SKELETON_2: m_uiPhaseTimer = 180000; break; + case PHASE_SKELETON_3: + m_uiPhaseTimer = 0; + // Go Berserk after third Balcony Phase + DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); + break; + } m_uiPhase = PHASE_GROUND; + return; } } @@ -266,26 +289,29 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI SPELL_SUMMON_GUARD01, SPELL_SUMMON_GUARD02, SPELL_SUMMON_GUARD03, SPELL_SUMMON_GUARD04 }; - // A bit unclear how many in each sub phase, and if there are any clear difference in 25man - switch(m_uiPhaseSub) + // A bit unclear how many in each sub phase + switch (m_uiPhaseSub) { case PHASE_SKELETON_1: { - for(uint8 i = 0; i < 2; ++i) - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0,9)], CAST_TRIGGERED); + for (uint8 i = 0; i < (m_bIsRegularMode ? 2 : 4); ++i) + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0, 9)], CAST_TRIGGERED); break; } case PHASE_SKELETON_2: { - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0,9)], CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0,3)], CAST_TRIGGERED); + 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); + } break; } case PHASE_SKELETON_3: { - for(uint8 i = 0; i < 2; ++i) - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0,3)], CAST_TRIGGERED); + for (uint8 i = 0; i < (m_bIsRegularMode ? 2 : 4); ++i) + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0, 3)], CAST_TRIGGERED); break; } @@ -306,9 +332,10 @@ CreatureAI* GetAI_boss_noth(Creature* pCreature) void AddSC_boss_noth() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_noth"; - NewScript->GetAI = &GetAI_boss_noth; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_noth"; + pNewScript->GetAI = &GetAI_boss_noth; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_patchwerk.cpp b/scripts/northrend/naxxramas/boss_patchwerk.cpp index 4bf70a6c46..9c98fb7fa4 100644 --- a/scripts/northrend/naxxramas/boss_patchwerk.cpp +++ b/scripts/northrend/naxxramas/boss_patchwerk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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); @@ -103,31 +103,40 @@ struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI // The ability is used on highest HP target choosen of the top 2 (3 heroic) targets on threat list being in melee range Unit* pTarget = NULL; uint32 uiHighestHP = 0; - uint32 uiTargets = m_bIsRegularMode ? 2 : 3; + uint32 uiTargets = m_bIsRegularMode ? 1 : 2; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator iter = tList.begin();iter != tList.end(); ++iter) + if (tList.size() > 1) // Check if more than two targets, and start loop with second-most aggro { - if (!uiTargets) - break; - - if (Unit* pTempTarget = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid())) + ThreatList::const_iterator iter = tList.begin(); + std::advance(iter, 1); + for (; iter != tList.end(); ++iter) { - if (pTempTarget->GetHealth() > uiHighestHP && m_creature->IsWithinDistInMap(pTempTarget, ATTACK_DISTANCE)) + if (!uiTargets) + break; + + if (Unit* pTempTarget = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid())) { - uiHighestHP = pTempTarget->GetHealth(); - pTarget = pTempTarget; + if (m_creature->CanReachWithMeleeAttack(pTempTarget)) + { + if (pTempTarget->GetHealth() > uiHighestHP) + { + uiHighestHP = pTempTarget->GetHealth(); + pTarget = pTempTarget; + } + --uiTargets; + } } } - - --uiTargets; } - if (pTarget) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_HATEFULSTRIKE : SPELL_HATEFULSTRIKE_H); + if (!pTarget) + pTarget = m_creature->getVictim(); + + 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; @@ -191,9 +200,10 @@ CreatureAI* GetAI_boss_patchwerk(Creature* pCreature) void AddSC_boss_patchwerk() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_patchwerk"; - NewScript->GetAI = &GetAI_boss_patchwerk; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_patchwerk"; + pNewScript->GetAI = &GetAI_boss_patchwerk; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_razuvious.cpp b/scripts/northrend/naxxramas/boss_razuvious.cpp index fe732cee4a..6211c9ef07 100644 --- a/scripts/northrend/naxxramas/boss_razuvious.cpp +++ b/scripts/northrend/naxxramas/boss_razuvious.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Razuvious -SD%Complete: 75% -SDComment: TODO: Timers and sounds need confirmation, implement spell Hopeless +SD%Complete: 85% +SDComment: TODO: Timers and sounds need confirmation - orb handling for normal-mode is missing SDCategory: Naxxramas EndScriptData */ @@ -37,7 +37,7 @@ enum SAY_COMMAND4 = -1533128, SAY_DEATH = -1533129, - SPELL_UNBALANCING_STRIKE = 26613, + SPELL_UNBALANCING_STRIKE = 55470, SPELL_DISRUPTING_SHOUT = 55543, SPELL_DISRUPTING_SHOUT_H = 29107, SPELL_JAGGED_KNIFE = 55550, @@ -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,29 +69,31 @@ 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); + DoCastSpellIfCan(m_creature, SPELL_HOPELESS, CAST_TRIGGERED); + if (m_pInstance) 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; @@ -102,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; @@ -116,8 +118,8 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI // Unbalancing Strike if (m_uiUnbalancingStrikeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_UNBALANCING_STRIKE); - m_uiUnbalancingStrikeTimer = 30000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_UNBALANCING_STRIKE) == CAST_OK) + m_uiUnbalancingStrikeTimer = 30000; } else m_uiUnbalancingStrikeTimer -= uiDiff; @@ -125,8 +127,8 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI // Disrupting Shout if (m_uiDisruptingShoutTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_DISRUPTING_SHOUT : SPELL_DISRUPTING_SHOUT_H); - m_uiDisruptingShoutTimer = 25000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DISRUPTING_SHOUT : SPELL_DISRUPTING_SHOUT_H) == CAST_OK) + m_uiDisruptingShoutTimer = 25000; } else m_uiDisruptingShoutTimer -= uiDiff; @@ -135,8 +137,10 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI if (m_uiJaggedKnifeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_JAGGED_KNIFE); - m_uiJaggedKnifeTimer = 10000; + { + if (DoCastSpellIfCan(pTarget, SPELL_JAGGED_KNIFE) == CAST_OK) + m_uiJaggedKnifeTimer = 10000; + } } else m_uiJaggedKnifeTimer -= uiDiff; @@ -144,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; @@ -160,6 +164,7 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_razuvious(Creature* pCreature) { return new boss_razuviousAI(pCreature); @@ -167,9 +172,10 @@ CreatureAI* GetAI_boss_razuvious(Creature* pCreature) void AddSC_boss_razuvious() { - Script* NewScript; - NewScript = new Script; - NewScript->Name = "boss_razuvious"; - NewScript->GetAI = &GetAI_boss_razuvious; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_razuvious"; + pNewScript->GetAI = &GetAI_boss_razuvious; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_sapphiron.cpp b/scripts/northrend/naxxramas/boss_sapphiron.cpp index 8d178d92be..463837ac3a 100644 --- a/scripts/northrend/naxxramas/boss_sapphiron.cpp +++ b/scripts/northrend/naxxramas/boss_sapphiron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,11 +16,24 @@ /* ScriptData SDName: Boss_Sapphiron -SD%Complete: 0 -SDComment: Place Holder +SD%Complete: 80 +SDComment: Some spells need core implementation SDCategory: Naxxramas EndScriptData */ +/* Additional comments: + * Bugged spells: 28560 (needs maxTarget = 1, Summon of 16474 implementation, TODO, 30s duration) + * 28526 (needs ScriptEffect to cast 28522 onto random target) + * + * Achievement-criteria check needs implementation + * + * Frost-Breath ability: the dummy spell 30101 is self cast, so it won't take the needed delay of ~7s until it reaches its target + * As Sapphiron is displayed visually in hight (hovering), and the spell is cast with target=self-location + * which is still on the ground, the client shows a nice slow falling of the visual animation + * Insisting on using the Dummy-Effect to cast the breath-dmg spells, would require, to relocate Sapphi internally, + * and to hack the targeting to be "on the ground" - Hence the prefered way as it is now! + */ + #include "precompiled.h" #include "naxxramas.h" @@ -28,15 +41,38 @@ enum { EMOTE_BREATH = -1533082, EMOTE_GENERIC_ENRAGED = -1000003, - EMOTE_FLY = -1533022, // NYI - EMOTE_GROUND = -1533083, // NYI + EMOTE_FLY = -1533022, + EMOTE_GROUND = -1533083, - SPELL_ICEBOLT = 28522, - SPELL_FROST_BREATH = 29318, + SPELL_CLEAVE = 19983, + SPELL_TAIL_SWEEP = 55697, + SPELL_TAIL_SWEEP_H = 55696, + SPELL_ICEBOLT = 28526, + SPELL_FROST_BREATH_DUMMY = 30101, + SPELL_FROST_BREATH_A = 28524, + SPELL_FROST_BREATH_B = 29318, SPELL_FROST_AURA = 28531, + SPELL_FROST_AURA_H = 55799, SPELL_LIFE_DRAIN = 28542, - SPELL_BLIZZARD = 28547, - SPELL_BESERK = 26662 + SPELL_LIFE_DRAIN_H = 55665, + SPELL_CHILL = 28547, + SPELL_CHILL_H = 55699, + SPELL_SUMMON_BLIZZARD = 28560, + SPELL_BESERK = 26662, + SPELL_ACHIEVEMENT_CHECK = 60539, // unused + + NPC_YOU_KNOW_WHO = 16474, +}; + +static const float aLiftOffPosition[3] = {3522.386f, -5236.784f, 137.709f}; + +enum Phases +{ + PHASE_GROUND = 1, + PHASE_LIFT_OFF = 2, + PHASE_AIR_BOLTS = 3, + PHASE_AIR_BREATH = 4, + PHASE_LANDING = 5, }; struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI @@ -51,152 +87,233 @@ struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI instance_naxxramas* m_pInstance; bool m_bIsRegularMode; - uint32 Icebolt_Count; - uint32 Icebolt_Timer; - uint32 FrostBreath_Timer; - uint32 FrostAura_Timer; - uint32 LifeDrain_Timer; - uint32 Blizzard_Timer; - uint32 Fly_Timer; - uint32 Beserk_Timer; - uint32 phase; - bool landoff; - uint32 land_Timer; - - void Reset() + uint32 m_uiCleaveTimer; + uint32 m_uiTailSweepTimer; + uint32 m_uiIceboltTimer; + uint32 m_uiFrostBreathTimer; + uint32 m_uiLifeDrainTimer; + uint32 m_uiBlizzardTimer; + uint32 m_uiFlyTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiLandTimer; + + uint32 m_uiIceboltCount; + Phases m_Phase; + + void Reset() override { - FrostAura_Timer = 2000; - FrostBreath_Timer = 2500; - LifeDrain_Timer = 24000; - Blizzard_Timer = 20000; - Fly_Timer = 45000; - Icebolt_Timer = 4000; - land_Timer = 2000; - Beserk_Timer = 0; - phase = 1; - Icebolt_Count = 0; - landoff = false; - - //m_creature->ApplySpellMod(SPELL_FROST_AURA, SPELLMOD_DURATION, -1); + m_uiCleaveTimer = 5000; + m_uiTailSweepTimer = 12000; + m_uiFrostBreathTimer = 7000; + m_uiLifeDrainTimer = 11000; + m_uiBlizzardTimer = 15000; // "Once the encounter starts,based on your version of Naxx, this will be used x2 for normal and x6 on HC" + m_uiFlyTimer = 46000; + m_uiIceboltTimer = 5000; + m_uiLandTimer = 0; + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; + m_Phase = PHASE_GROUND; + m_uiIceboltCount = 0; + + SetCombatMovement(true); + m_creature->SetLevitate(false); + // 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); + if (m_pInstance) 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 UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_YOU_KNOW_WHO) + { + if (Unit* pEnemy = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pEnemy); + } + } + + void MovementInform(uint32 uiType, uint32 /*uiPointId*/) override + { + if (uiType == POINT_MOTION_TYPE && m_Phase == PHASE_LIFT_OFF) + { + DoScriptText(EMOTE_FLY, m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_LIFTOFF); + m_creature->SetLevitate(true); + m_Phase = PHASE_AIR_BOLTS; + + m_uiFrostBreathTimer = 5000; + m_uiIceboltTimer = 5000; + m_uiIceboltCount = 0; + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (phase == 1) + switch (m_Phase) { - if (FrostAura_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROST_AURA); - FrostAura_Timer = 5000; - }else FrostAura_Timer -= uiDiff; + case PHASE_GROUND: + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(5000, 10000); + } + else + m_uiCleaveTimer -= uiDiff; - if (LifeDrain_Timer < uiDiff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_LIFE_DRAIN); + if (m_uiTailSweepTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TAIL_SWEEP : SPELL_TAIL_SWEEP_H) == CAST_OK) + m_uiTailSweepTimer = urand(7000, 10000); + } + else + m_uiTailSweepTimer -= uiDiff; - LifeDrain_Timer = 24000; - }else LifeDrain_Timer -= uiDiff; + if (m_uiLifeDrainTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIFE_DRAIN : SPELL_LIFE_DRAIN_H) == CAST_OK) + m_uiLifeDrainTimer = 23000; + } + else + m_uiLifeDrainTimer -= uiDiff; - if (Blizzard_Timer < uiDiff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_BLIZZARD); + if (m_uiBlizzardTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_BLIZZARD) == CAST_OK) + m_uiBlizzardTimer = 20000; + } + else + m_uiBlizzardTimer -= uiDiff; - Blizzard_Timer = 20000; - }else Blizzard_Timer -= uiDiff; + if (m_creature->GetHealthPercent() > 10.0f) + { + if (m_uiFlyTimer < uiDiff) + { + m_Phase = PHASE_LIFT_OFF; + m_creature->InterruptNonMeleeSpells(false); + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MovePoint(1, aLiftOffPosition[0], aLiftOffPosition[1], aLiftOffPosition[2]); + // TODO This should clear the target, too - if (m_creature->GetHealthPercent() > 10.0f) - { - if (Fly_Timer < uiDiff) + return; + } + else + m_uiFlyTimer -= uiDiff; + } + + // Only Phase in which we have melee attack! + DoMeleeAttackIfReady(); + break; + case PHASE_LIFT_OFF: + break; + case PHASE_AIR_BOLTS: + // WOTLK Changed, originally was 5 + if (m_uiIceboltCount == (uint32)(m_bIsRegularMode ? 2 : 3)) { - phase = 2; - m_creature->InterruptNonMeleeSpells(false); - m_creature->HandleEmote(EMOTE_ONESHOT_LIFTOFF); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - DoCastSpellIfCan(m_creature,11010); - m_creature->SetHover(true); - DoCastSpellIfCan(m_creature,18430); - Icebolt_Timer = 4000; - Icebolt_Count = 0; - landoff = false; - }else Fly_Timer -= uiDiff; - } - } + if (m_uiFrostBreathTimer < uiDiff) + { + m_Phase = PHASE_AIR_BREATH; + DoScriptText(EMOTE_BREATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_FROST_BREATH_DUMMY); + m_uiFrostBreathTimer = 7000; + } + else + m_uiFrostBreathTimer -= uiDiff; + } + else + { + if (m_uiIceboltTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_ICEBOLT); - if (phase == 2) - { - if (Icebolt_Timer < uiDiff && Icebolt_Count < 5) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_ICEBOLT); + ++m_uiIceboltCount; + m_uiIceboltTimer = 4000; + } + else + m_uiIceboltTimer -= uiDiff; + } - ++Icebolt_Count; - Icebolt_Timer = 4000; - }else Icebolt_Timer -= uiDiff; + break; + case PHASE_AIR_BREATH: + if (m_uiFrostBreathTimer) + { + if (m_uiFrostBreathTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_FROST_BREATH_A, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FROST_BREATH_B, CAST_TRIGGERED); + m_uiFrostBreathTimer = 0; - if (Icebolt_Count == 5 && !landoff) - { - if (FrostBreath_Timer < uiDiff) + m_uiLandTimer = 4000; + } + else + m_uiFrostBreathTimer -= uiDiff; + } + + if (m_uiLandTimer) { - DoScriptText(EMOTE_BREATH, m_creature); - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROST_BREATH); - land_Timer = 2000; - landoff = true; - FrostBreath_Timer = 6000; - }else FrostBreath_Timer -= uiDiff; - } + if (m_uiLandTimer <= uiDiff) + { + // Begin Landing + DoScriptText(EMOTE_GROUND, m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_LAND); + m_creature->SetLevitate(false); - if (landoff) - { - if (land_Timer < uiDiff) + m_Phase = PHASE_LANDING; + m_uiLandTimer = 2000; + } + else + m_uiLandTimer -= uiDiff; + } + + break; + case PHASE_LANDING: + if (m_uiLandTimer < uiDiff) { - phase = 1; - m_creature->HandleEmote(EMOTE_ONESHOT_LAND); - m_creature->SetHover(false); + m_Phase = PHASE_GROUND; + + SetCombatMovement(true); m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - Fly_Timer = 67000; - }else land_Timer -= uiDiff; - } + + m_uiFlyTimer = 67000; + m_uiLandTimer = 0; + } + else + m_uiLandTimer -= uiDiff; + + break; } - if (m_creature->GetHealthPercent() <= 10.0f) + // Enrage can happen in any phase + if (m_uiBerserkTimer < uiDiff) { - if (Beserk_Timer < uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_BESERK) == CAST_OK) { - if (DoCastSpellIfCan(m_creature, SPELL_BESERK) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_ENRAGED, m_creature); - Beserk_Timer = 300000; - } - }else Beserk_Timer -= uiDiff; + DoScriptText(EMOTE_GENERIC_ENRAGED, m_creature); + m_uiBerserkTimer = 300000; + } } - - if (phase!=2) - DoMeleeAttackIfReady(); + else + m_uiBerserkTimer -= uiDiff; } }; @@ -205,11 +322,36 @@ 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* NewScript; - NewScript = new Script; - NewScript->Name = "boss_sapphiron"; - NewScript->GetAI = &GetAI_boss_sapphiron; - NewScript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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 44990a82d1..0320513b70 100644 --- a/scripts/northrend/naxxramas/boss_thaddius.cpp +++ b/scripts/northrend/naxxramas/boss_thaddius.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,11 +16,18 @@ /* ScriptData SDName: Boss_Thaddius -SD%Complete: 0 -SDComment: Placeholder. Includes Feugen & Stalagg. +SD%Complete: 95 +SDComment: SDCategory: Naxxramas EndScriptData */ +/* ContentData +boss_thaddius +npc_tesla_coil +boss_stalagg +boss_feugen +EndContentData */ + #include "precompiled.h" #include "naxxramas.h" @@ -31,48 +38,749 @@ enum SAY_STAL_SLAY = -1533024, SAY_STAL_DEATH = -1533025, - SPELL_POWERSURGE = 28134, - - //Feugen + // Feugen SAY_FEUG_AGGRO = -1533026, SAY_FEUG_SLAY = -1533027, SAY_FEUG_DEATH = -1533028, - SPELL_MANABURN = 28135, - - //both - SPELL_WARSTOMP = 28125, + // Tesla Coils + EMOTE_LOSING_LINK = -1533149, + EMOTE_TESLA_OVERLOAD = -1533150, - //Thaddus - SAY_GREET = -1533029, - SAY_AGGRO1 = -1533030, - SAY_AGGRO2 = -1533031, - SAY_AGGRO3 = -1533032, + // Thaddus + SAY_AGGRO_1 = -1533030, + SAY_AGGRO_2 = -1533031, + SAY_AGGRO_3 = -1533032, SAY_SLAY = -1533033, SAY_ELECT = -1533034, SAY_DEATH = -1533035, + // Background screams in Instance if Thaddius still alive, needs general support most likely SAY_SCREAM1 = -1533036, SAY_SCREAM2 = -1533037, SAY_SCREAM3 = -1533038, SAY_SCREAM4 = -1533039, + EMOTE_POLARITY_SHIFT = -1533151, + // Thaddius Spells + SPELL_THADIUS_SPAWN = 28160, + SPELL_THADIUS_LIGHTNING_VISUAL = 28136, SPELL_BALL_LIGHTNING = 28299, + SPELL_CHAIN_LIGHTNING = 28167, + SPELL_CHAIN_LIGHTNING_H = 54531, + SPELL_POLARITY_SHIFT = 28089, + SPELL_BESERK = 27680, + SPELL_CLEAR_CHARGES = 63133, // TODO NYI, cast on death, most likely to remove remaining buffs - EMOTE_POLARITY_SHIFT = -1533151, + // Stalagg & Feugen Spells + // 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, + SPELL_STATIC_FIELD_H = 54528, + SPELL_POWERSURGE_H = 28134, + SPELL_POWERSURGE = 54529, - SPELL_CHARGE_POSITIVE_DMGBUFF = 29659, - SPELL_CHARGE_POSITIVE_NEARDMG = 28059, + // Tesla Spells + SPELL_FEUGEN_CHAIN = 28111, + SPELL_STALAGG_CHAIN = 28096, + SPELL_FEUGEN_TESLA_PASSIVE = 28109, + SPELL_STALAGG_TESLA_PASSIVE = 28097, + SPELL_SHOCK_OVERLOAD = 28159, + SPELL_SHOCK = 28099, +}; - SPELL_CHARGE_NEGATIVE_DMGBUFF = 29660, - SPELL_CHARGE_NEGATIVE_NEARDMG = 28084, +/************ +** boss_thaddius +************/ - SPELL_CHAIN_LIGHTNING = 28167, - SPELL_CHAIN_LIGHTNING_H = 54531, +// 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 +{ + boss_thaddiusAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_naxxramas*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - SPELL_BESERK = 26662, + Reset(); + } - //generic - NPC_TESLA_COIL = 16218, //the coils (emotes "Tesla Coil overloads!") - EMOTE_LOSING_LINK = -1533149, - EMOTE_TESLA_OVERLOAD = -1533150, + instance_naxxramas* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiPolarityShiftTimer; + uint32 m_uiChainLightningTimer; + uint32 m_uiBallLightningTimer; + uint32 m_uiBerserkTimer; + + 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_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit* /*pWho*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; + } + + // Make Attackable + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_THADDIUS, FAIL); + + // Respawn Adds: + Creature* pFeugen = m_pInstance->GetSingleCreatureFromStorage(NPC_FEUGEN); + Creature* pStalagg = m_pInstance->GetSingleCreatureFromStorage(NPC_STALAGG); + if (pFeugen) + { + pFeugen->ForcedDespawn(); + pFeugen->Respawn(); + } + if (pStalagg) + { + pStalagg->ForcedDespawn(); + pStalagg->Respawn(); + } + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_SLAY, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_THADDIUS, DONE); + + // Force Despawn of Adds + Creature* pFeugen = m_pInstance->GetSingleCreatureFromStorage(NPC_FEUGEN); + Creature* pStalagg = m_pInstance->GetSingleCreatureFromStorage(NPC_STALAGG); + + if (pFeugen) + pFeugen->ForcedDespawn(); + if (pStalagg) + pStalagg->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Berserk + if (m_uiBerserkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BESERK) == CAST_OK) // allow combat movement? + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + } + else + m_uiBerserkTimer -= uiDiff; + + // Polarity Shift + if (m_uiPolarityShiftTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POLARITY_SHIFT, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_ELECT, m_creature); + DoScriptText(EMOTE_POLARITY_SHIFT, m_creature); + m_uiPolarityShiftTimer = 30 * IN_MILLISECONDS; + } + } + else + m_uiPolarityShiftTimer -= uiDiff; + + // Chain Lightning + if (m_uiChainLightningTimer < uiDiff) + { + 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; + } + else + m_uiChainLightningTimer -= uiDiff; + + // Ball Lightning if target not in melee range + // TODO: Verify, likely that the boss should attack any enemy in melee range before starting to cast + if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + { + if (m_uiBallLightningTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BALL_LIGHTNING) == CAST_OK) + m_uiBallLightningTimer = 1 * IN_MILLISECONDS; + } + else + m_uiBallLightningTimer -= uiDiff; + } + else + DoMeleeAttackIfReady(); + } }; + +CreatureAI* GetAI_boss_thaddius(Creature* pCreature) +{ + return new boss_thaddiusAI(pCreature); +} + +bool EffectDummyNPC_spell_thaddius_encounter(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + switch (uiSpellId) + { + case SPELL_SHOCK_OVERLOAD: + if (uiEffIndex == EFFECT_INDEX_0) + { + // Only do something to Thaddius, and on the first hit. + if (pCreatureTarget->GetEntry() != NPC_THADDIUS || !pCreatureTarget->HasAura(SPELL_THADIUS_SPAWN)) + return true; + // remove Stun and then Cast + pCreatureTarget->RemoveAurasDueToSpell(SPELL_THADIUS_SPAWN); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_THADIUS_LIGHTNING_VISUAL, false); + } + return true; + case SPELL_THADIUS_LIGHTNING_VISUAL: + if (uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_THADDIUS) + { + if (instance_naxxramas* pInstance = (instance_naxxramas*)pCreatureTarget->GetInstanceData()) + { + if (Player* pPlayer = pInstance->GetPlayerInMap(true, false)) + pCreatureTarget->AI()->AttackStart(pPlayer); + pCreatureTarget->SetInCombatWithZone(); + } + } + return true; + } + return false; +} + +/************ +** npc_tesla_coil +************/ + +struct MANGOS_DLL_DECL 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_uiOverloadTimer = 0; + m_bReapply = false; + Reset(); + } + + instance_naxxramas* m_pInstance; + bool m_bToFeugen; + bool m_bReapply; + + uint32 m_uiSetupTimer; + uint32 m_uiOverloadTimer; + + void Reset() override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(EMOTE_LOSING_LINK, m_creature); + } + + // 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() override + { + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + } + + bool SetupChain() + { + // Check, if instance_ script failed or encounter finished + if (!m_pInstance || m_pInstance->GetData(TYPE_THADDIUS) == DONE) + return true; + + GameObject* pNoxTeslaFeugen = m_pInstance->GetSingleGameObjectFromStorage(GO_CONS_NOX_TESLA_FEUGEN); + GameObject* pNoxTeslaStalagg = m_pInstance->GetSingleGameObjectFromStorage(GO_CONS_NOX_TESLA_STALAGG); + + // Try again, till Tesla GOs are spawned + if (!pNoxTeslaFeugen || !pNoxTeslaStalagg) + return false; + + m_bToFeugen = m_creature->GetDistanceOrder(pNoxTeslaFeugen, pNoxTeslaStalagg); + + if (DoCastSpellIfCan(m_creature, m_bToFeugen ? SPELL_FEUGEN_CHAIN : SPELL_STALAGG_CHAIN) == CAST_OK) + return true; + + return false; + } + + void ReApplyChain(uint32 uiEntry) + { + if (uiEntry) // called from Stalagg/Feugen with their entry + { + // Only apply chain to own add + if ((uiEntry == NPC_FEUGEN && !m_bToFeugen) || (uiEntry == NPC_STALAGG && m_bToFeugen)) + return; + + m_bReapply = true; // Reapply Chains on next tick + } + else // if called from next tick, needed because otherwise the spell doesn't bind + { + m_bReapply = false; + m_creature->InterruptNonMeleeSpells(true); + GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(m_bToFeugen ? GO_CONS_NOX_TESLA_FEUGEN : GO_CONS_NOX_TESLA_STALAGG); + + if (pGo && pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON && pGo->getLootState() == GO_ACTIVATED) + pGo->ResetDoorOrButton(); + + DoCastSpellIfCan(m_creature, m_bToFeugen ? SPELL_FEUGEN_CHAIN : SPELL_STALAGG_CHAIN); + } + } + + void SetOverloading() + { + m_uiOverloadTimer = 14 * IN_MILLISECONDS; // it takes some time to overload and activate Thaddius + } + + void UpdateAI(const uint32 uiDiff) override + { + m_creature->SelectHostileTarget(); + + if (!m_uiOverloadTimer && !m_uiSetupTimer && !m_bReapply) + return; // Nothing to do this tick + + if (m_uiSetupTimer) + { + if (m_uiSetupTimer <= uiDiff) + { + if (SetupChain()) + m_uiSetupTimer = 0; + else + m_uiSetupTimer = 5 * IN_MILLISECONDS; + } + else + m_uiSetupTimer -= uiDiff; + } + + if (m_uiOverloadTimer) + { + if (m_uiOverloadTimer <= uiDiff) + { + m_uiOverloadTimer = 0; + m_creature->RemoveAurasDueToSpell(m_bToFeugen ? SPELL_FEUGEN_TESLA_PASSIVE : SPELL_STALAGG_TESLA_PASSIVE); + DoCastSpellIfCan(m_creature, SPELL_SHOCK_OVERLOAD, CAST_INTERRUPT_PREVIOUS); + DoScriptText(EMOTE_TESLA_OVERLOAD, m_creature); + m_pInstance->DoUseDoorOrButton(m_bToFeugen ? GO_CONS_NOX_TESLA_FEUGEN : GO_CONS_NOX_TESLA_STALAGG); + } + else + m_uiOverloadTimer -= uiDiff; + } + + if (m_bReapply) + ReApplyChain(0); + } +}; + +CreatureAI* GetAI_npc_tesla_coil(Creature* pCreature) +{ + return new npc_tesla_coilAI(pCreature); +} + +/************ +** boss_thaddiusAddsAI - Superclass for Feugen & Stalagg +************/ + +struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI +{ + boss_thaddiusAddsAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_naxxramas*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + Reset(); + } + + instance_naxxramas* m_pInstance; + bool m_bIsRegularMode; + + bool m_bFakeDeath; + bool m_bBothDead; + + uint32 m_uiHoldTimer; + // uint32 m_uiWarStompTimer; + uint32 m_uiReviveTimer; + uint32 m_uiMagneticPullTimer; + + 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_uiMagneticPullTimer = 20 * IN_MILLISECONDS; + + // We might Reset while faking death, so undo this + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + } + + Creature* GetOtherAdd() // For Stalagg returns pFeugen, for Feugen returns pStalagg + { + switch (m_creature->GetEntry()) + { + case NPC_FEUGEN: return m_pInstance->GetSingleCreatureFromStorage(NPC_STALAGG); + case NPC_STALAGG: return m_pInstance->GetSingleCreatureFromStorage(NPC_FEUGEN); + default: + return NULL; + } + } + + void Aggro(Unit* pWho) override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_THADDIUS, IN_PROGRESS); + + if (Creature* pOtherAdd = GetOtherAdd()) + { + if (!pOtherAdd->isInCombat()) + pOtherAdd->AI()->AttackStart(pWho); + } + } + + void JustRespawned() override + { + Reset(); // Needed to reset the flags properly + + GuidList lTeslaGUIDList; + if (!m_pInstance) + return; + + m_pInstance->GetThadTeslaCreatures(lTeslaGUIDList); + if (lTeslaGUIDList.empty()) + return; + + 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())) + pTeslaAI->ReApplyChain(m_creature->GetEntry()); + } + } + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + if (Creature* pOther = GetOtherAdd()) + { + if (boss_thaddiusAddsAI* pOtherAI = dynamic_cast(pOther->AI())) + { + if (pOtherAI->IsCountingDead()) + { + pOther->ForcedDespawn(); + pOther->Respawn(); + } + } + } + + // Reapply Chains if needed + if (!m_creature->HasAura(SPELL_FEUGEN_CHAIN) && !m_creature->HasAura(SPELL_STALAGG_CHAIN)) + JustRespawned(); + + m_pInstance->SetData(TYPE_THADDIUS, FAIL); + } + + void Revive() + { + DoResetThreat(); + PauseCombatMovement(); + Reset(); + } + + bool IsCountingDead() + { + return m_bFakeDeath || m_creature->isDead(); + } + + void PauseCombatMovement() + { + SetCombatMovement(false); + m_uiHoldTimer = 1500; + } + + virtual void UpdateAddAI(const uint32 /*uiDiff*/) {} // Used for Add-specific spells + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bBothDead) // This is the case while fighting Thaddius + return; + + if (m_bFakeDeath) + { + if (m_uiReviveTimer < uiDiff) + { + if (Creature* pOther = GetOtherAdd()) + { + if (boss_thaddiusAddsAI* pOtherAI = dynamic_cast(pOther->AI())) + { + if (!pOtherAI->IsCountingDead()) // Raid was to slow to kill the second add + Revive(); + else + { + m_bBothDead = true; // Now both adds are counting dead + pOtherAI->m_bBothDead = true; + // Set both Teslas to overload + GuidList lTeslaGUIDList; + m_pInstance->GetThadTeslaCreatures(lTeslaGUIDList); + 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())) + pTeslaAI->SetOverloading(); + } + } + } + } + } + } + else + m_uiReviveTimer -= uiDiff; + return; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHoldTimer) // A short timer preventing combat movement after revive + { + if (m_uiHoldTimer <= uiDiff) + { + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiHoldTimer = 0; + } + else + m_uiHoldTimer -= uiDiff; + } + + /* Doesn't happen in wotlk version any more + if (m_uiWarStompTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WARSTOMP) == CAST_OK) + m_uiWarStompTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); + } + else + m_uiWarStompTimer -= uiDiff;*/ + + if (m_uiMagneticPullTimer <= uiDiff) + { + SetCombatMovement(false); + if (m_creature->GetEntry() == NPC_FEUGEN) + DoCastSpellIfCan(m_creature, SPELL_MAGNETIC_PULL_B); + m_uiHoldTimer = 3000; + m_uiMagneticPullTimer = 30*IN_MILLISECONDS; + } + else + m_uiMagneticPullTimer -= uiDiff; + + UpdateAddAI(uiDiff); // For Add Specific Abilities + + DoMeleeAttackIfReady(); + } + + void DamageTaken(Unit* pKiller, uint32& uiDamage) override + { + if (uiDamage < m_creature->GetHealth()) + return; + + // Prevent glitch if in fake death + if (m_bFakeDeath) + { + uiDamage = 0; + return; + } + + // 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->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + JustDied(pKiller); // Texts + } +}; + +/************ +** boss_stalagg +************/ + +struct MANGOS_DLL_DECL boss_stalaggAI : public boss_thaddiusAddsAI +{ + boss_stalaggAI(Creature* pCreature) : boss_thaddiusAddsAI(pCreature) + { + Reset(); + } + uint32 m_uiPowerSurgeTimer; + + void Reset() override + { + boss_thaddiusAddsAI::Reset(); + m_uiPowerSurgeTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + } + + void Aggro(Unit* pWho) override + { + DoScriptText(SAY_STAL_AGGRO, m_creature); + boss_thaddiusAddsAI::Aggro(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_STAL_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_STAL_SLAY, m_creature); + } + + void UpdateAddAI(const uint32 uiDiff) + { + 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); + } + else + m_uiPowerSurgeTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_stalagg(Creature* pCreature) +{ + return new boss_stalaggAI(pCreature); +} + +/************ +** boss_feugen +************/ + +struct MANGOS_DLL_DECL boss_feugenAI : public boss_thaddiusAddsAI +{ + boss_feugenAI(Creature* pCreature) : boss_thaddiusAddsAI(pCreature) + { + Reset(); + } + uint32 m_uiStaticFieldTimer; + //uint32 m_uiMagneticPullTimer; // TODO, missing + + void Reset() override + { + boss_thaddiusAddsAI::Reset(); + m_uiStaticFieldTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + //m_uiMagneticPullTimer = 20 * IN_MILLISECONDS; + } + + void Aggro(Unit* pWho) override + { + DoScriptText(SAY_FEUG_AGGRO, m_creature); + boss_thaddiusAddsAI::Aggro(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_FEUG_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_FEUG_SLAY, m_creature); + } + + void UpdateAddAI(const uint32 uiDiff) + { + 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); + } + else + m_uiStaticFieldTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_feugen(Creature* pCreature) +{ + return new boss_feugenAI(pCreature); +} + +void AddSC_boss_thaddius() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_thaddius"; + pNewScript->GetAI = &GetAI_boss_thaddius; + pNewScript->pEffectDummyNPC = &EffectDummyNPC_spell_thaddius_encounter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_stalagg"; + pNewScript->GetAI = &GetAI_boss_stalagg; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_feugen"; + pNewScript->GetAI = &GetAI_boss_feugen; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tesla_coil"; + pNewScript->GetAI = &GetAI_npc_tesla_coil; + pNewScript->pEffectDummyNPC = &EffectDummyNPC_spell_thaddius_encounter; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/naxxramas/instance_naxxramas.cpp b/scripts/northrend/naxxramas/instance_naxxramas.cpp index ef7a801277..578bd5a515 100644 --- a/scripts/northrend/naxxramas/instance_naxxramas.cpp +++ b/scripts/northrend/naxxramas/instance_naxxramas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,61 +24,35 @@ EndScriptData */ #include "precompiled.h" #include "naxxramas.h" -instance_naxxramas::instance_naxxramas(Map* pMap) : ScriptedInstance(pMap), - m_uiAracEyeRampGUID(0), - m_uiPlagEyeRampGUID(0), - m_uiMiliEyeRampGUID(0), - m_uiConsEyeRampGUID(0), - - m_uiAracPortalGUID(0), - m_uiPlagPortalGUID(0), - m_uiMiliPortalGUID(0), - m_uiConsPortalGUID(0), - - m_uiAnubRekhanGUID(0), - m_uiFaerlinanGUID(0), - - m_uiZeliekGUID(0), - m_uiThaneGUID(0), - m_uiBlaumeuxGUID(0), - m_uiRivendareGUID(0), - - m_uiThaddiusGUID(0), - m_uiStalaggGUID(0), - m_uiFeugenGUID(0), - - m_uiKelthuzadGUID(0), - - m_uiPathExitDoorGUID(0), - m_uiGlutExitDoorGUID(0), - m_uiThadDoorGUID(0), - - m_uiAnubDoorGUID(0), - m_uiAnubGateGUID(0), - m_uiFaerDoorGUID(0), - m_uiFaerWebGUID(0), - m_uiMaexOuterGUID(0), - m_uiMaexInnerGUID(0), - - m_uiGothikGUID(0), - m_uiGothCombatGateGUID(0), - m_uiGothikEntryDoorGUID(0), - m_uiGothikExitDoorGUID(0), - m_uiHorsemenDoorGUID(0), - m_uiHorsemenChestGUID(0), - - m_uiNothEntryDoorGUID(0), - m_uiNothExitDoorGUID(0), - m_uiHeigEntryDoorGUID(0), - m_uiHeigExitDoorGUID(0), - m_uiLoathebDoorGUID(0), - - m_uiKelthuzadDoorGUID(0), - m_uiKelthuzadExitDoorGUID(0), +static const DialogueEntry aNaxxDialogue[] = +{ + {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}, + {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_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(); } @@ -86,312 +60,435 @@ instance_naxxramas::instance_naxxramas(Map* pMap) : ScriptedInstance(pMap), void instance_naxxramas::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS; ++i) + m_abAchievCriteria[i] = false; + + 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: m_uiAnubRekhanGUID = pCreature->GetGUID(); break; - case NPC_FAERLINA: m_uiFaerlinanGUID = pCreature->GetGUID(); break; - case NPC_THADDIUS: m_uiThaddiusGUID = pCreature->GetGUID(); break; - case NPC_STALAGG: m_uiStalaggGUID = pCreature->GetGUID(); break; - case NPC_FEUGEN: m_uiFeugenGUID = pCreature->GetGUID(); break; - case NPC_ZELIEK: m_uiZeliekGUID = pCreature->GetGUID(); break; - case NPC_THANE: m_uiThaneGUID = pCreature->GetGUID(); break; - case NPC_BLAUMEUX: m_uiBlaumeuxGUID = pCreature->GetGUID(); break; - case NPC_RIVENDARE: m_uiRivendareGUID = pCreature->GetGUID(); break; - case NPC_GOTHIK: m_uiGothikGUID = pCreature->GetGUID(); break; - case NPC_KELTHUZAD: m_uiKelthuzadGUID = pCreature->GetGUID(); break; - case NPC_SUB_BOSS_TRIGGER: m_lGothTriggerList.push_back(pCreature->GetGUID()); break; + case NPC_ANUB_REKHAN: + case NPC_FAERLINA: + case NPC_THADDIUS: + case NPC_STALAGG: + case NPC_FEUGEN: + case NPC_ZELIEK: + case NPC_THANE: + 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(); + break; + + case NPC_SUB_BOSS_TRIGGER: m_lGothTriggerList.push_back(pCreature->GetObjectGuid()); break; + case NPC_TESLA_COIL: m_lThadTeslaCoilList.push_back(pCreature->GetObjectGuid()); break; } } void instance_naxxramas::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { + // Arachnid Quarter case GO_ARAC_ANUB_DOOR: - m_uiAnubDoorGUID = pGo->GetGUID(); break; case GO_ARAC_ANUB_GATE: - m_uiAnubGateGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) + if (m_auiEncounter[TYPE_ANUB_REKHAN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ARAC_FAER_WEB: - m_uiFaerWebGUID = pGo->GetGUID(); break; case GO_ARAC_FAER_DOOR: - m_uiFaerDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) + if (m_auiEncounter[TYPE_FAERLINA] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ARAC_MAEX_INNER_DOOR: - m_uiMaexInnerGUID = pGo->GetGUID(); break; case GO_ARAC_MAEX_OUTER_DOOR: - m_uiMaexOuterGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) + if (m_auiEncounter[TYPE_FAERLINA] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + // Plague Quarter case GO_PLAG_NOTH_ENTRY_DOOR: - m_uiNothEntryDoorGUID = pGo->GetGUID(); break; case GO_PLAG_NOTH_EXIT_DOOR: - m_uiNothExitDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) + if (m_auiEncounter[TYPE_NOTH] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PLAG_HEIG_ENTRY_DOOR: - m_uiHeigEntryDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) + if (m_auiEncounter[TYPE_NOTH] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PLAG_HEIG_EXIT_DOOR: - m_uiHeigExitDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[4] == DONE) + if (m_auiEncounter[TYPE_HEIGAN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PLAG_LOAT_DOOR: - m_uiLoathebDoorGUID = pGo->GetGUID(); break; + // Military Quarter case GO_MILI_GOTH_ENTRY_GATE: - m_uiGothikEntryDoorGUID = pGo->GetGUID(); break; case GO_MILI_GOTH_EXIT_GATE: - m_uiGothikExitDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[7] == DONE) + if (m_auiEncounter[TYPE_GOTHIK] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_MILI_GOTH_COMBAT_GATE: - m_uiGothCombatGateGUID = pGo->GetGUID(); break; case GO_MILI_HORSEMEN_DOOR: - m_uiHorsemenDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[7] == DONE) + if (m_auiEncounter[TYPE_GOTHIK] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_CHEST_HORSEMEN_NORM: case GO_CHEST_HORSEMEN_HERO: - m_uiHorsemenChestGUID = pGo->GetGUID(); break; + // Construct Quarter case GO_CONS_PATH_EXIT_DOOR: - m_uiPathExitDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[9] == DONE) + if (m_auiEncounter[TYPE_PATCHWERK] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_CONS_GLUT_EXIT_DOOR: - m_uiGlutExitDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[11] == DONE) + if (m_auiEncounter[TYPE_GLUTH] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_CONS_THAD_DOOR: - m_uiThadDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[11] == DONE) + if (m_auiEncounter[TYPE_GLUTH] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + case GO_CONS_NOX_TESLA_FEUGEN: + if (m_auiEncounter[TYPE_THADDIUS] == DONE) + pGo->SetGoState(GO_STATE_READY); + break; + case GO_CONS_NOX_TESLA_STALAGG: + if (m_auiEncounter[TYPE_THADDIUS] == DONE) + pGo->SetGoState(GO_STATE_READY); + break; + // Frostwyrm Lair case GO_KELTHUZAD_WATERFALL_DOOR: - m_uiKelthuzadDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[13] == DONE) + if (m_auiEncounter[TYPE_SAPPHIRON] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_KELTHUZAD_EXIT_DOOR: - m_uiKelthuzadExitDoorGUID = pGo->GetGUID(); break; + // Eyes case GO_ARAC_EYE_RAMP: - m_uiAracEyeRampGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) + case GO_ARAC_EYE_BOSS: + if (m_auiEncounter[TYPE_MAEXXNA] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PLAG_EYE_RAMP: - m_uiPlagEyeRampGUID = pGo->GetGUID(); - if (m_auiEncounter[5] == DONE) + case GO_PLAG_EYE_BOSS: + if (m_auiEncounter[TYPE_LOATHEB] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_MILI_EYE_RAMP: - m_uiMiliEyeRampGUID = pGo->GetGUID(); - if (m_auiEncounter[8] == DONE) + case GO_MILI_EYE_BOSS: + if (m_auiEncounter[TYPE_FOUR_HORSEMEN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_CONS_EYE_RAMP: - m_uiConsEyeRampGUID = pGo->GetGUID(); - if (m_auiEncounter[12] == DONE) + case GO_CONS_EYE_BOSS: + if (m_auiEncounter[TYPE_THADDIUS] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + // Portals case GO_ARAC_PORTAL: - m_uiAracPortalGUID = pGo->GetGUID(); + if (m_auiEncounter[TYPE_MAEXXNA] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; case GO_PLAG_PORTAL: - m_uiPlagPortalGUID = pGo->GetGUID(); + if (m_auiEncounter[TYPE_LOATHEB] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; case GO_MILI_PORTAL: - m_uiMiliPortalGUID = pGo->GetGUID(); + if (m_auiEncounter[TYPE_FOUR_HORSEMEN] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; case GO_CONS_PORTAL: - m_uiConsPortalGUID = pGo->GetGUID(); + if (m_auiEncounter[TYPE_THADDIUS] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; + + default: + // Heigan Traps - many different entries which are only required for sorting + if (pGo->GetGoType() == GAMEOBJECT_TYPE_TRAP) + { + uint32 uiGoEntry = pGo->GetEntry(); + + if ((uiGoEntry >= 181517 && uiGoEntry <= 181524) || uiGoEntry == 181678) + m_alHeiganTrapGuids[0].push_back(pGo->GetObjectGuid()); + else if ((uiGoEntry >= 181510 && uiGoEntry <= 181516) || (uiGoEntry >= 181525 && uiGoEntry <= 181531) || uiGoEntry == 181533 || uiGoEntry == 181676) + m_alHeiganTrapGuids[1].push_back(pGo->GetObjectGuid()); + else if ((uiGoEntry >= 181534 && uiGoEntry <= 181544) || uiGoEntry == 181532 || uiGoEntry == 181677) + m_alHeiganTrapGuids[2].push_back(pGo->GetObjectGuid()); + else if ((uiGoEntry >= 181545 && uiGoEntry <= 181552) || uiGoEntry == 181695) + m_alHeiganTrapGuids[3].push_back(pGo->GetObjectGuid()); + } + + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_naxxramas::OnPlayerDeath(Player* /*pPlayer*/) +{ + if (IsEncounterInProgress()) + SetData(TYPE_UNDYING_FAILED, DONE); + + if (GetData(TYPE_HEIGAN) == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_SAFETY_DANCE, false); +} + +void instance_naxxramas::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_MR_BIGGLESWORTH && m_auiEncounter[TYPE_KELTHUZAD] != DONE) + DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_CAT_DIED, NPC_KELTHUZAD); } bool instance_naxxramas::IsEncounterInProgress() const { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i <= TYPE_KELTHUZAD; ++i) + { if (m_auiEncounter[i] == IN_PROGRESS) return true; + } + + // Some Encounters use SPECIAL while in progress + if (m_auiEncounter[TYPE_GOTHIK] == SPECIAL) + return true; return false; } void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ANUB_REKHAN: - m_auiEncounter[0] = uiData; - DoUseDoorOrButton(m_uiAnubDoorGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_ARAC_ANUB_DOOR); if (uiData == DONE) - DoUseDoorOrButton(m_uiAnubGateGUID); + { + DoUseDoorOrButton(GO_ARAC_ANUB_GATE); + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_MAEXXNA_ID); + } break; case TYPE_FAERLINA: - m_auiEncounter[1] = uiData; - DoUseDoorOrButton(m_uiFaerWebGUID); - if (uiData == DONE) + DoUseDoorOrButton(GO_ARAC_FAER_WEB); + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_KNOCK_YOU_OUT, true); + else if (uiData == DONE) { - DoUseDoorOrButton(m_uiFaerDoorGUID); - DoUseDoorOrButton(m_uiMaexOuterGUID); + DoUseDoorOrButton(GO_ARAC_FAER_DOOR); + DoUseDoorOrButton(GO_ARAC_MAEX_OUTER_DOOR); } + m_auiEncounter[uiType] = uiData; break; case TYPE_MAEXXNA: - m_auiEncounter[2] = uiData; - DoUseDoorOrButton(m_uiMaexInnerGUID, uiData); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_ARAC_MAEX_INNER_DOOR, uiData); if (uiData == DONE) { - DoUseDoorOrButton(m_uiAracEyeRampGUID); - DoRespawnGameObject(m_uiAracPortalGUID, 30*MINUTE); - DoTaunt(); + DoUseDoorOrButton(GO_ARAC_EYE_RAMP); + DoUseDoorOrButton(GO_ARAC_EYE_BOSS); + DoRespawnGameObject(GO_ARAC_PORTAL, 30 * MINUTE); + DoToggleGameObjectFlags(GO_ARAC_PORTAL, GO_FLAG_NO_INTERACT, false); + m_uiTauntTimer = 5000; } break; case TYPE_NOTH: - m_auiEncounter[3] = uiData; - DoUseDoorOrButton(m_uiNothEntryDoorGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_PLAG_NOTH_ENTRY_DOOR); if (uiData == DONE) { - DoUseDoorOrButton(m_uiNothExitDoorGUID); - DoUseDoorOrButton(m_uiHeigEntryDoorGUID); + DoUseDoorOrButton(GO_PLAG_NOTH_EXIT_DOOR); + DoUseDoorOrButton(GO_PLAG_HEIG_ENTRY_DOOR); } break; case TYPE_HEIGAN: - m_auiEncounter[4] = uiData; - DoUseDoorOrButton(m_uiHeigEntryDoorGUID); - if (uiData == DONE) - DoUseDoorOrButton(m_uiHeigExitDoorGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_PLAG_HEIG_ENTRY_DOOR); + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_SAFETY_DANCE, true); + else if (uiData == DONE) + DoUseDoorOrButton(GO_PLAG_HEIG_EXIT_DOOR); break; case TYPE_LOATHEB: - m_auiEncounter[5] = uiData; - DoUseDoorOrButton(m_uiLoathebDoorGUID); - if (uiData == DONE) + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_PLAG_LOAT_DOOR); + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_SPORE_LOSER, true); + else if (uiData == DONE) { - DoUseDoorOrButton(m_uiPlagEyeRampGUID); - DoRespawnGameObject(m_uiPlagPortalGUID, 30*MINUTE); - DoTaunt(); + DoUseDoorOrButton(GO_PLAG_EYE_RAMP); + DoUseDoorOrButton(GO_PLAG_EYE_BOSS); + DoRespawnGameObject(GO_PLAG_PORTAL, 30 * MINUTE); + DoToggleGameObjectFlags(GO_PLAG_PORTAL, GO_FLAG_NO_INTERACT, false); + m_uiTauntTimer = 5000; } break; case TYPE_RAZUVIOUS: - m_auiEncounter[6] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_GOTHIK: - switch(uiData) + switch (uiData) { case IN_PROGRESS: - DoUseDoorOrButton(m_uiGothikEntryDoorGUID); - DoUseDoorOrButton(m_uiGothCombatGateGUID); + DoUseDoorOrButton(GO_MILI_GOTH_ENTRY_GATE); + DoUseDoorOrButton(GO_MILI_GOTH_COMBAT_GATE); break; case SPECIAL: - DoUseDoorOrButton(m_uiGothCombatGateGUID); + DoUseDoorOrButton(GO_MILI_GOTH_COMBAT_GATE); break; case FAIL: - if (m_auiEncounter[7] == IN_PROGRESS) - DoUseDoorOrButton(m_uiGothCombatGateGUID); + if (m_auiEncounter[uiType] == IN_PROGRESS) + DoUseDoorOrButton(GO_MILI_GOTH_COMBAT_GATE); - DoUseDoorOrButton(m_uiGothikEntryDoorGUID); + DoUseDoorOrButton(GO_MILI_GOTH_ENTRY_GATE); break; case DONE: - DoUseDoorOrButton(m_uiGothikEntryDoorGUID); - DoUseDoorOrButton(m_uiGothikExitDoorGUID); - DoUseDoorOrButton(m_uiHorsemenDoorGUID); + 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[7] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_FOUR_HORSEMEN: - m_auiEncounter[8] = uiData; - DoUseDoorOrButton(m_uiHorsemenDoorGUID); - 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(m_uiMiliEyeRampGUID); - DoRespawnGameObject(m_uiMiliPortalGUID, 30*MINUTE); - DoRespawnGameObject(m_uiHorsemenChestGUID, 30*MINUTE); - DoTaunt(); + DoUseDoorOrButton(GO_MILI_EYE_RAMP); + 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[9] = uiData; - if (uiData == DONE) - DoUseDoorOrButton(m_uiPathExitDoorGUID); + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_PATCHWERK_ID); + else if (uiData == DONE) + DoUseDoorOrButton(GO_CONS_PATH_EXIT_DOOR); break; case TYPE_GROBBULUS: - m_auiEncounter[10] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_GLUTH: - m_auiEncounter[11] = uiData; + m_auiEncounter[uiType] = uiData; if (uiData == DONE) { - DoUseDoorOrButton(m_uiGlutExitDoorGUID); - DoUseDoorOrButton(m_uiThadDoorGUID); + DoUseDoorOrButton(GO_CONS_GLUT_EXIT_DOOR); + DoUseDoorOrButton(GO_CONS_THAD_DOOR); } break; case TYPE_THADDIUS: - m_auiEncounter[12] = uiData; - DoUseDoorOrButton(m_uiThadDoorGUID, uiData); + // Only process real changes here + if (m_auiEncounter[uiType] == uiData) + return; + + m_auiEncounter[uiType] = uiData; + if (uiData != SPECIAL) + DoUseDoorOrButton(GO_CONS_THAD_DOOR, uiData); + // Uncomment when this achievement is implemented + // if (uiData == IN_PROGRESS) + // SetSpecialAchievementCriteria(TYPE_ACHIEV_SHOCKING, true); if (uiData == DONE) { - DoUseDoorOrButton(m_uiConsEyeRampGUID); - DoRespawnGameObject(m_uiConsPortalGUID, 30*MINUTE); - DoTaunt(); + DoUseDoorOrButton(GO_CONS_EYE_RAMP); + 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[13] = uiData; + m_auiEncounter[uiType] = uiData; + // Uncomment when achiev check implemented + // if (uiData == IN_PROGRESS) + // SetSpecialAchievementCriteria(TYPE_ACHIEV_HUNDRED_CLUB, true); if (uiData == DONE) - DoUseDoorOrButton(m_uiKelthuzadDoorGUID); + { + DoUseDoorOrButton(GO_KELTHUZAD_WATERFALL_DOOR); + m_dialogueHelper.StartNextDialogueText(NPC_KELTHUZAD); + } + // Start Sapph summoning process + if (uiData == SPECIAL) + m_uiSapphSpawnTimer = 22000; break; case TYPE_KELTHUZAD: - m_auiEncounter[14] = uiData; - DoUseDoorOrButton(m_uiKelthuzadExitDoorGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_KELTHUZAD_EXIT_DOOR); + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_GET_ENOUGH, false); + break; + case TYPE_UNDYING_FAILED: + m_auiEncounter[uiType] = 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[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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; @@ -410,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[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; @@ -423,84 +520,123 @@ 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]; + switch(uiType) { - case TYPE_ANUB_REKHAN: - return m_auiEncounter[0]; - case TYPE_FAERLINA: - return m_auiEncounter[1]; - case TYPE_MAEXXNA: - return m_auiEncounter[2]; - case TYPE_NOTH: - return m_auiEncounter[3]; - case TYPE_HEIGAN: - return m_auiEncounter[4]; - case TYPE_LOATHEB: - return m_auiEncounter[5]; - case TYPE_RAZUVIOUS: - return m_auiEncounter[6]; - case TYPE_GOTHIK: - return m_auiEncounter[7]; - case TYPE_FOUR_HORSEMEN: - return m_auiEncounter[8]; - case TYPE_PATCHWERK: - return m_auiEncounter[9]; - case TYPE_GROBBULUS: - return m_auiEncounter[10]; - case TYPE_GLUTH: - return m_auiEncounter[11]; - case TYPE_THADDIUS: - return m_auiEncounter[12]; - case TYPE_SAPPHIRON: - return m_auiEncounter[13]; - case TYPE_KELTHUZAD: - return m_auiEncounter[14]; + // Number of Heigan traps per area + case TYPE_MAX_HEIGAN_TRAPS_1: return m_avuiHeiganTraps[0].size(); + case TYPE_MAX_HEIGAN_TRAPS_2: return m_avuiHeiganTraps[1].size(); + case TYPE_MAX_HEIGAN_TRAPS_3: return m_avuiHeiganTraps[2].size(); + case TYPE_MAX_HEIGAN_TRAPS_4: return m_avuiHeiganTraps[3].size(); } return 0; } -uint64 instance_naxxramas::GetData64(uint32 uiData) +void instance_naxxramas::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < MAX_SPECIAL_ACHIEV_CRITS) + m_abAchievCriteria[uiType] = bIsMet; +} + +bool instance_naxxramas::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { - switch(uiData) + switch (uiCriteriaId) { - case NPC_ANUB_REKHAN: - return m_uiAnubRekhanGUID; - case NPC_FAERLINA: - return m_uiFaerlinanGUID; - case GO_MILI_GOTH_COMBAT_GATE: - return m_uiGothCombatGateGUID; - case NPC_ZELIEK: - return m_uiZeliekGUID; - case NPC_THANE: - return m_uiThaneGUID; - case NPC_BLAUMEUX: - return m_uiBlaumeuxGUID; - case NPC_RIVENDARE: - return m_uiRivendareGUID; - case NPC_THADDIUS: - return m_uiThaddiusGUID; - case NPC_STALAGG: - return m_uiStalaggGUID; - case NPC_FEUGEN: - return m_uiFeugenGUID; - case NPC_GOTHIK: - return m_uiGothikGUID; - case NPC_KELTHUZAD: - return m_uiKelthuzadGUID; + case ACHIEV_CRIT_SAFETY_DANCE_N: + case ACHIEV_CRIT_SAFETY_DANCE_H: + return m_abAchievCriteria[TYPE_ACHIEV_SAFETY_DANCE]; + case ACHIEV_CRIT_KNOCK_YOU_OUT_N: + case ACHIEV_CRIT_KNOCK_YOU_OUT_H: + return m_abAchievCriteria[TYPE_ACHIEV_KNOCK_YOU_OUT]; + case ACHIEV_CRIT_HUNDRED_CLUB_N: + case ACHIEV_CRIT_HUNDRED_CLUB_H: + return m_abAchievCriteria[TYPE_ACHIEV_HUNDRED_CLUB]; + case ACHIEV_CRIT_SHOCKING_N: + case ACHIEV_CRIT_SHOCKING_H: + return m_abAchievCriteria[TYPE_ACHIEV_SHOCKING]; + case ACHIEV_CRIT_SPORE_LOSER_N: + case ACHIEV_CRIT_SPORE_LOSER_H: + return m_abAchievCriteria[TYPE_ACHIEV_SPORE_LOSER]; + case ACHIEV_CRIT_GET_ENOUGH_N: + case ACHIEV_CRIT_GET_ENOUGH_H: + return m_abAchievCriteria[TYPE_ACHIEV_GET_ENOUGH]; + 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: + case ACHIEV_CRIT_IMMOORTAL_MAEX: + case ACHIEV_CRIT_IMMOORTAL_HORSE: + case ACHIEV_CRIT_UNDYING_KEL: + case ACHIEV_CRIT_UNDYING_HORSE: + case ACHIEV_CRIT_UNDYING_MAEX: + case ACHIEV_CRIT_UNDYING_LOA: + case ACHIEV_CRIT_UNDYING_THAD: + { + // First, check if all bosses are killed (except the last encounter) + uint8 uiEncounterDone = 0; + for (uint8 i = 0; i < TYPE_KELTHUZAD; ++i) + if (m_auiEncounter[i] == DONE) + ++uiEncounterDone; + + return uiEncounterDone >= 14 && GetData(TYPE_UNDYING_FAILED) != DONE; + } + default: + return false; } - return 0; +} + +void instance_naxxramas::Update(uint32 uiDiff) +{ + if (m_uiTauntTimer) + { + if (m_uiTauntTimer <= uiDiff) + { + DoTaunt(); + m_uiTauntTimer = 0; + } + else + 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); } void instance_naxxramas::SetGothTriggers() { - Creature* pGoth = instance->GetCreature(m_uiGothikGUID); + Creature* pGoth = GetSingleCreatureFromStorage(NPC_GOTHIK); if (!pGoth) return; - for(std::list::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)) { @@ -508,7 +644,7 @@ void instance_naxxramas::SetGothTriggers() pGt.bIsAnchorHigh = (pTrigger->GetPositionZ() >= (pGoth->GetPositionZ() - 5.0f)); pGt.bIsRightSide = IsInRightSideGothArea(pTrigger); - m_mGothTriggerMap[pTrigger->GetGUID()] = pGt; + m_mGothTriggerMap[pTrigger->GetObjectGuid()] = pGt; } } } @@ -517,7 +653,7 @@ Creature* instance_naxxramas::GetClosestAnchorForGoth(Creature* pSource, bool bR { std::list lList; - for (UNORDERED_MAP::iterator itr = m_mGothTriggerMap.begin(); itr != m_mGothTriggerMap.end(); ++itr) + for (UNORDERED_MAP::iterator itr = m_mGothTriggerMap.begin(); itr != m_mGothTriggerMap.end(); ++itr) { if (!itr->second.bIsAnchorHigh) continue; @@ -538,9 +674,9 @@ 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) + for (UNORDERED_MAP::iterator itr = m_mGothTriggerMap.begin(); itr != m_mGothTriggerMap.end(); ++itr) { if (itr->second.bIsAnchorHigh) continue; @@ -553,15 +689,28 @@ void instance_naxxramas::GetGothSummonPointCreatures(std::list &lList } } +// Right is right side from gothik (eastern) bool instance_naxxramas::IsInRightSideGothArea(Unit* pUnit) { - if (GameObject* pCombatGate = instance->GetGameObject(m_uiGothCombatGateGUID)) + 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; } +void instance_naxxramas::DoTriggerHeiganTraps(Creature* pHeigan, uint32 uiAreaIndex) +{ + if (uiAreaIndex >= MAX_HEIGAN_TRAP_AREAS) + return; + + for (GuidList::const_iterator itr = m_alHeiganTrapGuids[uiAreaIndex].begin(); itr != m_alHeiganTrapGuids[uiAreaIndex].end(); ++itr) + { + if (GameObject* pTrap = instance->GetGameObject(*itr)) + pTrap->Use(pHeigan); + } +} + void instance_naxxramas::SetChamberCenterCoords(float fX, float fY, float fZ) { m_fChamberCenterX = fX; @@ -571,30 +720,28 @@ void instance_naxxramas::SetChamberCenterCoords(float fX, float fY, float fZ) void instance_naxxramas::DoTaunt() { - Creature* pKelThuzad = instance->GetCreature(m_uiKelthuzadGUID); - - if (pKelThuzad && pKelThuzad->isAlive()) + if (m_auiEncounter[TYPE_KELTHUZAD] != DONE) { uint8 uiWingsCleared = 0; - if (m_auiEncounter[2] == DONE) + if (m_auiEncounter[TYPE_MAEXXNA] == DONE) ++uiWingsCleared; - if (m_auiEncounter[5] == DONE) + if (m_auiEncounter[TYPE_LOATHEB] == DONE) ++uiWingsCleared; - if (m_auiEncounter[8] == DONE) + if (m_auiEncounter[TYPE_FOUR_HORSEMEN] == DONE) ++uiWingsCleared; - if (m_auiEncounter[12] == DONE) + if (m_auiEncounter[TYPE_THADDIUS] == DONE) ++uiWingsCleared; - switch(uiWingsCleared) + switch (uiWingsCleared) { - case 1: DoScriptText(SAY_KELTHUZAD_TAUNT1, pKelThuzad); break; - case 2: DoScriptText(SAY_KELTHUZAD_TAUNT2, pKelThuzad); break; - case 3: DoScriptText(SAY_KELTHUZAD_TAUNT3, pKelThuzad); break; - case 4: DoScriptText(SAY_KELTHUZAD_TAUNT4, pKelThuzad); break; + case 1: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT1, NPC_KELTHUZAD); break; + case 2: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT2, NPC_KELTHUZAD); break; + case 3: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT3, NPC_KELTHUZAD); break; + case 4: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT4, NPC_KELTHUZAD); break; } } } @@ -608,7 +755,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(); @@ -620,7 +767,7 @@ bool AreaTrigger_at_naxxramas(Player* pPlayer, AreaTriggerEntry const* pAt) if (pInstance->GetData(TYPE_KELTHUZAD) == NOT_STARTED) { - if (Creature* pKelthuzad = pInstance->instance->GetCreature(pInstance->GetData64(NPC_KELTHUZAD))) + if (Creature* pKelthuzad = pInstance->GetSingleCreatureFromStorage(NPC_KELTHUZAD)) { if (pKelthuzad->isAlive()) { @@ -631,6 +778,21 @@ bool AreaTrigger_at_naxxramas(Player* pPlayer, AreaTriggerEntry const* pAt) } } + if (pAt->id == AREATRIGGER_THADDIUS_DOOR) + { + if (instance_naxxramas* pInstance = (instance_naxxramas*)pPlayer->GetInstanceData()) + { + if (pInstance->GetData(TYPE_THADDIUS) == NOT_STARTED) + { + if (Creature* pThaddius = pInstance->GetSingleCreatureFromStorage(NPC_THADDIUS)) + { + pInstance->SetData(TYPE_THADDIUS, SPECIAL); + DoScriptText(SAY_THADDIUS_GREET, pThaddius); + } + } + } + } + return false; } diff --git a/scripts/northrend/naxxramas/naxxramas.h b/scripts/northrend/naxxramas/naxxramas.h index 933279a757..58ebde31f4 100644 --- a/scripts/northrend/naxxramas/naxxramas.h +++ b/scripts/northrend/naxxramas/naxxramas.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,35 +7,76 @@ enum { - MAX_ENCOUNTER = 15, + MAX_ENCOUNTER = 16, + // A few instance-script related texts + SAY_THADDIUS_GREET = -1533029, + + // Kel'Thuzad + SAY_KELTHUZAD_CAT_DIED = -1533089, // Kel'Thuzad's taunts after killing Wing Bosses SAY_KELTHUZAD_TAUNT1 = -1533090, SAY_KELTHUZAD_TAUNT2 = -1533091, SAY_KELTHUZAD_TAUNT3 = -1533092, SAY_KELTHUZAD_TAUNT4 = -1533093, - - TYPE_ANUB_REKHAN = 1, - TYPE_FAERLINA = 2, - TYPE_MAEXXNA = 3, - - TYPE_NOTH = 4, - TYPE_HEIGAN = 5, - TYPE_LOATHEB = 6, - - TYPE_RAZUVIOUS = 7, - TYPE_GOTHIK = 8, - TYPE_FOUR_HORSEMEN = 9, - - TYPE_PATCHWERK = 10, - TYPE_GROBBULUS = 11, - TYPE_GLUTH = 12, - TYPE_THADDIUS = 13, - TYPE_STALAGG = 14, - TYPE_FEUGEN = 15, - - TYPE_SAPPHIRON = 16, - TYPE_KELTHUZAD = 17, + // Dialogues with Lich King + SAY_SAPP_DIALOG1 = -1533084, + SAY_SAPP_DIALOG2_LICH = -1533085, + 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, + TYPE_MAEXXNA = 2, + + TYPE_NOTH = 3, + TYPE_HEIGAN = 4, + TYPE_LOATHEB = 5, + + TYPE_RAZUVIOUS = 6, + TYPE_GOTHIK = 7, + TYPE_FOUR_HORSEMEN = 8, + + TYPE_PATCHWERK = 9, + TYPE_GROBBULUS = 10, + TYPE_GLUTH = 11, + TYPE_THADDIUS = 12, + + TYPE_SAPPHIRON = 13, + TYPE_KELTHUZAD = 14, + + TYPE_UNDYING_FAILED = 15, // Achievements Undying and Immortal, needs to be saved to database + + TYPE_MAX_HEIGAN_TRAPS_1 = 18, + TYPE_MAX_HEIGAN_TRAPS_2 = 19, + TYPE_MAX_HEIGAN_TRAPS_3 = 20, + TYPE_MAX_HEIGAN_TRAPS_4 = 21, + + MAX_SPECIAL_ACHIEV_CRITS = 7, + + TYPE_ACHIEV_SAFETY_DANCE = 0, + TYPE_ACHIEV_KNOCK_YOU_OUT = 1, + TYPE_ACHIEV_HUNDRED_CLUB = 2, + TYPE_ACHIEV_AND_THEY = 3, + TYPE_ACHIEV_SHOCKING = 4, + TYPE_ACHIEV_SPORE_LOSER = 5, + TYPE_ACHIEV_GET_ENOUGH = 6, + + MAX_HEIGAN_TRAP_AREAS = 4, NPC_ANUB_REKHAN = 15956, NPC_FAERLINA = 15953, @@ -43,61 +84,67 @@ enum NPC_THADDIUS = 15928, NPC_STALAGG = 15929, NPC_FEUGEN = 15930, + NPC_TESLA_COIL = 16218, NPC_ZELIEK = 16063, NPC_THANE = 16064, 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, NPC_SPECT_TRAINEE = 16127, - NPC_SPECT_DEATH_KNIGTH = 16148, + NPC_SPECT_DEATH_KNIGHT = 16148, NPC_SPECT_RIDER = 16150, NPC_SPECT_HORSE = 16149, - // End boss adds + // Kel'Thuzad NPC_SOLDIER_FROZEN = 16427, NPC_UNSTOPPABLE_ABOM = 16428, NPC_SOUL_WEAVER = 16429, 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 GO_CONS_PATH_EXIT_DOOR = 181123, GO_CONS_GLUT_EXIT_DOOR = 181120, GO_CONS_THAD_DOOR = 181121, // Thaddius enc door + GO_CONS_NOX_TESLA_FEUGEN = 181477, + GO_CONS_NOX_TESLA_STALAGG = 181478, // Frostwyrm Lair GO_KELTHUZAD_WATERFALL_DOOR = 181225, // exit, open after sapphiron is dead @@ -109,15 +156,56 @@ 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, GO_MILI_PORTAL = 181578, GO_CONS_PORTAL = 181576, - AREATRIGGER_FROSTWYRM = 4120, //not needed here, but AT to be scripted + AREATRIGGER_FROSTWYRM = 4120, // not needed here, but AT to be scripted AREATRIGGER_KELTHUZAD = 4112, - AREATRIGGER_GOTHIK = 4116 + AREATRIGGER_GOTHIK = 4116, + AREATRIGGER_THADDIUS_DOOR = 4113, + + // Achievement related + ACHIEV_CRIT_SAFETY_DANCE_N = 7264, // Heigan, achievs 1996, 2139 + ACHIEV_CRIT_SAFETY_DANCE_H = 7548, + ACHIEV_CRIT_KNOCK_YOU_OUT_N = 7265, // Faerlina, achievs 1997, 2140 + 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 + ACHIEV_CRIT_SPORE_LOSER_H = 7613, + ACHIEV_CRIT_GET_ENOUGH_N = 7614, // Kel'Thuzad, achievs 2184, 2185 + ACHIEV_CRIT_GET_ENOUGH_H = 7615, + + // 'The Immortal'(25m) or 'Undying'(10m) - (achievs 2186, 2187) + ACHIEV_CRIT_IMMORTAL_KEL = 7616, + ACHIEV_CRIT_IMMOORTAL_LOA = 13236, + ACHIEV_CRIT_IMMOORTAL_THAD = 13235, + ACHIEV_CRIT_IMMOORTAL_MAEX = 13234, + ACHIEV_CRIT_IMMOORTAL_HORSE = 13233, + ACHIEV_CRIT_UNDYING_KEL = 7617, + ACHIEV_CRIT_UNDYING_HORSE = 13237, + ACHIEV_CRIT_UNDYING_MAEX = 13238, + ACHIEV_CRIT_UNDYING_LOA = 13239, + ACHIEV_CRIT_UNDYING_THAD = 13240, + + // Timed achievement criterias + ACHIEV_START_PATCHWERK_ID = 10286, + ACHIEV_START_MAEXXNA_ID = 9891, + + // Achievement Spells + ACHIEV_SPELL_FOUR_HORSEMEN = 59450, }; struct GothTrigger @@ -126,98 +214,79 @@ struct GothTrigger bool bIsAnchorHigh; }; +static const float aSapphPositions[4] = {3521.48f, -5234.87f, 137.626f, 4.53329f}; + class MANGOS_DLL_DECL instance_naxxramas : public ScriptedInstance { public: instance_naxxramas(Map* pMap); ~instance_naxxramas() {} - void Initialize(); + void Initialize() override; + + bool IsEncounterInProgress() const override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - bool IsEncounterInProgress() const; + void OnPlayerDeath(Player* pPlayer) 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); - uint64 GetData64(uint32 uiData); + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return 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; + + // Heigan + void DoTriggerHeiganTraps(Creature* pHeigan, uint32 uiAreaIndex); // 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); + // Heigan + uint64 GetHeiganTrapData64(uint8 uiAreaIndex, uint32 uiIndex); + + // thaddius + 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: uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiAracEyeRampGUID; - uint64 m_uiPlagEyeRampGUID; - uint64 m_uiMiliEyeRampGUID; - uint64 m_uiConsEyeRampGUID; - - uint64 m_uiAracPortalGUID; - uint64 m_uiPlagPortalGUID; - uint64 m_uiMiliPortalGUID; - uint64 m_uiConsPortalGUID; - - uint64 m_uiAnubRekhanGUID; - uint64 m_uiFaerlinanGUID; - - uint64 m_uiZeliekGUID; - uint64 m_uiThaneGUID; - uint64 m_uiBlaumeuxGUID; - uint64 m_uiRivendareGUID; - - uint64 m_uiThaddiusGUID; - uint64 m_uiStalaggGUID; - uint64 m_uiFeugenGUID; - - uint64 m_uiKelthuzadGUID; - - uint64 m_uiPathExitDoorGUID; - uint64 m_uiGlutExitDoorGUID; - uint64 m_uiThadDoorGUID; - - uint64 m_uiAnubDoorGUID; - uint64 m_uiAnubGateGUID; - uint64 m_uiFaerDoorGUID; - uint64 m_uiFaerWebGUID; - uint64 m_uiMaexOuterGUID; - uint64 m_uiMaexInnerGUID; - - uint64 m_uiGothikGUID; - uint64 m_uiGothCombatGateGUID; - uint64 m_uiGothikEntryDoorGUID; - uint64 m_uiGothikExitDoorGUID; - std::list m_lGothTriggerList; - UNORDERED_MAP m_mGothTriggerMap; - - uint64 m_uiHorsemenDoorGUID; - uint64 m_uiHorsemenChestGUID; - - uint64 m_uiNothEntryDoorGUID; - uint64 m_uiNothExitDoorGUID; - uint64 m_uiHeigEntryDoorGUID; - uint64 m_uiHeigExitDoorGUID; - uint64 m_uiLoathebDoorGUID; - - uint64 m_uiKelthuzadDoorGUID; - uint64 m_uiKelthuzadExitDoorGUID; + bool m_abAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; + std::string m_strInstData; + + GuidList m_lThadTeslaCoilList; + GuidList m_lGothTriggerList; + + UNORDERED_MAP m_mGothTriggerMap; + GuidList m_alHeiganTrapGuids[MAX_HEIGAN_TRAP_AREAS]; + + std::vector m_avuiHeiganTraps[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; }; #endif diff --git a/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp b/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp new file mode 100644 index 0000000000..cf7590f2ed --- /dev/null +++ b/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp @@ -0,0 +1,1436 @@ +/* Copyright (C) 2006 - 2013 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_Malygos +SD%Complete: 98% +SDComment: +Some Vehicle-Core problems with need improvments: + Hover Disks are unsummon, if player leave it + Dragon spell handling. Healing other player is a little bit strange +Possible improvements: + Make a entry in vehicle_accessory for hover disk 30234 and 30248 with passengers Nexus Lord and Scion of Eternity +Other things: + Remove spell_dbc hack for spell 56046 +SDAuthor: Reamer + Tasssadar + PSZ + some corrections from MaxXx2021 and /dev/rsa +SDCategory: Nexus, Eye of Eternity +EndScriptData */ + +#include "precompiled.h" +#include "eye_of_eternity.h" +#include "Vehicle.h" + +enum +{ + // ******************************** SPELLS ******************************** // + SPELL_BERSERK = 64238, + + //////////////// PHASE 0 //////////////// + SPELL_PORTAL_BEAM = 56046, + SPELL_PORTAL_OPEN = 61236, // not used + SPELL_PORTAL_CLOSE = 55949, // not used + + //////////////// PHASE 1 //////////////// + SPELL_ARCANE_BREATH = 56272, + SPELL_ARCANE_BREATH_H = 60072, + SPELL_ARCANE_STORM = 61693, + SPELL_ARCANE_STORM_H = 61694, + SPELL_POWER_SPARK_MAIN_SUMMON = 56140, // limit to one target in spell.cpp and spell_script_target with target 30118 + SPELL_POWER_SPARK_SUMMON = 56142, + SPELL_POWER_SPARK = 56152, // if spark reach malygos then buff him + SPELL_POWER_SPARK_PLAYERS = 55852, // if spark is killed - buff players in area + SPELL_POWER_SPARK_VISUAL = 55845, + + SPELL_VORTEX_SPAWN = 59670, // visual spawn effect for vortex + SPELL_VORTEX = 56105, + SPELL_VORTEX_CHANNEL = 56237, // Malygos Channel Effect + + //////////////// PHASE 2 //////////////// + SPELL_ARCANE_BOMB_SUMMON = 56429, // target with spell_script_target-table to trigger npc 22517 + SPELL_ARCANE_BOMB_MISSILE = 56430, + SPELL_ARCANE_BOMB_DAMAGE = 56431, // cast by arcane overload + SPELL_ARCANE_OVERLOAD = 56432, // cast this on arcane overload NPCs + SPELL_SURGE_OF_POWER_BREATH = 56505, // omfg, they say deep breath, but its this! + + //NPCs spells + SPELL_ARCANE_SHOCK = 57058, + SPELL_ARCANE_SHOCK_H = 60073, + SPELL_HASTE = 57060, + SPELL_ARCANE_BARRAGE = 50804, // hack, right spell is 56397 + + //////////////// PHASE 3 //////////////// + SPELL_STATIC_FIELD_MISSILE = 57430, // TODO: maybe limit to 1 in spell.cpp + SPELL_STATIC_FIELD = 57428, + SPELL_SURGE_OF_POWER = 57407, // this is on one target + SPELL_SURGE_OF_POWER_H = 60936, // this is on unlimited tagets, must limit it in mangos + SPELL_ARCANE_PULSE = 57432, + + SPELL_ALEXSTRASZAS_GIFT_BEAM = 61028, + SPELL_ALEXSTRASZAS_GIFT_VISUAL = 61023, + + SPELL_CALL_SKYTALON = 58846, + SPELL_RIDE_RED_DRAGON_BUDDY = 56071, + + SAY_INTRO1 = -1616000, + SAY_INTRO2 = -1616001, + SAY_INTRO3 = -1616002, + SAY_INTRO4 = -1616003, + SAY_INTRO5 = -1616004, + SAY_INTRO_PHASE3 = -1616018, + SAY_AGGRO1 = -1616005, + SAY_AGGRO2 = -1616013, + SAY_AGGRO3 = -1616019, + SAY_VORTEX = -1616006, + SAY_POWER_SPARK = -1616035, + SAY_POWER_SPARK_BUFF = -1616007, + SAY_KILL1_1 = -1616008, + SAY_KILL1_2 = -1616009, + SAY_KILL1_3 = -1616010, + SAY_KILL2_1 = -1616020, + SAY_KILL2_2 = -1616021, + SAY_KILL2_3 = -1616022, + SAY_KILL3_1 = -1616023, + SAY_KILL3_2 = -1616024, + SAY_KILL3_3 = -1616025, + SAY_END_PHASE1 = -1616012, + SAY_END_PHASE2 = -1616017, + SAY_ARCANE_PULSE = -1616014, + SAY_ARCANE_PULSE_WARN = -1616015, + SAY_ARCANE_OVERLOAD = -1616016, + SAY_SURGE_OF_POWER = -1616026, + SAY_CAST_SPELL1 = -1616027, + SAY_CAST_SPELL2 = -1616028, + SAY_CAST_SPELL3 = -1616029, + SAY_DEATH = -1616030, + // Alexstrasza + SAY_OUTRO1 = -1616031, + SAY_OUTRO2 = -1616032, + SAY_OUTRO3 = -1616033, + SAY_OUTRO4 = -1616034, + + PLATFORM_MIN_X = 722, + PLATFORM_MAX_X = 768, + PLATFORM_MIN_Y = 1290, + PLATFORM_MAX_Y = 1339, + + NEXUS_LORD_COUNT = 2, + NEXUS_LORD_COUNT_H = 4, + SCION_OF_ETERNITY_COUNT = 4, + SCION_OF_ETERNITY_COUNT_H = 8, + + POINT_ID_WAYPOINT = 1, + POINT_ID_LAND = 2, + POINT_ID_VORTEX_AIR = 3, + POINT_ID_PHASE_2_WP = 4, + POINT_ID_DEEP_BREATH = 5, + + //hacks + SPELL_FLIGHT = 59553, + MODEL_ID_INVISIBLE = 11686 +}; + +enum MalygosPhase +{ + PHASE_INTRO = 0, + SUBPHASE_INTRO = 0, + PHASE_FLOOR = 1, + SUBPHASE_NOT_VORTEX = 10, + SUBPHASE_VORTEX = 11, + PHASE_ADDS = 2, + SUBPHASE_NOT_DEEP_BREATH = 20, // maybe better name SUBPHASE_NOT_SURGE_OF_POWER + SUBPHASE_FLY = 21, + SUBPHASE_DEEP_BREATH = 22, // maybe better name SUBPHASE_SURGE_OF_POWER + PHASE_DRAGONS = 3, + SUBPHASE_NOT_SURGE_OF_POWER = 30, + SUBPHASE_DESTROY_PLATFORM_1 = 31, + SUBPHASE_DESTROY_PLATFORM_2 = 32, + SUBPHASE_DESTROY_PLATFORM_3 = 33, + SUBPHASE_DESTROY_PLATFORM_4 = 34, + SUBPHASE_SURGE_OF_POWER = 35, + +}; + +static LOCATION WPs[]= +{ + // Z coord not used + {810.0f, 1248.0f, 0.0f}, + {810.0f, 1358.0f, 0.0f}, + {700.0f, 1358.0f, 0.0f}, + {700.0f, 1248.0f, 0.0f}, +}; + +#define CENTER_X 754.50f +#define CENTER_Y 1301.76f +#define FLOOR_Z 266.17f +#define AIR_Z 296.17f + +/*###### +## boss_malygos +######*/ + +struct MANGOS_DLL_DECL boss_malygosAI : public ScriptedAI +{ + boss_malygosAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_eye_of_eternity*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_eye_of_eternity* m_pInstance; + bool m_bIsRegularMode; + + MalygosPhase m_Phase; + MalygosPhase m_SubPhase; + + uint8 m_uiSpeechCount; + uint32 m_uiSpeechTimer; + + uint32 m_uiTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiVortexTimer; + uint32 m_uiVortexStep; + uint32 m_uiArcaneBreathTimer; + uint32 m_uiPowerSparkTimer; + uint32 m_uiDeepBreathTimer; + uint32 m_uiShellTimer; + uint32 m_uiArcaneStormTimer; + uint32 m_uiStaticFieldTimer; + uint32 m_uiArcanePulseTimer; + uint32 m_uiSurgeOfPowerTimer; + uint32 m_uiCheckTimer; + uint32 m_uiMovingSteps; + + uint8 m_uiWP; + uint8 m_uiAddDieCounter; + + bool m_bReadyForWPMove; + + void Reset() + { + m_uiMovingSteps = 0; + m_bReadyForWPMove = true; + m_Phase = PHASE_INTRO; + m_SubPhase = SUBPHASE_INTRO; + m_uiTimer = 0; + m_uiEnrageTimer = 600000; + m_uiArcaneBreathTimer = urand(13000, 16000); + m_uiArcaneStormTimer = urand(10000, 15000); + m_uiVortexTimer = 60000; + m_uiVortexStep = 0; + m_uiPowerSparkTimer = urand(20000, 30000); + m_uiDeepBreathTimer = 65000; + m_uiShellTimer = 0; + m_uiStaticFieldTimer = 10000; + m_uiArcanePulseTimer = 1000; + m_uiSurgeOfPowerTimer = 8000; + m_uiCheckTimer = 1000; + + m_uiWP = 0; + m_uiAddDieCounter = 0; + m_uiSpeechCount = 0; + m_uiSpeechTimer = 15000; + m_creature->SetSpeedRate(MOVE_RUN, 2.85714f); + m_creature->SetSpeedRate(MOVE_WALK, 6.0f); + m_creature->SetSpeedRate(MOVE_FLIGHT, 2.0f); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + MakeBossFlight(); + m_creature->GetMotionMaster()->Clear(); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALYGOS, NOT_STARTED); + } + + void MakeBossFlight() + { + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->SetLevitate(true); + } + + void MakeBossWalk() + { + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); + m_creature->SetLevitate(false); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO1, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALYGOS, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + m_creature->SummonCreature(NPC_ALEXSTRASZA, CENTER_X+20.0f, CENTER_Y+20.0f, AIR_Z, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->GetMap()->CreatureRelocation(m_creature, m_creature->GetPositionX(), m_creature->GetPositionY(), FLOOR_Z-500.0f, 0); + m_creature->MonsterMoveWithSpeed(m_creature->GetPositionX(), m_creature->GetPositionY(), FLOOR_Z-400.0f, 26); + } + + void KilledUnit(Unit* pVictim) override + { + uint8 uiText = 0; + switch (m_Phase) + { + case PHASE_FLOOR: uiText = urand(0, 2); break; + case PHASE_ADDS: uiText = urand(3, 5); break; + case PHASE_DRAGONS: uiText = urand(6, 8); break; + default: + break; + } + switch (uiText) + { + case 0: DoScriptText(SAY_KILL1_1, m_creature); break; + case 1: DoScriptText(SAY_KILL1_2, m_creature); break; + case 2: DoScriptText(SAY_KILL1_3, m_creature); break; + case 3: DoScriptText(SAY_KILL2_1, m_creature); break; + case 4: DoScriptText(SAY_KILL2_2, m_creature); break; + case 5: DoScriptText(SAY_KILL2_3, m_creature); break; + case 6: DoScriptText(SAY_KILL3_1, m_creature); break; + case 7: DoScriptText(SAY_KILL3_2, m_creature); break; + case 8: DoScriptText(SAY_KILL3_3, m_creature); break; + default: + break; + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + switch (pSpell->Id) + { + case SPELL_POWER_SPARK: + DoScriptText(SAY_POWER_SPARK_BUFF, m_creature); + break; + default: + break; + } + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + switch (pSpell->Id) + { + case SPELL_ARCANE_BOMB_MISSILE: + { + if (pTarget->GetEntry() == NPC_ARCANE_OVERLOAD) + { + pTarget->CastSpell(pTarget, SPELL_ARCANE_BOMB_DAMAGE, false); + pTarget->CastSpell(pTarget, SPELL_ARCANE_OVERLOAD, false); + ((Creature*)pTarget)->ForcedDespawn(45000); + } + break; + } + case SPELL_VORTEX: + { + m_pInstance->HandleRiderOfVortex(pTarget); + break; + } + default: + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_STATIC_FIELD: + { + pSummoned->CastSpell(m_creature, SPELL_STATIC_FIELD, false, 0, 0, m_creature->GetObjectGuid()); + pSummoned->ForcedDespawn(30000); + pSummoned->SetDisplayId(MODEL_ID_INVISIBLE); + break; + } + case NPC_NEXUS_LORD: + { + if (Creature* pDisk = pSummoned->SummonCreature(NPC_HOVER_DISK_MELEE, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + pDisk->SetLevitate(true); + pDisk->CastSpell(pDisk, SPELL_FLIGHT, true); + if (VehicleKitPtr pDiskVehicle = pDisk->GetVehicleKit()) + pSummoned->EnterVehicle(pDiskVehicle, 0); + } + pSummoned->SetInCombatWithZone(); + break; + } + case NPC_SCION_OF_ETERNITY: + { + if (Creature* pDisk = pSummoned->SummonCreature(NPC_HOVER_DISK_CASTER, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + pDisk->SetLevitate(true); + pDisk->CastSpell(pDisk, SPELL_FLIGHT, true); + if (VehicleKitPtr pDiskVehicle = pDisk->GetVehicleKit()) + pSummoned->EnterVehicle(pDiskVehicle, 0); + } + pSummoned->SetInCombatWithZone(); + break; + } + case NPC_POWER_SPARK: + { + // maybe some functions + break; + } + case NPC_ARCANE_OVERLOAD: + { + DoCast(pSummoned, SPELL_ARCANE_BOMB_MISSILE, true); + break; + } + default: + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) + { + switch (pSummoned->GetEntry()) + { + case NPC_NEXUS_LORD: + case NPC_SCION_OF_ETERNITY: + { + ++m_uiAddDieCounter; + break; + } + default: + break; + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + switch(uiPointId) + { + case POINT_ID_WAYPOINT: + { + if (Creature* pSparkPortal = GetClosestCreatureWithEntry(m_creature, NPC_SPARK_PORTAL, 100.0f)) + { + m_creature->SetFacingToObject(pSparkPortal); + DoCast(pSparkPortal, SPELL_PORTAL_BEAM, true); + } + m_bReadyForWPMove = true; + m_uiTimer = 15000; + break; + } + case POINT_ID_LAND: + { + MakeBossWalk(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_Phase = PHASE_FLOOR; + m_SubPhase = SUBPHASE_NOT_VORTEX; + m_creature->SetInCombatWithZone(); + if (Unit* pTarget = m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(pTarget); + break; + } + case POINT_ID_VORTEX_AIR: + { + m_pInstance->ActivateVisualOfVortex(); + DoCast(m_creature, SPELL_VORTEX); + DoCast(m_creature, SPELL_VORTEX_CHANNEL); + m_uiVortexTimer = 10 * IN_MILLISECONDS; + m_uiVortexStep = 1; + break; + } + case POINT_ID_PHASE_2_WP: + { + if (m_Phase == PHASE_ADDS) + { + m_bReadyForWPMove = true; + m_uiTimer = 0; + if (m_SubPhase == SUBPHASE_FLY) + { + DoScriptText(SAY_AGGRO2, m_creature); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiShellTimer = urand(2000, 3000); + m_SubPhase = SUBPHASE_NOT_DEEP_BREATH; + for (uint8 i = 0; i < (m_bIsRegularMode ? NEXUS_LORD_COUNT : NEXUS_LORD_COUNT_H); ++i) + m_creature->SummonCreature(NPC_NEXUS_LORD, urand(PLATFORM_MIN_X, PLATFORM_MAX_X), urand(PLATFORM_MIN_Y, PLATFORM_MAX_Y), FLOOR_Z+10.0f+urand(0, 15), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + for (uint8 i = 0; i < (m_bIsRegularMode ? SCION_OF_ETERNITY_COUNT : SCION_OF_ETERNITY_COUNT_H); ++i) + m_creature->SummonCreature(NPC_SCION_OF_ETERNITY, urand(PLATFORM_MIN_X, PLATFORM_MAX_X), urand(PLATFORM_MIN_Y, PLATFORM_MAX_Y), FLOOR_Z+10.0f+urand(0, 15), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_uiTimer = 5000; + } + } + break; + } + case POINT_ID_DEEP_BREATH: + { + if (m_Phase == PHASE_ADDS) + { + DoScriptText(SAY_ARCANE_PULSE, m_creature); + DoScriptText(SAY_ARCANE_PULSE_WARN, m_creature); + DoCast(m_creature, SPELL_SURGE_OF_POWER_BREATH); + m_uiShellTimer = urand(2000, 4000); + m_SubPhase = SUBPHASE_NOT_DEEP_BREATH; + m_bReadyForWPMove = true; + m_uiTimer = 10000; + } + break; + } + default: + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_Phase != PHASE_INTRO) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEnrageTimer <= uiDiff) + { + SetCombatMovement(true); + DoCast(m_creature, SPELL_BERSERK, true); + m_uiEnrageTimer = 600000; + m_creature->GetMotionMaster()->Clear(false, true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + else + m_uiEnrageTimer -= uiDiff; + } + + switch (m_Phase) + { + case PHASE_INTRO: + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) + { + if (m_bReadyForWPMove) + { + if (m_uiTimer <= uiDiff) + { + if (m_pInstance->GetData(TYPE_MALYGOS) == IN_PROGRESS) // variable set with gameobject focusing iris Script + { + float fAng = m_creature->GetAngle(CENTER_X, CENTER_Y); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_LAND, CENTER_X-40.76f*cos(fAng), CENTER_Y-40.76f*sin(fAng), FLOOR_Z+7.0f); + } + else + { + m_creature->GetMotionMaster()->MovePoint(POINT_ID_WAYPOINT, WPs[m_uiWP].x, WPs[m_uiWP].y, AIR_Z); + } + m_bReadyForWPMove = false; + ++m_uiWP; + if (m_uiWP == 4) + m_uiWP = 0; + } + else + m_uiTimer -= uiDiff; + } + + if (m_uiSpeechTimer <= uiDiff) + { + switch(m_uiSpeechCount) + { + case 0: + { + DoScriptText(SAY_INTRO1, m_creature); + m_uiSpeechTimer = 22000; + break; + } + case 1: + { + DoScriptText(SAY_INTRO2, m_creature); + m_uiSpeechTimer = 24000; + break; + } + case 2: + { + DoScriptText(SAY_INTRO3, m_creature); + m_uiSpeechTimer = 26000; + break; + } + case 3: + { + DoScriptText(SAY_INTRO4, m_creature); + m_uiSpeechTimer = 23000; + break; + } + case 4: + { + DoScriptText(SAY_INTRO5, m_creature); + m_uiSpeechTimer = 120000; + break; + } + } + ++m_uiSpeechCount; + if (m_uiSpeechCount == 5) + m_uiSpeechCount = 0; + } + else + m_uiSpeechTimer -= uiDiff; + } + break; + case PHASE_FLOOR: + { + switch (m_SubPhase) + { + case SUBPHASE_VORTEX: + { + if (m_uiVortexTimer < uiDiff) + { + switch (m_uiVortexStep) + { + case 0: // fly - should never appear, but maybe a fly point never reached + m_creature->MonsterSay("Fly time is to short", LANG_UNIVERSAL); + m_uiVortexTimer = 500; + break; + case 1: // remove Aura + m_creature->RemoveAurasDueToSpell(SPELL_VORTEX_CHANNEL); + m_uiVortexTimer = 500; + break; + case 2: // land + MakeBossWalk(); + m_uiVortexTimer = 500; + break; + case 3: // end + m_SubPhase = SUBPHASE_NOT_VORTEX; + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true); + if (Unit* pTarget = m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(pTarget); + m_uiVortexTimer = 50 * IN_MILLISECONDS; + m_uiPowerSparkTimer = urand(2000, 5000); + break; + default: + m_creature->MonsterSay("Unknow VortexStep", LANG_UNIVERSAL); + break; + + } + ++m_uiVortexStep; + } + else + m_uiVortexTimer -= uiDiff; + + break; + } + case SUBPHASE_NOT_VORTEX: + { + 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_uiArcaneStormTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_STORM : SPELL_ARCANE_STORM_H) == CAST_OK) + m_uiArcaneStormTimer = urand(10000, 15000); + } + else + m_uiArcaneStormTimer -= uiDiff; + + if (m_uiPowerSparkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POWER_SPARK_MAIN_SUMMON) == CAST_OK) + { + m_uiPowerSparkTimer = urand(20000, 30000); + DoScriptText(SAY_POWER_SPARK, m_creature); + } + } + else + m_uiPowerSparkTimer -= uiDiff; + + if (m_uiVortexTimer <= uiDiff) + { + MakeBossFlight(); + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_VORTEX_AIR, CENTER_X, CENTER_Y, AIR_Z); + m_SubPhase = SUBPHASE_VORTEX; + m_uiVortexStep = 0; + m_uiVortexTimer = 5000; + DoScriptText(SAY_VORTEX, m_creature); + return; + } + else + m_uiVortexTimer -= uiDiff; + + // switch to next Phase (Add Phase) + if (m_creature->GetHealthPercent() <= 50.0f) + { + DoScriptText(SAY_END_PHASE1, m_creature); + m_Phase = PHASE_ADDS; + m_SubPhase = SUBPHASE_FLY ; + MakeBossFlight(); + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, AIR_Z); + m_bReadyForWPMove = false; + m_uiTimer = 23000; + return; + } + + DoMeleeAttackIfReady(); + break; + } + default: + m_creature->MonsterSay("Unknown SubPhase in Floor Phase", LANG_UNIVERSAL); + } + break; + } + case PHASE_ADDS: + { + switch (m_SubPhase) + { + case SUBPHASE_FLY : + { + if (m_uiTimer <= uiDiff) + { + m_uiWP = urand(0, 3); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PHASE_2_WP, WPs[m_uiWP].x, WPs[m_uiWP].y, AIR_Z); + m_uiTimer = 15000; + } + else + m_uiTimer -= uiDiff; + return; + } + case SUBPHASE_DEEP_BREATH: + { + break; + } + case SUBPHASE_NOT_DEEP_BREATH: + { + if (m_uiShellTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_BOMB_SUMMON) == CAST_OK) + { + if (!urand(0, 3)) + DoScriptText(SAY_ARCANE_OVERLOAD, m_creature); + m_uiShellTimer = urand(15000, 17000); + m_bReadyForWPMove = true; + m_uiTimer = 2000; + } + } + else + m_uiShellTimer -= uiDiff; + + if (m_uiDeepBreathTimer <= uiDiff) + { + m_creature->GetMotionMaster()->MovePoint(POINT_ID_DEEP_BREATH, CENTER_X, CENTER_Y, AIR_Z+20.0f); + m_bReadyForWPMove = false; + m_uiTimer = 20000; + m_uiDeepBreathTimer = 63000; + m_SubPhase = SUBPHASE_DEEP_BREATH; + } + else + m_uiDeepBreathTimer -= uiDiff; + + break; + } + default: + break; + } + + if (m_uiCheckTimer <= uiDiff) + { + uint8 uiAddAmount = m_bIsRegularMode ? (NEXUS_LORD_COUNT + SCION_OF_ETERNITY_COUNT): (NEXUS_LORD_COUNT_H + SCION_OF_ETERNITY_COUNT_H); + if (m_uiAddDieCounter == uiAddAmount) + { + // for save work + //if (!m_pInstance->IsAnyAddAtLife()) + //{ + m_Phase = PHASE_DRAGONS; + m_SubPhase = SUBPHASE_DESTROY_PLATFORM_1; + DoScriptText(SAY_END_PHASE2, m_creature); + m_pInstance->DestroyVisualOfVortex(false); + m_uiTimer = 6000; + //} + } + + Map* pMap = m_creature->GetMap(); + if (pMap) + { + Map::PlayerList const &lPlayers = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Player* pPlayer = itr->getSource(); + if (pPlayer->GetVehicle() && m_Phase == PHASE_ADDS) + pPlayer->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true); + else + pPlayer->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, false); + } + } + + if (m_Phase == PHASE_DRAGONS) + return; + + m_uiCheckTimer = 1000; + } + else + m_uiCheckTimer -= uiDiff; + + if (m_bReadyForWPMove) + { + if (m_uiTimer <= uiDiff) + { + m_creature->GetMotionMaster()->Clear(); + if (m_SubPhase == SUBPHASE_DEEP_BREATH) + { + m_uiWP = urand(0, 3); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PHASE_2_WP, WPs[m_uiWP].x, WPs[m_uiWP].y, AIR_Z); + } + else + { + float fAng = M_PI/4 + m_creature->GetAngle(CENTER_X, CENTER_Y); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PHASE_2_WP, CENTER_X-80.0f*cos(fAng), CENTER_Y-80.0f*sin(fAng), AIR_Z); + } + m_SubPhase = SUBPHASE_NOT_DEEP_BREATH; + m_bReadyForWPMove = false; + } + else + m_uiTimer -= uiDiff; + } + break; + } + case PHASE_DRAGONS: + { + switch (m_SubPhase) + { + case SUBPHASE_DESTROY_PLATFORM_1: + { + if (m_uiTimer <= uiDiff) + { + m_pInstance->DespawnCreatures(NPC_ARCANE_OVERLOAD); + m_pInstance->DespawnCreatures(NPC_HOVER_DISK_CASTER); + DoCast(m_creature, SPELL_CALL_SKYTALON, true); + m_pInstance->DestroyVisualOfVortex(true); + m_creature->SetInCombatWithZone(); + m_SubPhase = SUBPHASE_DESTROY_PLATFORM_2; + m_uiTimer = 3000; + } + else + m_uiTimer -= uiDiff; + + return; + } + case SUBPHASE_DESTROY_PLATFORM_2: + { + if (m_uiTimer <= uiDiff) + { + if (m_pInstance) + if (GameObject* pPlatform = m_pInstance->GetSingleGameObjectFromStorage(GO_PLATFORM)) + pPlatform->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + + m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, FLOOR_Z); + DoScriptText(SAY_INTRO_PHASE3, m_creature); + + m_SubPhase = SUBPHASE_DESTROY_PLATFORM_3; + m_uiTimer = 3000; + } + else + m_uiTimer -= uiDiff; + + return; + } + case SUBPHASE_DESTROY_PLATFORM_3: + { + if (m_uiTimer<= uiDiff) + { + m_SubPhase = SUBPHASE_DESTROY_PLATFORM_4; + m_uiTimer = 12000; + } + else + m_uiTimer -= uiDiff; + + return; + } + case SUBPHASE_DESTROY_PLATFORM_4: + { + if (m_uiTimer <= uiDiff) + { + m_SubPhase = SUBPHASE_NOT_SURGE_OF_POWER; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoScriptText(SAY_AGGRO3, m_creature); + m_uiArcaneStormTimer = 6000; + } + else + m_uiTimer -= uiDiff; + + return; + } + case SUBPHASE_SURGE_OF_POWER: + { + if (m_uiTimer <= uiDiff) + m_SubPhase = SUBPHASE_NOT_SURGE_OF_POWER; + else + m_uiTimer -= uiDiff; + return; + } + case SUBPHASE_NOT_SURGE_OF_POWER: + { + if (m_uiArcanePulseTimer <= uiDiff) + { + DoCast(m_creature, SPELL_ARCANE_PULSE); + m_uiArcanePulseTimer = 1000; + } + else + m_uiArcanePulseTimer -= uiDiff; + + if (m_uiArcaneStormTimer <= uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_ARCANE_STORM : SPELL_ARCANE_STORM_H); + m_uiArcaneStormTimer = urand(6000, 10000); + } + else + m_uiArcaneStormTimer -= uiDiff; + + if (m_uiStaticFieldTimer <= uiDiff) + { + for (uint8 i = 0; i<=50; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (pTarget->GetEntry() == NPC_WYRMREST_SKYTALON) + { + switch (urand(0, 5)) + { + case 0: DoScriptText(SAY_CAST_SPELL1, m_creature); break; + case 1: DoScriptText(SAY_CAST_SPELL2, m_creature); break; + case 2: DoScriptText(SAY_CAST_SPELL3, m_creature); break; + } + DoCast(pTarget, SPELL_STATIC_FIELD_MISSILE); + break; + } + } + + m_uiStaticFieldTimer = urand(10000, 16000); + } + else + m_uiStaticFieldTimer -= uiDiff; + + if (m_uiSurgeOfPowerTimer <= uiDiff) + { + for (uint8 i = 0; i<=50; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (pTarget->GetEntry() == NPC_WYRMREST_SKYTALON) + { + m_SubPhase = SUBPHASE_SURGE_OF_POWER; + m_uiTimer = 6500; + if (urand(0, 1)) + DoScriptText(SAY_SURGE_OF_POWER, m_creature); + DoCast(pTarget, m_bIsRegularMode ? SPELL_SURGE_OF_POWER : SPELL_SURGE_OF_POWER_H); + break; + } + } + + m_uiSurgeOfPowerTimer = urand(5000, 15000); + } + else + m_uiSurgeOfPowerTimer -= uiDiff; + break; + } + default: + m_creature->MonsterSay("Unknown SubPhase in MainPhase Dragon", LANG_UNIVERSAL); + break; + } + break; + } + default: + m_creature->MonsterSay("Unknown MainPhase", LANG_UNIVERSAL); + break; + } + } +}; + +/*###### +## npc_power_spark +######*/ +struct MANGOS_DLL_DECL npc_power_sparkAI : public ScriptedAI +{ + npc_power_sparkAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_eye_of_eternity*)pCreature->GetInstanceData(); + Reset(); + } + + instance_eye_of_eternity* m_pInstance; + uint32 m_uiCheckTimer; + + void Reset() + { + m_uiCheckTimer = 2000; + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->CastSpell(m_creature, SPELL_POWER_SPARK_VISUAL, false); + m_creature->SetRespawnDelay(DAY); + } + + void JustDied(Unit* pKiller) override + { + DoCast(m_creature, SPELL_POWER_SPARK_PLAYERS, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiCheckTimer <= uiDiff) + { + if (m_pInstance) + if (Creature* pMalygos = m_pInstance->GetSingleCreatureFromStorage(NPC_MALYGOS)) + { + m_creature->GetMotionMaster()->Clear(); + if (m_creature->IsWithinDist(pMalygos, 5.0f, false)) + { + m_creature->CastSpell(pMalygos, SPELL_POWER_SPARK, true); + m_creature->ForcedDespawn(100); + } + else + { + m_creature->GetMotionMaster()->MovePoint(0, pMalygos->GetPositionX(), pMalygos->GetPositionY(), pMalygos->GetPositionZ(), false); + } + } + + m_uiCheckTimer = 2000; + } + else + m_uiCheckTimer -= uiDiff; + } +}; + +/*###### +## npc_nexus_lord +######*/ + +struct MANGOS_DLL_DECL npc_nexus_lordAI : public ScriptedAI +{ + npc_nexus_lordAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + uint32 m_uiArcaneShockTimer; + uint32 m_uiHasteTimer; + + uint32 m_uiMoveTimer; + + void Reset() + { + m_uiMoveTimer = 2000; + SetCombatMovement(false); + m_uiArcaneShockTimer = urand(8000, 9000); + m_uiHasteTimer = urand(10000, 12000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + { + if (m_uiMoveTimer <=uiDiff) + { + if (VehicleKitPtr pVehicleBase = m_creature->GetVehicle()) + { + if (Unit* pDisk = pVehicleBase->GetBase()) + { + pDisk->GetMotionMaster()->Clear(); + pDisk->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + m_uiMoveTimer = 2000; + } + else + m_uiMoveTimer -= uiDiff; + } + + if (m_uiArcaneShockTimer <= uiDiff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_SHOCK : SPELL_ARCANE_SHOCK_H); + m_uiArcaneShockTimer = urand(8000, 10000); + } + else + m_uiArcaneShockTimer -= uiDiff; + + if (m_uiHasteTimer <= uiDiff) + { + DoCast(m_creature, SPELL_HASTE); + m_uiHasteTimer = urand(25000, 30000); + } + else + m_uiHasteTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_scion_of_eternity +######*/ + +struct MANGOS_DLL_DECL npc_scion_of_eternityAI : public ScriptedAI +{ + npc_scion_of_eternityAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + uint32 m_uiArcaneBarrageTimer; + + uint32 m_uiMoveTimer; + + void Reset() + { + m_uiMoveTimer = 2000; + SetCombatMovement(false); + m_uiArcaneBarrageTimer = urand(4000, 12000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiArcaneBarrageTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (!pTarget->GetVehicle()) + { + int32 uiDmg = m_bIsRegularMode ? urand(14138, 15862) : urand(16965, 19035); + m_creature->CastCustomSpell(pTarget, SPELL_ARCANE_BARRAGE, &uiDmg, 0, 0, true); + m_uiArcaneBarrageTimer = urand(4000, 12000); + } + } + } + else + m_uiArcaneBarrageTimer -= uiDiff; + + if (m_uiMoveTimer < uiDiff) + { + if (VehicleKitPtr pVehicle = m_creature->GetVehicle()) + { + if (Unit* pDisk = pVehicle->GetBase()) + { + pDisk->GetMotionMaster()->Clear(); + pDisk->GetMotionMaster()->MovePoint(0, urand(PLATFORM_MIN_X, PLATFORM_MAX_X), urand(PLATFORM_MIN_Y, PLATFORM_MAX_Y), FLOOR_Z+10.0f+urand(0, 15), false); + } + } + m_uiMoveTimer = 10000; + } + else + m_uiMoveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_hover_disk +######*/ +struct MANGOS_DLL_DECL npc_hover_diskAI : public ScriptedAI +{ + npc_hover_diskAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + void Reset() + { + m_creature->CastSpell(m_creature, SPELL_FLIGHT, true); + m_creature->SetLevitate(true); + } + + void AttackStart(Unit* pWho) override + { + } + + void PassengerBoarded(Unit* pWho, int8 seatId, bool apply) override + { + if (!apply) + { + m_creature->GetMotionMaster()->MoveFall(); + m_creature->setFaction(35); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->CastSpell(m_creature, SPELL_FLIGHT, true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + } +}; + +/*###### +## npc_alexstrasza +######*/ +struct MANGOS_DLL_DECL npc_alexstraszaAI : public ScriptedAI +{ + npc_alexstraszaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiTimer; + uint8 m_uiCount; + + void Reset() + { + m_uiTimer = 9500; + m_uiCount = 0; + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->SetLevitate(true); + if (m_pInstance) + if (Creature* pMalygos = m_pInstance->GetSingleCreatureFromStorage(NPC_MALYGOS)) + m_creature->SetFacingToObject(pMalygos); + } + + void SpellHitTarget(Unit* pUnit, const SpellEntry* pSpell) + { + if (pUnit->GetEntry() == NPC_ALEXSTRASZAS_GIFT && pSpell->Id == SPELL_ALEXSTRASZAS_GIFT_BEAM) + pUnit->CastSpell(pUnit, SPELL_ALEXSTRASZAS_GIFT_VISUAL, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiCount == 6) + return; + + if (m_uiTimer <= uiDiff) + { + switch (m_uiCount) + { + case 0: + if (m_pInstance) + if (Creature* pMalygos = m_pInstance->GetSingleCreatureFromStorage(NPC_MALYGOS)) + pMalygos->RemoveCorpse(); + DoScriptText(SAY_OUTRO1, m_creature); + m_uiTimer = 5000; + break; + case 1: + DoScriptText(SAY_OUTRO2, m_creature); + m_uiTimer = 3500; + break; + case 2: + DoScriptText(SAY_OUTRO3, m_creature); + m_uiTimer = 22000; + break; + case 3: + DoScriptText(SAY_OUTRO4, m_creature); + m_uiTimer = 19500; + break; + case 4: + DoCast(m_creature, SPELL_ALEXSTRASZAS_GIFT_BEAM); + m_uiTimer = 3000; + break; + case 5: + if (m_pInstance) + m_pInstance->SetData(TYPE_MALYGOS, DONE); + break; + } + ++m_uiCount; + } + else + m_uiTimer -= uiDiff; + } +}; + +/*###### +## go_focusing_iris +######*/ +bool GOHello_go_focusing_iris(Player* pPlayer, GameObject* pGo) +{ + if (instance_eye_of_eternity* pInstance = (instance_eye_of_eternity*)pGo->GetInstanceData()) + { + pInstance->SetData(TYPE_MALYGOS, IN_PROGRESS); + } + return false; +} + +CreatureAI* GetAI_boss_malygos(Creature* pCreature) +{ + return new boss_malygosAI(pCreature); +} + +CreatureAI* GetAI_npc_power_spark(Creature* pCreature) +{ + return new npc_power_sparkAI(pCreature); +} + +CreatureAI* GetAI_npc_nexus_lord(Creature* pCreature) +{ + return new npc_nexus_lordAI(pCreature); +} + +CreatureAI* GetAI_npc_scion_of_eternity(Creature* pCreature) +{ + return new npc_scion_of_eternityAI(pCreature); +} + +CreatureAI* GetAI_npc_hover_disk(Creature* pCreature) +{ + return new npc_hover_diskAI(pCreature); +} + +CreatureAI* GetAI_npc_alexstrasza(Creature* pCreature) +{ + return new npc_alexstraszaAI(pCreature); +} + +struct MANGOS_DLL_DECL npc_whyrmrest_skytalonAI : public ScriptedAI +{ + npc_whyrmrest_skytalonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_eye_of_eternity*)pCreature->GetInstanceData(); + Reset(); + } + + instance_eye_of_eternity* m_pInstance; + bool Active; + bool seated; + ObjectGuid ownerGUID; + uint32 StartTimer; + uint32 SeatTimer; + + void Reset() + { + Active = false; + seated = false; + ownerGUID = ObjectGuid(); + StartTimer = 500; + SeatTimer = 2000; + ownerGUID = m_creature->GetCreatorGuid(); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->SetLevitate(true); + } + + void AttackStart(Unit *) {} + void MoveInLineOfSight(Unit*) override { } + + /*void JustDied(Unit* killer) + { + if (!m_creature || m_creature->GetTypeId() != TYPEID_UNIT) + return; + + if (ownerGUID.IsEmpty()) + ownerGUID = m_creature->GetCreatorGuid(); + + Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID); + + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + owner->RemoveAurasDueToSpell(SPELL_VEHICLE_HARDCODED); + m_creature->SetCreatorGuid(ObjectGuid()); + }*/ + + void UpdateAI(const uint32 uiDiff) override + { + + if (ownerGUID.IsEmpty()) + { + ownerGUID = m_creature->GetCreatorGuid(); + if (Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID)) + m_creature->setFaction(owner->getFaction()); + } + + if (!ownerGUID.IsEmpty() && !seated && Active) + { + if (SeatTimer < uiDiff) + { + if (Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID)) + { + m_creature->setFaction(owner->getFaction()); + owner->CastSpell(m_creature, SPELL_RIDE_RED_DRAGON_BUDDY, true); + if (Creature* pMalygos = m_pInstance->GetSingleCreatureFromStorage(NPC_MALYGOS)) + { + pMalygos->SetInCombatWith(m_creature); + pMalygos->AddThreat(m_creature); + } + seated = true; + } + } + else + SeatTimer -= uiDiff; + } + + if (!ownerGUID.IsEmpty() && !Active) + { + if (StartTimer < uiDiff) + { + if (Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID)) + { + float x, y, z; + owner->GetClosePoint(x, y, z, owner->GetObjectBoundingRadius(), 1.0f, owner->GetAngle(m_creature)); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z); + Active = true; + } + } + else + StartTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_whyrmrest_skytalon(Creature* pCreature) +{ + return new npc_whyrmrest_skytalonAI(pCreature); +} + +void AddSC_boss_malygos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_malygos"; + newscript->GetAI = &GetAI_boss_malygos; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_power_spark"; + newscript->GetAI = &GetAI_npc_power_spark; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_nexus_lord"; + newscript->GetAI = &GetAI_npc_nexus_lord; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_scion_of_eternity"; + newscript->GetAI = &GetAI_npc_scion_of_eternity; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_hover_disk"; + newscript->GetAI = &GetAI_npc_hover_disk; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_whyrmrest_skytalon"; + newscript->GetAI = &GetAI_npc_whyrmrest_skytalon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_alexstrasza"; + newscript->GetAI = &GetAI_npc_alexstrasza; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "go_focusing_iris"; + newscript->pGOUse = &GOHello_go_focusing_iris; + newscript->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 0000000000..fb5d2a767f --- /dev/null +++ b/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h @@ -0,0 +1,96 @@ + +#ifndef DEF_EYE_OF_ETERNITY_H +#define DEF_EYE_OF_ETERNITY_H + +enum +{ + MAX_ENCOUNTER = 1, + + TYPE_MALYGOS = 0, + + NPC_MALYGOS = 28859, + + // ******************************** Items, NPCs & GameObjects ******************************** // + + ITEM_KEY_TO_FOCUSING_IRIS = 44582, + ITEM_KEY_TO_FOCUSING_IRIS_H = 44581, + + GO_PLATFORM = 193070, + GO_EXIT_PORTAL = 193908, + GO_FOCUSING_IRIS = 193958, + GO_FOCUSING_IRIS_H = 193960, + GO_ALEXSTRASZAS_GIFT = 193905, + GO_ALEXSTRASZAS_GIFT_H = 193967, + GO_HEART_OF_MAGIC = 194158, + GO_HEART_OF_MAGIC_H = 194159, + + //////////////// PHASE 1 //////////////// + NPC_VORTEX = 30090, + NPC_POWER_SPARK = 30084, + NPC_SPARK_PORTAL = 30118, // for power sparks + VEHICLE_VORTEX = 168, + + //////////////// PHASE 2 //////////////// + NPC_HOVER_DISK_MELEE = 30234, + NPC_HOVER_DISK_CASTER = 30248, + NPC_NEXUS_LORD = 30245, // 2 (normal) and 4 (heroic) of them are spawned on beginning of phase 2 + NPC_SCION_OF_ETERNITY = 30249, // 4 (normal) and 8 (heroic) of them are spawned on beginning of phase 2 + NPC_ARCANE_OVERLOAD = 30282, + NPC_SURGE_OF_POWER = 30334, + + //////////////// PHASE 3 //////////////// + NPC_STATIC_FIELD = 30592, // trigger for that spell + NPC_WYRMREST_SKYTALON = 30161, // dragon vehicle in 3-d Phase + NPC_ALEXSTRASZA = 32295, + NPC_ALEXSTRASZAS_GIFT = 32448, + NPC_ALEXSTRASZA_THE_LIFE_BINDER = 31253, // maybe trigger npc + + // ********************************* Some Spells *************************************// + SPELL_VORTEX_RIDE_AURA = 56266, // on 10 sec, deal 2000 damage all player around caster + SPELL_VORTEX_VISUAL = 55873, // visual effect around platform + SPELL_DESTROY_PLATFORM_PRE = 58842, // lights all over the platform + SPELL_DESTROY_PLATFORM_BOOM = 59084, // Big Blue boom +}; + +struct MANGOS_DLL_DECL instance_eye_of_eternity : public ScriptedInstance +{ + public: + instance_eye_of_eternity(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + bool IsEncounterInProgress() const override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return strInstData.c_str();} + void Load(const char* chrIn) override; + + void DespawnCreatures(uint32 uiEntry); + + void ActivateVisualOfVortex(); + void DestroyVisualOfVortex(bool boom); + void HandleRiderOfVortex(Unit* pTarget); + + bool IsAnyAddAtLife(); + + private: + std::string strInstData; + uint32 m_auiEncounter[MAX_ENCOUNTER]; + Difficulty difficulty; + + GuidList m_lPowerSparkList; + GuidList m_lArcaneOverload; + GuidList m_lNexusLord; + GuidList m_lScionOfEternity; + GuidList m_lHoverDisk; + GuidList m_lStaticField; + + GuidList m_lSparkPortal; + GuidList m_lVortex; + +}; +#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 0000000000..8b8a119a3e --- /dev/null +++ b/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp @@ -0,0 +1,349 @@ +/* Copyright (C) 2006 - 2013 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: Instance_Eye_of_Eternity + SD%Complete: 90% + SDComment: + SDAuthor: Tassadar + SDCategory: Nexus, Eye of Eternity + EndScriptData */ + +#include "precompiled.h" +#include "eye_of_eternity.h" +#include "Vehicle.h" + +instance_eye_of_eternity::instance_eye_of_eternity(Map* pMap) : + ScriptedInstance(pMap) +{ + difficulty = pMap->GetDifficulty(); + Initialize(); +} + +void instance_eye_of_eternity::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +void instance_eye_of_eternity::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_MALYGOS: + pCreature->SetActiveObjectState(true); + /* no break */ + case NPC_SURGE_OF_POWER: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_POWER_SPARK: + m_lPowerSparkList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_ARCANE_OVERLOAD: + m_lArcaneOverload.push_back(pCreature->GetObjectGuid()); + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + break; + case NPC_NEXUS_LORD: + m_lNexusLord.push_back(pCreature->GetObjectGuid()); + break; + case NPC_SCION_OF_ETERNITY: + m_lScionOfEternity.push_back(pCreature->GetObjectGuid()); + break; + case NPC_HOVER_DISK_MELEE: + case NPC_HOVER_DISK_CASTER: + m_lHoverDisk.push_back(pCreature->GetObjectGuid()); + break; + case NPC_STATIC_FIELD: + m_lStaticField.push_back(pCreature->GetObjectGuid()); + break; + case NPC_SPARK_PORTAL: + m_lSparkPortal.push_back(pCreature->GetObjectGuid()); + break; + case NPC_VORTEX: + m_lVortex.push_back(pCreature->GetObjectGuid()); + break; + default: + break; + } +} + +void instance_eye_of_eternity::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_PLATFORM: + case GO_EXIT_PORTAL: + case GO_FOCUSING_IRIS: + case GO_FOCUSING_IRIS_H: + case GO_ALEXSTRASZAS_GIFT: + case GO_ALEXSTRASZAS_GIFT_H: + case GO_HEART_OF_MAGIC: + case GO_HEART_OF_MAGIC_H: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + } +} + +bool instance_eye_of_eternity::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + + return false; +} + +void instance_eye_of_eternity::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_MALYGOS: + { + switch (uiData) + { + case FAIL: + case NOT_STARTED: + { + if (GameObject* pFocusingIris = GetSingleGameObjectFromStorage(difficulty == RAID_DIFFICULTY_10MAN_NORMAL ? GO_FOCUSING_IRIS : GO_FOCUSING_IRIS_H)) + { + pFocusingIris->SetGoState(GO_STATE_READY); + pFocusingIris->SetPhaseMask(1, true); + } + if (GameObject* pExitPortal = GetSingleGameObjectFromStorage(GO_EXIT_PORTAL)) + pExitPortal->SetPhaseMask(1, true); + if (GameObject* pPlatform = GetSingleGameObjectFromStorage(GO_PLATFORM)) + pPlatform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + DespawnCreatures(NPC_POWER_SPARK); + DespawnCreatures(NPC_ARCANE_OVERLOAD); + DespawnCreatures(NPC_NEXUS_LORD); + DespawnCreatures(NPC_SCION_OF_ETERNITY); + DespawnCreatures(NPC_HOVER_DISK_CASTER); + DespawnCreatures(NPC_STATIC_FIELD); + break; + } + case IN_PROGRESS: + { + if (GameObject* pFocusingIris = GetSingleGameObjectFromStorage(difficulty == RAID_DIFFICULTY_10MAN_NORMAL ? GO_FOCUSING_IRIS : GO_FOCUSING_IRIS_H)) + pFocusingIris->SetPhaseMask(2, true); + if (GameObject* pExitPortal = GetSingleGameObjectFromStorage(GO_EXIT_PORTAL)) + pExitPortal->SetPhaseMask(2, true); + break; + } + case DONE: + { + if (GameObject* pExitPortal = GetSingleGameObjectFromStorage(GO_EXIT_PORTAL)) + pExitPortal->SetPhaseMask(1, true); + DoRespawnGameObject(difficulty == RAID_DIFFICULTY_10MAN_NORMAL ? GO_ALEXSTRASZAS_GIFT : GO_ALEXSTRASZAS_GIFT_H, HOUR * IN_MILLISECONDS); + DoRespawnGameObject(difficulty == RAID_DIFFICULTY_10MAN_NORMAL ? GO_HEART_OF_MAGIC : GO_HEART_OF_MAGIC_H, HOUR * IN_MILLISECONDS); + break; + } + default: + break; + } + m_auiEncounter[0] = uiData; + break; + } + default: + break; + } + OUT_SAVE_INST_DATA; + std::ostringstream saveStream; + saveStream << m_auiEncounter[TYPE_MALYGOS]; + + strInstData = saveStream.str(); + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + +} + +void instance_eye_of_eternity::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; +} + +uint32 instance_eye_of_eternity::GetData(uint32 uiType) const +{ + switch (uiType) + { + case TYPE_MALYGOS: + return m_auiEncounter[TYPE_MALYGOS]; + } + return 0; +} + +void instance_eye_of_eternity::DespawnCreatures(uint32 uiEntry) +{ + switch (uiEntry) + { + case NPC_POWER_SPARK: + { + for (GuidList::iterator iter = m_lPowerSparkList.begin(); iter != m_lPowerSparkList.end(); ++iter) + { + if (Creature* pSpark = instance->GetCreature(*iter)) + pSpark->ForcedDespawn(); + } + m_lPowerSparkList.clear(); + break; + } + case NPC_ARCANE_OVERLOAD: + { + for (GuidList::iterator iter = m_lArcaneOverload.begin(); iter != m_lArcaneOverload.end(); ++iter) + { + if (Creature* pArcaneOverload = instance->GetCreature(*iter)) + pArcaneOverload->ForcedDespawn(); + } + m_lArcaneOverload.clear(); + break; + } + case NPC_NEXUS_LORD: + { + for (GuidList::iterator iter = m_lNexusLord.begin(); iter != m_lNexusLord.end(); ++iter) + { + if (Creature* pNexusLord = instance->GetCreature(*iter)) + pNexusLord->ForcedDespawn(); + } + m_lNexusLord.clear(); + break; + } + case NPC_SCION_OF_ETERNITY: + { + for (GuidList::iterator iter = m_lScionOfEternity.begin(); iter != m_lScionOfEternity.end(); ++iter) + { + if (Creature* pScionOfEternity = instance->GetCreature(*iter)) + pScionOfEternity->ForcedDespawn(); + } + m_lScionOfEternity.clear(); + break; + } + case NPC_HOVER_DISK_MELEE: + case NPC_HOVER_DISK_CASTER: + { + for (GuidList::iterator iter = m_lHoverDisk.begin(); iter != m_lHoverDisk.end(); ++iter) + { + if (Creature* pHoverDisk = instance->GetCreature(*iter)) + pHoverDisk->ForcedDespawn(); + } + m_lHoverDisk.clear(); + break; + } + case NPC_STATIC_FIELD: + { + for (GuidList::iterator iter = m_lStaticField.begin(); iter != m_lStaticField.end(); ++iter) + { + if (Creature* pStaticField = instance->GetCreature(*iter)) + pStaticField->ForcedDespawn(); + } + m_lStaticField.clear(); + break; + } + default: + break; + } +} + +void instance_eye_of_eternity::ActivateVisualOfVortex() +{ + for (GuidList::const_iterator iter = m_lVortex.begin(); iter != m_lVortex.end(); ++ iter) + { + if (Creature* pVortex = instance->GetCreature(*iter)) + { + pVortex->CastSpell(pVortex, SPELL_VORTEX_VISUAL, false); + } + } +} + +void instance_eye_of_eternity::DestroyVisualOfVortex(bool boom) +{ + for (GuidList::const_iterator iter = m_lVortex.begin(); iter != m_lVortex.end(); ++ iter) + { + if (Creature* pVortex = instance->GetCreature(*iter)) + { + pVortex->CastSpell(pVortex, (boom ? SPELL_DESTROY_PLATFORM_BOOM : SPELL_DESTROY_PLATFORM_PRE), false); + } + } +} + +void instance_eye_of_eternity::HandleRiderOfVortex(Unit* pTarget) +{ + for (GuidList::const_iterator iter = m_lVortex.begin(); iter != m_lVortex.end(); ++iter) + { + if (Creature* pVortex = instance->GetCreature(*iter)) + { + if (VehicleKitPtr pVehicle = pVortex->GetVehicleKit()) + { + if (pVehicle->GetNextEmptySeatWithFlag(0) != -1) + { + pTarget->CastSpell(pTarget, SPELL_VORTEX_RIDE_AURA, true); + return; + } + } + } + } +} + +//TODO: better count down +bool instance_eye_of_eternity::IsAnyAddAtLife() +{ + for (GuidList::const_iterator iter = m_lNexusLord.begin(); iter != m_lNexusLord.end(); ++iter) + { + if (Creature* pNexusLord = instance->GetCreature(*iter)) + { + if (pNexusLord->isAlive()) + return true; + } + } + for (GuidList::const_iterator iter = m_lScionOfEternity.begin(); iter != m_lScionOfEternity.end(); ++iter) + { + if (Creature* pScionOfEternity = instance->GetCreature(*iter)) + { + if (pScionOfEternity->isAlive()) + return true; + } + } + return false; +} + +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 46f96d36d7..ba79015cc0 100644 --- a/scripts/northrend/nexus/nexus/boss_anomalus.cpp +++ b/scripts/northrend/nexus/nexus/boss_anomalus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Anomalus -SD%Complete: 50% -SDComment: TODO: remove hacks, add support for rift charging +SD%Complete: 90% +SDComment: Small adjustments required SDCategory: Nexus EndScriptData */ @@ -42,7 +42,6 @@ enum SPELL_SPARK = 47751, SPELL_SPARK_H = 57062, - SPELL_ARCANE_FORM = 48019, // Chaotic Rift SPELL_RIFT_AURA = 47687, SPELL_RIFT_SUMMON_AURA = 47732, @@ -51,7 +50,6 @@ enum SPELL_CHARGED_RIFT_AURA = 47733, SPELL_CHARGED_RIFT_SUMMON_AURA = 47742, - SPELL_SUMMON_CRAZED_MANA_WRAITH = 47692, NPC_CHAOTIC_RIFT = 26918, NPC_CRAZED_MANA_WRAITH = 26746 }; @@ -64,33 +62,36 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI { boss_anomalusAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_nexus*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_nexus* m_pInstance; bool m_bIsRegularMode; bool m_bChaoticRift; uint32 m_uiSparkTimer; uint32 m_uiCreateRiftTimer; - uint64 m_uiChaoticRiftGUID; + uint8 m_uiChaoticRiftCount; - void Reset() + void Reset() override { m_bChaoticRift = false; m_uiSparkTimer = 5000; m_uiCreateRiftTimer = 25000; - m_uiChaoticRiftGUID = 0; + m_uiChaoticRiftCount = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ANOMALUS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -98,16 +99,18 @@ 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) { + ++m_uiChaoticRiftCount; + DoScriptText(SAY_RIFT, m_creature); if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) @@ -115,50 +118,55 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI } } - void SummonedCreatureDespawn(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { - if (pSummoned->GetGUID() == m_uiChaoticRiftGUID) + if (pSummoned->GetEntry() == NPC_CHAOTIC_RIFT) { - if (m_creature->HasAura(SPELL_RIFT_SHIELD)) - m_creature->RemoveAurasDueToSpell(SPELL_RIFT_SHIELD); - - m_uiChaoticRiftGUID = 0; - } - } - - uint64 CreateRiftAtRandomPoint() - { - float fPosX, fPosY, fPosZ; - m_creature->GetPosition(fPosX, fPosY, fPosZ); - m_creature->GetRandomPoint(fPosX, fPosY, fPosZ, urand(15, 25), fPosX, fPosY, fPosZ); + --m_uiChaoticRiftCount; - Creature* pRift = m_creature->SummonCreature(NPC_CHAOTIC_RIFT, fPosX, fPosY, fPosZ, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 1000); - DoScriptText(EMOTE_OPEN_RIFT, m_creature); + // If players kill the Chaotic Rifts then mark the achievement as false + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_CHAOS_THEORY, false); - return pRift?pRift->GetGUID():0; + if (!m_uiChaoticRiftCount) + { + if (m_creature->HasAura(SPELL_RIFT_SHIELD)) + m_creature->RemoveAurasDueToSpell(SPELL_RIFT_SHIELD); + } + } } - 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) { - DoScriptText(EMOTE_SHIELD, m_creature); - m_uiChaoticRiftGUID = CreateRiftAtRandomPoint(); - - DoScriptText(SAY_SHIELD, m_creature); - DoCastSpellIfCan(m_creature, SPELL_RIFT_SHIELD); - m_bChaoticRift = true; + // create a rift then set shield up and finally charge rift + if (DoCastSpellIfCan(m_creature, SPELL_CREATE_RIFT, CAST_TRIGGERED) == CAST_OK) + { + // emotes are in this order + DoScriptText(EMOTE_SHIELD, m_creature); + DoScriptText(SAY_SHIELD, m_creature); + DoScriptText(EMOTE_OPEN_RIFT, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_RIFT_SHIELD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CHARGE_RIFT, CAST_TRIGGERED); + m_bChaoticRift = true; + } return; } if (m_uiCreateRiftTimer < uiDiff) { - CreateRiftAtRandomPoint(); - m_uiCreateRiftTimer = 25000; + if (DoCastSpellIfCan(m_creature, SPELL_CREATE_RIFT) == CAST_OK) + { + DoScriptText(SAY_RIFT, m_creature); + DoScriptText(EMOTE_OPEN_RIFT, m_creature); + m_uiCreateRiftTimer = 25000; + } } else m_uiCreateRiftTimer -= uiDiff; @@ -184,23 +192,23 @@ CreatureAI* GetAI_boss_anomalus(Creature* pCreature) struct MANGOS_DLL_DECL mob_chaotic_riftAI : public Scripted_NoMovementAI { - mob_chaotic_riftAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + mob_chaotic_riftAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiChargedRemoveTimer; + + void Reset() override { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); + m_uiChargedRemoveTimer = 0; } - ScriptedInstance* m_pInstance; - uint32 m_uiSummonTimer; - - void Reset() + void Aggro(Unit* /*pWho*/) override { - m_uiSummonTimer = 16000; - DoCastSpellIfCan(m_creature, SPELL_RIFT_AURA); - //DoCastSpellIfCan(m_creature, SPELL_RIFT_SUMMON_AURA); + // 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) { @@ -209,21 +217,34 @@ struct MANGOS_DLL_DECL mob_chaotic_riftAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // When hit with Charge Rift cast the Charged Rift spells + if (pSpell->Id == SPELL_CHARGE_RIFT) + { + DoCastSpellIfCan(m_creature, SPELL_CHARGED_RIFT_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CHARGED_RIFT_SUMMON_AURA, CAST_TRIGGERED); + m_uiChargedRemoveTimer = 45000; + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!m_creature->HasAura(SPELL_ARCANE_FORM)) - DoCastSpellIfCan(m_creature, SPELL_ARCANE_FORM); - - if (m_uiSummonTimer < uiDiff) + if (m_uiChargedRemoveTimer) { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_CRAZED_MANA_WRAITH); - m_uiSummonTimer = 16000; + // The charged spells need to be removed by casting the normal ones in case the npc isn't killed + if (m_uiChargedRemoveTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_RIFT_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_RIFT_SUMMON_AURA, CAST_TRIGGERED); + m_uiChargedRemoveTimer = 0; + } + else + m_uiChargedRemoveTimer -= uiDiff; } - else - m_uiSummonTimer -= uiDiff; } }; @@ -234,15 +255,15 @@ CreatureAI* GetAI_mob_chaotic_rift(Creature* pCreature) void AddSC_boss_anomalus() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_anomalus"; - newscript->GetAI = &GetAI_boss_anomalus; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_anomalus"; + pNewScript->GetAI = &GetAI_boss_anomalus; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_chaotic_rift"; - newscript->GetAI = &GetAI_mob_chaotic_rift; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_chaotic_rift"; + pNewScript->GetAI = &GetAI_mob_chaotic_rift; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/nexus/boss_keristrasza.cpp b/scripts/northrend/nexus/nexus/boss_keristrasza.cpp index fa11d676ce..ce8bba6606 100644 --- a/scripts/northrend/nexus/nexus/boss_keristrasza.cpp +++ b/scripts/northrend/nexus/nexus/boss_keristrasza.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -32,7 +32,10 @@ enum SAY_KILL = -1576019, SAY_DEATH = -1576020, + MAX_INTENSE_COLD_STACK = 2, // the max allowed stacks for the achiev to pass + SPELL_INTENSE_COLD = 48094, + SPELL_INTENSE_COLD_AURA = 48095, // used for Intense cold achiev SPELL_CRYSTALFIRE_BREATH = 48096, SPELL_CRYSTALFIRE_BREATH_H = 57091, @@ -66,15 +69,17 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI uint32 uiTailSweepTimer; uint32 uiCrystalfireBreathTimer; uint32 uiCrystallizeTimer; + uint32 uiCheckIntenseColdTimer; bool m_bIsEnraged; - void Reset() + void Reset() override { uiCrystalChainTimer = 30000; uiTailSweepTimer = urand(5000, 7500); uiCrystalfireBreathTimer = urand(10000, 20000); uiCrystallizeTimer = urand(20000, 30000); + uiCheckIntenseColdTimer = 2000; m_bIsEnraged = false; @@ -84,18 +89,21 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI if (m_creature->isAlive()) { if (m_pInstance->GetData(TYPE_KERISTRASZA) != SPECIAL) - m_creature->CastSpell(m_creature, SPELL_FROZEN_PRISON, true); + DoCastSpellIfCan(m_creature, SPELL_FROZEN_PRISON, CAST_TRIGGERED); } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); m_creature->CastSpell(m_creature, SPELL_INTENSE_COLD, true); + + if (m_pInstance) + m_pInstance->SetData(TYPE_KERISTRASZA, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -103,17 +111,41 @@ 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) + { + 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_INTENSE_COLD_AURA, EFFECT_INDEX_0); + + if (pAuraIntenseCold) + { + if (pAuraIntenseCold->GetStackAmount() > MAX_INTENSE_COLD_STACK) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_INTENSE_COLD_FAILED, pTarget->GetGUIDLow()); + } + } + } + } + uiCheckIntenseColdTimer = 1000; + } + else + uiCheckIntenseColdTimer -= uiDiff; + if (!m_bIsEnraged && m_creature->GetHealthPercent() < 25.0f) { if (!m_creature->IsNonMeleeSpellCasted(false)) @@ -151,7 +183,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()) { @@ -210,10 +242,10 @@ CreatureAI* GetAI_boss_keristrasza(Creature* pCreature) void AddSC_boss_keristrasza() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_keristrasza"; - newscript->GetAI = &GetAI_boss_keristrasza; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_keristrasza"; + pNewScript->GetAI = &GetAI_boss_keristrasza; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/nexus/boss_ormorok.cpp b/scripts/northrend/nexus/nexus/boss_ormorok.cpp index aa8b4c0807..fc440597a8 100644 --- a/scripts/northrend/nexus/nexus/boss_ormorok.cpp +++ b/scripts/northrend/nexus/nexus/boss_ormorok.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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: 95% +SDComment: Playable Normal Heroic Support SDCategory: Nexus EndScriptData */ @@ -26,32 +26,35 @@ EndScriptData */ enum { - SAY_AGGRO = -1576011, - SAY_KILL = -1576012, - SAY_REFLECT = -1576013, - SAY_ICESPIKE = -1576014, - SAY_DEATH = -1576015, - EMOTE_BOSS_GENERIC_FRENZY = -1000005, + // Spells + SPELL_CRYSTAL_SPIKES_N = 47958, //Don't work, using walkaround + SPELL_CRYSTAL_SPIKES_H = 57082, //Don't work, using walkaround + SPELL_CRYSTALL_SPIKE_DAMAGE_N = 47944, + SPELL_CRYSTALL_SPIKE_DAMAGE_H = 57067, + SPELL_CRYSTAL_SPIKE_PREVISUAL = 50442, + SPELL_SPELL_REFLECTION = 35399, //47981, + SPELL_TRAMPLE_N = 48016, + SPELL_TRAMPLE_H = 57066, + SPELL_FRENZY_H = 48017, + SPELL_FRENZY_N = 57086, + SPELL_SUMMON_CRYSTALLINE_TANGLER = 61564, //summons npc 32665 + SPELL_ROOTS = 28858, //proper spell id is unknown - SPELL_REFLECTION = 47981, + // NPC's + MOB_CRYSTAL_SPIKE = 27099, + MOB_CRYSTALLINE_TANGLER = 32665, - SPELL_CRYSTAL_SPIKES = 47958, - SPELL_CRYSTAL_SPIKES_H1 = 57082, - SPELL_CRYSTAL_SPIKES_H2 = 57083, + // Texts + SAY_AGGRO = -1576020, + SAY_DEATH = -1576021, + SAY_REFLECT = -1576022, + SAY_CRYSTAL_SPIKES = -1576023, + SAY_KILL = -1576024, - SPELL_FRENZY = 48017, - SPELL_FRENZY_H = 57086, - - SPELL_TRAMPLE = 48016, - SPELL_TRAMPLE_H = 57066, - - SPELL_SUMMON_TANGLER_H = 61564 + // Others + SPIKE_DISTANCE = 5 }; -/*###### -## boss_ormorok -######*/ - struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI { boss_ormorokAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -64,29 +67,40 @@ struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - bool m_bIsEnraged; - + bool m_bIsFrenzy; + bool m_bIsCrystalSpikes; + uint8 m_uiCrystalSpikesCount; + uint32 m_uiSpellCrystalSpikesTimer; + uint32 m_uiCrystalSpikesTimer; uint32 m_uiTrampleTimer; - uint32 m_uiSpellReflectTimer; - uint32 m_uiCrystalSpikeTimer; - uint32 m_uiTanglerTimer; + uint32 m_uiFrenzyTimer; + uint32 m_uiReflectionTimer; + uint32 m_uiSummonTanglerTimer; + float m_fBaseX; + float m_fBaseY; + float m_fBaseZ; + float m_fBaseO; + float m_fSpikeXY[4][2]; void Reset() { - m_bIsEnraged = false; + m_uiSpellCrystalSpikesTimer = 12*IN_MILLISECONDS; + m_uiTrampleTimer = 10*IN_MILLISECONDS; + m_uiReflectionTimer = 30*IN_MILLISECONDS; + m_uiSummonTanglerTimer = 17*IN_MILLISECONDS; + m_bIsFrenzy = false; + m_bIsCrystalSpikes = false; - m_uiTrampleTimer = urand(10000, 35000); - m_uiSpellReflectTimer = urand(5000, 10000); - m_uiCrystalSpikeTimer = urand(15000, 30000); - m_uiTanglerTimer = 20000; + if(m_pInstance) + m_pInstance->SetData(TYPE_ORMOROK, NOT_STARTED); } - 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,68 +108,90 @@ 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); + DoScriptText(SAY_KILL, m_creature); } - void JustSummoned(Creature* pSummoned) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - pSummoned->AI()->AttackStart(pTarget); - } - - 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_bIsCrystalSpikes) { - if (!m_creature->IsNonMeleeSpellCasted(false)) + if (m_uiCrystalSpikesTimer < uiDiff) { - m_bIsEnraged = true; - DoScriptText(EMOTE_BOSS_GENERIC_FRENZY, m_creature); - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FRENZY : SPELL_FRENZY_H); + m_fSpikeXY[0][0] = m_fBaseX+(SPIKE_DISTANCE*m_uiCrystalSpikesCount*cos(m_fBaseO)); + m_fSpikeXY[0][1] = m_fBaseY+(SPIKE_DISTANCE*m_uiCrystalSpikesCount*sin(m_fBaseO)); + m_fSpikeXY[1][0] = m_fBaseX-(SPIKE_DISTANCE*m_uiCrystalSpikesCount*cos(m_fBaseO)); + m_fSpikeXY[1][1] = m_fBaseY-(SPIKE_DISTANCE*m_uiCrystalSpikesCount*sin(m_fBaseO)); + m_fSpikeXY[2][0] = m_fBaseX+(SPIKE_DISTANCE*m_uiCrystalSpikesCount*cos(m_fBaseO-(M_PI/2))); + m_fSpikeXY[2][1] = m_fBaseY+(SPIKE_DISTANCE*m_uiCrystalSpikesCount*sin(m_fBaseO-(M_PI/2))); + m_fSpikeXY[3][0] = m_fBaseX-(SPIKE_DISTANCE*m_uiCrystalSpikesCount*cos(m_fBaseO-(M_PI/2))); + m_fSpikeXY[3][1] = m_fBaseY-(SPIKE_DISTANCE*m_uiCrystalSpikesCount*sin(m_fBaseO-(M_PI/2))); + + for (uint8 i = 0; i < 4; i++) + Creature* Spike = m_creature->SummonCreature(MOB_CRYSTAL_SPIKE, m_fSpikeXY[i][0], m_fSpikeXY[i][1], m_fBaseZ, 0, TEMPSUMMON_TIMED_DESPAWN, 7000); + + if (++m_uiCrystalSpikesCount >= 13) + m_bIsCrystalSpikes = false; + + m_uiCrystalSpikesTimer = 0.2*IN_MILLISECONDS; } + else + m_uiCrystalSpikesTimer -= uiDiff; + } + + if (!m_bIsFrenzy && (m_creature->GetHealthPercent() < 25.0f)) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_FRENZY_N : SPELL_FRENZY_H); + m_bIsFrenzy = true; } if (m_uiTrampleTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TRAMPLE : SPELL_TRAMPLE_H); - m_uiTrampleTimer = urand(10000, 35000); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TRAMPLE_N : SPELL_TRAMPLE_H); + m_uiTrampleTimer = urand(10*IN_MILLISECONDS, 35*IN_MILLISECONDS); } else m_uiTrampleTimer -= uiDiff; - if (m_uiSpellReflectTimer < uiDiff) + if (m_uiReflectionTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_REFLECTION); - m_uiSpellReflectTimer = urand(25000, 40000); + DoScriptText(SAY_REFLECT, m_creature); + DoCast(m_creature, SPELL_SPELL_REFLECTION); + m_uiReflectionTimer = 15*IN_MILLISECONDS; } else - m_uiSpellReflectTimer -= uiDiff; + m_uiReflectionTimer -= uiDiff; - if (m_uiCrystalSpikeTimer < uiDiff) + if (m_uiSpellCrystalSpikesTimer < uiDiff) { - DoScriptText(SAY_ICESPIKE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_CRYSTAL_SPIKES); - m_uiCrystalSpikeTimer = urand(15000, 30000); + DoScriptText(SAY_CRYSTAL_SPIKES, m_creature); + m_bIsCrystalSpikes = true; + m_uiCrystalSpikesCount = 1; + m_uiCrystalSpikesTimer = 0; + m_fBaseX = m_creature->GetPositionX(); + m_fBaseY = m_creature->GetPositionY(); + m_fBaseZ = m_creature->GetPositionZ(); + m_fBaseO = m_creature->GetOrientation(); + m_uiSpellCrystalSpikesTimer = 20*IN_MILLISECONDS; } else - m_uiCrystalSpikeTimer -= uiDiff; + m_uiSpellCrystalSpikesTimer -= uiDiff; - if (!m_bIsRegularMode) + if (!m_bIsRegularMode && (m_uiSummonTanglerTimer < uiDiff)) { - if (m_uiTanglerTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_TANGLER_H); - m_uiTanglerTimer = urand(15000, 25000); - } - else - m_uiTanglerTimer -= uiDiff; + Creature* CrystallineTangler = m_creature->SummonCreature(MOB_CRYSTALLINE_TANGLER, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_OOC_DESPAWN, 10000); + if (CrystallineTangler) + if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + CrystallineTangler->AI()->AttackStart(target); + + m_uiSummonTanglerTimer = 17*IN_MILLISECONDS; } + else + m_uiSummonTanglerTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -163,15 +199,104 @@ struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI CreatureAI* GetAI_boss_ormorok(Creature* pCreature) { - return new boss_ormorokAI(pCreature); + return new boss_ormorokAI (pCreature); +} + +struct MANGOS_DLL_DECL mob_crystal_spikeAI : public Scripted_NoMovementAI +{ + mob_crystal_spikeAI(Creature *pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + + uint32 m_uiCrystallSpikeDamageTimer; + uint32 m_uiCrystalSpikePreVisualTimer; + + void Reset() + { + m_uiCrystallSpikeDamageTimer = 3.7*IN_MILLISECONDS; + m_uiCrystalSpikePreVisualTimer = 1*IN_MILLISECONDS; + m_creature->SetLevel(80); // + m_creature->setFaction(16); //Walkaround to be independent from data in DB + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiCrystalSpikePreVisualTimer < uiDiff) + { + DoCast(m_creature, SPELL_CRYSTAL_SPIKE_PREVISUAL); + m_uiCrystalSpikePreVisualTimer = 10*IN_MILLISECONDS; + } + else + m_uiCrystalSpikePreVisualTimer -= uiDiff; + + if (m_uiCrystallSpikeDamageTimer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_CRYSTALL_SPIKE_DAMAGE_N : SPELL_CRYSTALL_SPIKE_DAMAGE_H); + m_uiCrystallSpikeDamageTimer = 10*IN_MILLISECONDS; + } + else + m_uiCrystallSpikeDamageTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_crystal_spike(Creature* pCreature) +{ + return new mob_crystal_spikeAI (pCreature); +} + +struct MANGOS_DLL_DECL mob_crystalline_tanglerAI : public ScriptedAI +{ + mob_crystalline_tanglerAI(Creature *pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiRootsTimer; + + void Reset() + { + m_uiRootsTimer = 1*IN_MILLISECONDS; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiRootsTimer < uiDiff) + { + if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(target, SPELL_ROOTS, true); + m_uiRootsTimer = 15*IN_MILLISECONDS; + } + else + m_uiRootsTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_crystalline_tangler(Creature* pCreature) +{ + return new mob_crystalline_tanglerAI (pCreature); } void AddSC_boss_ormorok() { - Script *newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name= "boss_ormorok"; + pNewScript->GetAI = &GetAI_boss_ormorok; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name= "mob_crystal_spike"; + pNewScript->GetAI = &GetAI_mob_crystal_spike; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_ormorok"; - newscript->GetAI = &GetAI_boss_ormorok; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name= "mob_crystalline_tangler"; + pNewScript->GetAI = &GetAI_mob_crystalline_tangler; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/nexus/boss_telestra.cpp b/scripts/northrend/nexus/nexus/boss_telestra.cpp index 2f26dc7a98..bfc389afe5 100644 --- a/scripts/northrend/nexus/nexus/boss_telestra.cpp +++ b/scripts/northrend/nexus/nexus/boss_telestra.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -75,37 +75,43 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI { boss_telestraAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_nexus*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_nexus* m_pInstance; bool m_bIsRegularMode; uint8 m_uiPhase; uint8 m_uiCloneDeadCount; + uint32 m_uiPersonalityTimer; uint32 m_uiFirebombTimer; uint32 m_uiIceNovaTimer; uint32 m_uiGravityWellTimer; - void Reset() + bool m_bCanCheckAchiev; + + void Reset() override { m_uiPhase = PHASE_1; m_uiCloneDeadCount = 0; + m_uiPersonalityTimer = 0; m_uiFirebombTimer = urand(2000, 4000); m_uiIceNovaTimer = urand(8000, 12000); m_uiGravityWellTimer = urand(15000, 25000); + + 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)) { @@ -117,12 +123,15 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_TELESTRA, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -130,23 +139,30 @@ 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: { ++m_uiCloneDeadCount; + // After the first clone from each split phase is dead start the achiev timer + if (m_uiCloneDeadCount == 1 || m_uiCloneDeadCount == 4) + { + m_bCanCheckAchiev = true; + m_uiPersonalityTimer = 0; + } + if (m_uiCloneDeadCount == 3 || m_uiCloneDeadCount == 6) { m_creature->RemoveAurasDueToSpell(SPELL_SUMMON_CLONES); @@ -156,6 +172,14 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI DoScriptText(SAY_MERGE, m_creature); + // Check if it took longer than 5 sec + if (m_uiPersonalityTimer > 5000) + { + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_SPLIT_PERSONALITY, false); + } + m_bCanCheckAchiev = false; + m_uiPhase = m_uiCloneDeadCount == 3 ? PHASE_3 : PHASE_4; } break; @@ -166,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; @@ -176,12 +200,15 @@ 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; - switch(m_uiPhase) + if (m_bCanCheckAchiev) + m_uiPersonalityTimer += uiDiff; + + switch (m_uiPhase) { case PHASE_1: case PHASE_3: @@ -251,10 +278,10 @@ CreatureAI* GetAI_boss_telestra(Creature* pCreature) void AddSC_boss_telestra() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_telestra"; - newscript->GetAI = &GetAI_boss_telestra; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_telestra"; + pNewScript->GetAI = &GetAI_boss_telestra; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/nexus/instance_nexus.cpp b/scripts/northrend/nexus/nexus/instance_nexus.cpp index 64c30401b8..9ae03df1db 100644 --- a/scripts/northrend/nexus/nexus/instance_nexus.cpp +++ b/scripts/northrend/nexus/nexus/instance_nexus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,232 +24,425 @@ EndScriptData */ #include "precompiled.h" #include "nexus.h" -bool GOHello_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; case GO_CONTAINMENT_SPHERE_ORMOROK: pInstance->SetData(TYPE_ORMOROK, SPECIAL); break; } - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + if (Creature *pCaster = GetClosestCreatureWithEntry(pGo, NPC_BREATH_CASTER, 15.0f)) + pCaster->ForcedDespawn(); + + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); return false; } -struct MANGOS_DLL_DECL instance_nexus : public ScriptedInstance +instance_nexus::instance_nexus(Map* pMap) : ScriptedInstance(pMap) { - instance_nexus(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; + Initialize(); - uint64 m_uiAnomalusGUID; - uint64 m_uiKeristrazaGUID; + for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS; ++i) + m_abAchievCriteria[i] = false; +} - uint64 m_uiTelestrasContainmentSphereGUID; - uint64 m_uiAnomalusContainmentSphereGUID; - uint64 m_uiOrmoroksContainmentSphereGUID; +void instance_nexus::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_nexus::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + case GO_CONTAINMENT_SPHERE_TELESTRA: + if (m_auiEncounter[TYPE_TELESTRA] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; + case GO_CONTAINMENT_SPHERE_ANOMALUS: + if (m_auiEncounter[TYPE_ANOMALUS] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; + case GO_CONTAINMENT_SPHERE_ORMOROK: + if (m_auiEncounter[TYPE_ORMOROK] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_nexus::OnCreatureCreate(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_KERISTRASZA) + m_mNpcEntryGuidStore[NPC_KERISTRASZA] = pCreature->GetObjectGuid(); +} - m_uiAnomalusGUID = 0; - m_uiKeristrazaGUID = 0; +uint32 instance_nexus::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} - m_uiTelestrasContainmentSphereGUID = 0; - m_uiAnomalusContainmentSphereGUID = 0; - m_uiOrmoroksContainmentSphereGUID = 0; +void instance_nexus::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_TELESTRA: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_SPLIT_PERSONALITY, true); + if (uiData == DONE) + DoToggleGameObjectFlags(GO_CONTAINMENT_SPHERE_TELESTRA, GO_FLAG_NO_INTERACT, false); + break; + case TYPE_ANOMALUS: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_CHAOS_THEORY, true); + if (uiData == DONE) + DoToggleGameObjectFlags(GO_CONTAINMENT_SPHERE_ANOMALUS, GO_FLAG_NO_INTERACT, false); + break; + case TYPE_ORMOROK: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoToggleGameObjectFlags(GO_CONTAINMENT_SPHERE_ORMOROK, GO_FLAG_NO_INTERACT, false); + break; + case TYPE_KERISTRASZA: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + m_sIntenseColdFailPlayers.clear(); + break; + case TYPE_INTENSE_COLD_FAILED: + // Insert the players who fail the achiev and haven't been already inserted in the set + if (m_sIntenseColdFailPlayers.find(uiData) == m_sIntenseColdFailPlayers.end()) + m_sIntenseColdFailPlayers.insert(uiData); + break; + default: + script_error_log("Instance Nexus: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; } - bool IsEncounterInProgress() const + if (m_auiEncounter[TYPE_TELESTRA] == SPECIAL && m_auiEncounter[TYPE_ANOMALUS] == SPECIAL && m_auiEncounter[TYPE_ORMOROK] == SPECIAL) { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + // release Keristrasza from her prison here + m_auiEncounter[TYPE_KERISTRASZA] = SPECIAL; + + Creature* pCreature = GetSingleCreatureFromStorage(NPC_KERISTRASZA); + if (pCreature && pCreature->isAlive()) { - if (m_auiEncounter[i] == IN_PROGRESS) - return true; + if (pCreature->isAlive()) + { + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + pCreature->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON); + } } + } - return false; + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} + +void instance_nexus::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < MAX_SPECIAL_ACHIEV_CRITS) + m_abAchievCriteria[uiType] = bIsMet; +} - void OnObjectCreate(GameObject* pGo) +bool instance_nexus::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) { - switch(pGo->GetEntry()) - { - case GO_CONTAINMENT_SPHERE_TELESTRA: - m_uiTelestrasContainmentSphereGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - case GO_CONTAINMENT_SPHERE_ANOMALUS: - m_uiAnomalusContainmentSphereGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - case GO_CONTAINMENT_SPHERE_ORMOROK: - m_uiOrmoroksContainmentSphereGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - } + case ACHIEV_CRIT_CHAOS_THEORY: + return m_abAchievCriteria[TYPE_ACHIEV_CHAOS_THEORY]; + case ACHIEV_CRIT_SPLIT_PERSONALITY: + return m_abAchievCriteria[TYPE_ACHIEV_SPLIT_PERSONALITY]; + case ACHIEV_CRIT_INTENSE_COLD: + // Return true if not found in the set + return m_sIntenseColdFailPlayers.find(pSource->GetGUIDLow()) == m_sIntenseColdFailPlayers.end(); + + default: + return false; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_nexus::Load(const char* chrIn) +{ + if (!chrIn) { - switch(pCreature->GetEntry()) - { - case NPC_ANOMALUS: - m_uiAnomalusGUID = pCreature->GetGUID(); - break; - case NPC_KERISTRASZA: - m_uiKeristrazaGUID = pCreature->GetGUID(); - break; - } + OUT_LOAD_INST_DATA_FAIL; + return; } - uint64 GetData64(uint32 uiType) + 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) { - switch(uiType) - { - case NPC_ANOMALUS: - return m_uiAnomalusGUID; - } + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } - return 0; + OUT_LOAD_INST_DATA_COMPLETE; +} + +InstanceData* GetInstanceData_instance_nexus(Map* pMap) +{ + return new instance_nexus(pMap); +} + +/*#### +# boss_commander_kolurg +####*/ +// both commanders share this enum +enum +{ + SAY_AGGRO = -1576024, // need correct text + SAY_KILL = -1576025, // need correct text + SAY_DEATH = -1576026, // need correct text + + SPELL_BATTLE_SHOUT = 31403, // Increases the melee attack power of nearby friendly targets for 2 min. + SPELL_CHARGE = 60067, // Charges an enemy, inflicting normal damage plus 75 and stuns the opponent for 2 sec. + SPELL_FRIGHTENING_SHOUT = 19134, // Shouts at nearby enemies causing them to flee in fear for 6 sec + SPELL_WHIRLWIND_1 = 38618, // triggers spell 38619 Attacks nearby enemies in a whirlwind of steel that lasts until cancelled. and inflicts double damage + SPELL_WHIRLWIND_2 = 38619 // Attacks nearby enemies in a whirlwind of steel that inflicts 200% of weapon damage. +}; + +struct MANGOS_DLL_DECL boss_commander_kolurgAI : public ScriptedAI // triggers spell 38619 Attacks nearby enemies in a whirlwind of steel that lasts until cancelled. and inflicts double damage +{ + boss_commander_kolurgAI(Creature *pCreature) : ScriptedAI(pCreature) + { + //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + //m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); } - uint32 GetData(uint32 uiType) + //ScriptedInstance* m_pInstance; + //bool m_bIsRegularMode; + + uint32 SPELL_BATTLE_SHOUT_Timer; + uint32 SPELL_CHARGE_Timer; + uint32 SPELL_FRIGHTENING_SHOUT_Timer; + uint32 SPELL_WHIRLWIND_1_Timer; + uint32 SPELL_WHIRLWIND_2_Timer; + + void Reset() { - switch(uiType) - { - case TYPE_TELESTRA: - return m_auiEncounter[0]; - case TYPE_ANOMALUS: - return m_auiEncounter[1]; - case TYPE_ORMOROK: - return m_auiEncounter[2]; - case TYPE_KERISTRASZA: - return m_auiEncounter[3]; - } + SPELL_BATTLE_SHOUT_Timer = 3000; // needs adjusting + SPELL_CHARGE_Timer = 2000; // needs adjusting + SPELL_FRIGHTENING_SHOUT_Timer = 2000; // needs adjusting + SPELL_WHIRLWIND_1_Timer = 0; // THIS IS NOT RIGHT JUST A PLACEHOLDER FOR NOW + SPELL_WHIRLWIND_2_Timer = 2000; // needs adjusting + - return 0; + //if (m_pInstance) + //m_pInstance->SetData(TYPE_COMMANDER_KOLURG, NOT_STARTED); } - void SetData(uint32 uiType, uint32 uiData) + void EnterCombat(Unit* who) override { - debug_log("SD2: Instance Nexus: SetData received for type %u with data %u", uiType, uiData); + /* DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_COMMANDER_KOLURG, IN_PROGRESS);*/ + } - switch(uiType) + //void AttackStart(Unit* who) {} + + //void MoveInLineOfSight(Unit* who) override { } + + void KilledUnit(Unit *victim) + { + //DoScriptText(SAY_KILL, m_creature); + } + + void JustDied(Unit* killer) + { + //DoScriptText(SAY_DEATH, m_creature); + + //if (m_pInstance) + //m_pInstance->SetData(TYPE_COMMANDER_KOLURG, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (SPELL_BATTLE_SHOUT_Timer < diff) { - case TYPE_TELESTRA: - m_auiEncounter[0] = uiData; - if (uiData == DONE) - { - if (GameObject* pGo = instance->GetGameObject(m_uiTelestrasContainmentSphereGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - } - break; - case TYPE_ANOMALUS: - m_auiEncounter[1] = uiData; - if (uiData == DONE) - { - if (GameObject* pGo = instance->GetGameObject(m_uiAnomalusContainmentSphereGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - } - break; - case TYPE_ORMOROK: - m_auiEncounter[2] = uiData; - if (uiData == DONE) - { - if (GameObject* pGo = instance->GetGameObject(m_uiOrmoroksContainmentSphereGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - } - break; - case TYPE_KERISTRASZA: - m_auiEncounter[3] = uiData; - break; - default: - error_log("SD2: Instance Nexus: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); - break; - } + DoCastSpellIfCan(m_creature, SPELL_BATTLE_SHOUT); + SPELL_BATTLE_SHOUT_Timer = 3000 + rand()%5000; + }else SPELL_BATTLE_SHOUT_Timer -= diff; - if (m_auiEncounter[0] == SPECIAL && m_auiEncounter[1] == SPECIAL && m_auiEncounter[2] == SPECIAL) + if (SPELL_CHARGE_Timer < diff) // this spell needs to be a distance check on victims in distance not a timer on victim { - // release Keristrasza from her prison here - m_auiEncounter[3] = SPECIAL; + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHARGE); + SPELL_CHARGE_Timer = 2000 + rand()%5000; + }else SPELL_CHARGE_Timer -= diff; - if (Creature* pCreature = instance->GetCreature(m_uiKeristrazaGUID)) - { - if (pCreature->isAlive()) - pCreature->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON); - } - } + if (SPELL_FRIGHTENING_SHOUT_Timer < diff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT); + SPELL_FRIGHTENING_SHOUT_Timer = 2000 + rand()%5000; + }else SPELL_FRIGHTENING_SHOUT_Timer -= diff; - if (uiData == DONE) + if (SPELL_WHIRLWIND_2_Timer < diff) { - OUT_SAVE_INST_DATA; + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WHIRLWIND_2); + SPELL_WHIRLWIND_2_Timer = 2000 + rand()%5000; + }else SPELL_WHIRLWIND_2_Timer -= diff; + + DoMeleeAttackIfReady(); + } +}; - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; +CreatureAI* GetAI_boss_commander_kolurg(Creature* pCreature) +{ + return new boss_commander_kolurgAI (pCreature); +} - strInstData = saveStream.str(); +/*#### +# boss_commander_stoutbeard +####*/ - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } +struct MANGOS_DLL_DECL boss_commander_stoutbeardAI : public ScriptedAI +{ + boss_commander_stoutbeardAI(Creature *pCreature) : ScriptedAI(pCreature) + { + //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + //m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); } - const char* Save() + //ScriptedInstance* m_pInstance; + //bool m_bIsRegularMode; + + uint32 SPELL_BATTLE_SHOUT_Timer; + uint32 SPELL_CHARGE_Timer; + uint32 SPELL_FRIGHTENING_SHOUT_Timer; + uint32 SPELL_WHIRLWIND_1_Timer; + uint32 SPELL_WHIRLWIND_2_Timer; + + void Reset() { - return strInstData.c_str(); + SPELL_BATTLE_SHOUT_Timer = 3000; // needs adjusting + SPELL_CHARGE_Timer = 2000; // needs adjusting + SPELL_FRIGHTENING_SHOUT_Timer = 2000; // needs adjusting + SPELL_WHIRLWIND_1_Timer = 0; // THIS IS NOT RIGHT JUST A PLACEHOLDER FOR NOW + SPELL_WHIRLWIND_2_Timer = 2000; // needs adjusting + + + //if (m_pInstance) + //m_pInstance->SetData(TYPE_COMMANDER_STOUTBEARD, NOT_STARTED); } - void Load(const char* chrIn) + void EnterCombat(Unit* who) override { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; + /* DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_COMMANDER_STOUTBEARD, IN_PROGRESS);*/ + } + + //void AttackStart(Unit* who) {} + + //void MoveInLineOfSight(Unit* who) override { } + + void KilledUnit(Unit *victim) + { + //DoScriptText(SAY_KILL, m_creature); + } + + void JustDied(Unit* killer) + { + //DoScriptText(SAY_DEATH, m_creature); + + //if (m_pInstance) + //m_pInstance->SetData(TYPE_COMMANDER_STOUTBEARD, DONE); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - } - OUT_LOAD_INST_DATA(chrIn); + if (SPELL_BATTLE_SHOUT_Timer < diff) + { + DoCastSpellIfCan(m_creature, SPELL_BATTLE_SHOUT); + SPELL_BATTLE_SHOUT_Timer = 3000 + rand()%5000; + }else SPELL_BATTLE_SHOUT_Timer -= diff; + + if (SPELL_CHARGE_Timer < diff) // this spell needs to be a distance check on victims in distance not a timer on victim + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHARGE); + SPELL_CHARGE_Timer = 2000 + rand()%5000; + }else SPELL_CHARGE_Timer -= diff; - std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; + if (SPELL_FRIGHTENING_SHOUT_Timer < diff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT); + SPELL_FRIGHTENING_SHOUT_Timer = 2000 + rand()%5000; + }else SPELL_FRIGHTENING_SHOUT_Timer -= diff; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (SPELL_WHIRLWIND_2_Timer < diff) { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + DoCastSpellIfCan(m_creature->getVictim(), SPELL_WHIRLWIND_2); + SPELL_WHIRLWIND_2_Timer = 2000 + rand()%5000; + }else SPELL_WHIRLWIND_2_Timer -= diff; - OUT_LOAD_INST_DATA_COMPLETE; + DoMeleeAttackIfReady(); } }; -InstanceData* GetInstanceData_instance_nexus(Map* pMap) +CreatureAI* GetAI_boss_commander_stoutbeard(Creature* pCreature) { - return new instance_nexus(pMap); + return new boss_commander_stoutbeardAI (pCreature); } void AddSC_instance_nexus() { - Script* newscript; - - newscript = new Script; - newscript->Name = "instance_nexus"; - newscript->GetInstanceData = &GetInstanceData_instance_nexus; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_containment_sphere"; - newscript->pGOHello = &GOHello_go_containment_sphere; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_nexus"; + pNewScript->GetInstanceData = &GetInstanceData_instance_nexus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_containment_sphere"; + pNewScript->pGOUse = &GOUse_go_containment_sphere; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_commander_stoutbeard"; + pNewScript->GetAI = &GetAI_boss_commander_stoutbeard; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_commander_kolurg"; + pNewScript->GetAI = &GetAI_boss_commander_kolurg; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/nexus/nexus.h b/scripts/northrend/nexus/nexus/nexus.h index 9aabb9ece3..bad12fee2b 100644 --- a/scripts/northrend/nexus/nexus/nexus.h +++ b/scripts/northrend/nexus/nexus/nexus.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,21 +8,65 @@ enum { MAX_ENCOUNTER = 4, + MAX_SPECIAL_ACHIEV_CRITS = 2, TYPE_TELESTRA = 0, TYPE_ANOMALUS = 1, TYPE_ORMOROK = 2, TYPE_KERISTRASZA = 3, + TYPE_INTENSE_COLD_FAILED = 4, + + TYPE_ACHIEV_CHAOS_THEORY = 0, + TYPE_ACHIEV_SPLIT_PERSONALITY = 1, NPC_TELESTRA = 26731, NPC_ANOMALUS = 26763, NPC_ORMOROK = 26794, NPC_KERISTRASZA = 26723, + NPC_COMM_KOLURG = 26798, + NPC_COMM_STOUTBEARD = 26796, + + NPC_BREATH_CASTER = 27048, + GO_CONTAINMENT_SPHERE_TELESTRA = 188526, GO_CONTAINMENT_SPHERE_ANOMALUS = 188527, GO_CONTAINMENT_SPHERE_ORMOROK = 188528, - SPELL_FROZEN_PRISON = 47854 // may not be correct spell + SPELL_FROZEN_PRISON = 47854, + + ACHIEV_CRIT_CHAOS_THEORY = 7316, // Anomalus, achiev 2037 + ACHIEV_CRIT_INTENSE_COLD = 7315, // Keristrasza, achiev 2036 + ACHIEV_CRIT_SPLIT_PERSONALITY = 7577, // Telestra, achiev 2150 }; + +class MANGOS_DLL_DECL instance_nexus : public ScriptedInstance +{ + public: + instance_nexus(Map* pMap); + + void Initialize() override; + + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + 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*/) 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; + + bool m_abAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; + + std::set m_sIntenseColdFailPlayers; +}; + #endif diff --git a/scripts/northrend/nexus/oculus/boss_drakos.cpp b/scripts/northrend/nexus/oculus/boss_drakos.cpp new file mode 100644 index 0000000000..973209f9af --- /dev/null +++ b/scripts/northrend/nexus/oculus/boss_drakos.cpp @@ -0,0 +1,295 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * Copyright (C) 2011 - 2013 MangosR2 + * This program is free software; you can redistribute it and/or modify + * 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_Drakos +SD%Complete: 80% +SDComment: +SDAuthor: +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" + +enum +{ + SAY_AGGRO = -1578031, + SAY_KILL_1 = -1578032, + SAY_KILL_2 = -1578033, + SAY_KILL_3 = -1578034, + SAY_DEATH = -1578035, + SAY_PULL_1 = -1578036, + SAY_PULL_2 = -1578037, + SAY_PULL_3 = -1578038, + SAY_PULL_4 = -1578039, + SAY_STOMP_1 = -1578040, + SAY_STOMP_2 = -1578041, + SAY_STOMP_3 = -1578042, + + SPELL_MAGIC_PULL = 51336, + SPELL_MAGIC_PULL_EFFECT = 50770, + SPELL_THUNDERING_STOMP_N = 50774, + SPELL_THUNDERING_STOMP_H = 59370, + SPELL_UNSTABLE_SPHERE_PASSIVE = 50756, + SPELL_UNSTABLE_SPHERE_PULSE = 50757, + SPELL_UNSTABLE_SPHERE_TIMER = 50758, + SPELL_UNSTABLE_SPHERE_EXPLODE = 50759, + + NPC_UNSTABLE_SPHERE = 28166 +}; + +/**** +* Boss_Drakos +****/ + +struct MANGOS_DLL_DECL boss_drakosAI : public ScriptedAI +{ + boss_drakosAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiMagicPullTimer ; + uint32 m_uiStompTimer ; + uint32 m_uiBombSummonTimer ; + + bool MagicPull80; + bool MagicPull60; + bool MagicPull40; + bool MagicPull20; + + void Reset() + { + m_uiMagicPullTimer = urand(12000, 15000); + m_uiStompTimer = urand(3000, 6000); + m_uiBombSummonTimer = 7000; + + if (m_pInstance && m_creature->isAlive()) + m_pInstance->SetData(TYPE_DRAKOS, NOT_STARTED); + + MagicPull80 = false; + MagicPull60 = false; + MagicPull40 = false; + MagicPull20 = false; + } + + void Aggro(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DRAKOS, IN_PROGRESS); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DRAKOS, DONE); + } + + void KilledUnit(Unit *victim) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_KILL_1, m_creature); break; + case 1: DoScriptText(SAY_KILL_2, m_creature); break; + case 2: DoScriptText(SAY_KILL_3, m_creature); break; + } + } + + void SpellHitTarget(Unit *pTarget, const SpellEntry *spell) + { + if (spell->Id == SPELL_MAGIC_PULL) + if (pTarget->GetTypeId() == TYPEID_PLAYER) + DoCast(pTarget, SPELL_MAGIC_PULL_EFFECT, true); + } + +///-> magic pull bombing + /*void MagicPullBombing + { + uint8 BombCount = 5; + for(uint32 i = 0; i < BombCount; i++) + DoSpawnCreature(NPC_UNSTABLE_SPHERE, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + }*/ + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBombSummonTimer < uiDiff) + { + uint8 BombCount = urand(1, m_bIsRegularMode ? 4 : 6); + for(uint32 i = 0; i < BombCount; i++) + DoSpawnCreature(NPC_UNSTABLE_SPHERE, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiBombSummonTimer = urand(5000, 6000); + } + else + m_uiBombSummonTimer -= uiDiff; + + if (m_uiStompTimer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_THUNDERING_STOMP_N : SPELL_THUNDERING_STOMP_H); + m_uiStompTimer = urand(11000, 18000); + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_STOMP_1, m_creature); break; + case 1: DoScriptText(SAY_STOMP_2, m_creature); break; + case 2: DoScriptText(SAY_STOMP_3, m_creature); break; + } + } + else + m_uiStompTimer -= uiDiff ; + + if (m_uiMagicPullTimer < uiDiff) + { + if (!MagicPull80 && m_creature->GetHealthPercent() < 80.0f) // 80% hp + { + DoScriptText(SAY_PULL_1, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MAGIC_PULL); +///-> summons lots of spheres at once each pull need more data + MagicPull80 = true; + return; + } + if (!MagicPull60 && m_creature->GetHealthPercent() < 60.0f) // 60% hp + { + DoScriptText(SAY_PULL_2, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MAGIC_PULL); +///-> summons lots of spheres at once each pull need more data + MagicPull60 = true; + return; + } + if (!MagicPull40 && m_creature->GetHealthPercent() < 40.0f) // 40% hp + { + DoScriptText(SAY_PULL_3, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MAGIC_PULL); +///-> summons lots of spheres at once each pull need more data + MagicPull40 = true; + return; + } + if (!MagicPull20 && m_creature->GetHealthPercent() < 20.0f) // 20% hp + { + DoScriptText(SAY_PULL_4, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MAGIC_PULL); +///-> summons lots of spheres at once each pull need more data + MagicPull20 = true; + return; + } + } + else + m_uiMagicPullTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_drakos(Creature* pCreature) +{ + return new boss_drakosAI (pCreature); +} + +/***** +* npc_unstable_sphere +*****/ + +#define X 960 +#define Y 1050 +#define Z 360 +#define PI 3.14 + +struct MANGOS_DLL_DECL npc_unstable_sphereAI : public ScriptedAI +{ + npc_unstable_sphereAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiPulseTimer; + + void MoveToPointInCircle(uint32 id) + { + float x, y, z, r, angle; + angle = urand(0, 36000) / 100; + r = urand(20, 320) / 10; + (angle <= PI) ? y = Y + (sin(angle) * r) : y = Y - (sin(angle) * r); + (angle >= (PI / 2) && angle <= (PI * 3 / 2)) ? x = X - (cos(angle) * r) : x = X + (cos(angle) * r); + z = Z; + m_creature->GetMotionMaster()->MovePoint(id, x, y, z); + } + + void Reset() + { + m_creature->SetLevitate(true); + MoveToPointInCircle(1); + m_creature->setFaction(14); + DoCast(m_creature, SPELL_UNSTABLE_SPHERE_PASSIVE, true); + DoCast(m_creature, SPELL_UNSTABLE_SPHERE_TIMER, true); + m_uiPulseTimer = 3000; + m_creature->ForcedDespawn(19000); + } + + void AttackStart(Unit* pWho) override + { + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_DRAKOS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiPulseTimer < uiDiff) + { + DoCast(m_creature, SPELL_UNSTABLE_SPHERE_PULSE, true); + m_uiPulseTimer = 3000; + } + else + m_uiPulseTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_unstable_sphere(Creature* pCreature) +{ + return new npc_unstable_sphereAI (pCreature); +} + +void AddSC_boss_drakos() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_drakos"; + pNewScript->GetAI = &GetAI_boss_drakos; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_unstable_sphere"; + pNewScript->GetAI = &GetAI_npc_unstable_sphere; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/boss_eregos.cpp b/scripts/northrend/nexus/oculus/boss_eregos.cpp new file mode 100644 index 0000000000..9b3c8df596 --- /dev/null +++ b/scripts/northrend/nexus/oculus/boss_eregos.cpp @@ -0,0 +1,347 @@ +/* Copyright (C) 2006 - 2013 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_Eregos +SD%Complete: 60% +SDComment: +SDAuthor: originally from TC, reworked by MaxXx2021 Aka Mioka, corrected by /dev/rsa +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" + +enum Spells +{ + SAY_SPAWN = -1578010, + SAY_AGGRO = -1578011, + SAY_ARCANE_SHIELD = -1578012, + SAY_FIRE_SHIELD = -1578013, + SAY_NATURE_SHIELD = -1578014, + SAY_FRENZY = -1578015, + SAY_KILL_1 = -1578016, + SAY_KILL_2 = -1578017, + SAY_KILL_3 = -1578018, + SAY_DEATH = -1578019, + + SPELL_ARCANE_BARRAGE_N = 50804, + SPELL_ARCANE_BARRAGE_H = 59381, + SPELL_ARCANE_VOLLEY_N = 51153, + SPELL_ARCANE_VOLLEY_H = 59382, + SPELL_ENRAGED_ASSAULT = 51170, + SPELL_SUMMON_DRAKE = 51175, + SPELL_PLANAR_ANOMALIES = 57959, + SPELL_PLANAR_ANOMALIES_SUMMON = 57963, //need spell script on m_creature 27656 + SPELL_PLANAR_ANOMALIES_VISUAL = 57971, + SPELL_PLANAR_SHIFT = 51162, + SPELL_PLANAR_ANOMALIES_DMG = 57976, + + NPC_PLANAR_ANOMALY = 30879, + NPC_DRAGON = 28276 +}; + +struct MANGOS_DLL_DECL boss_eregosAI : public ScriptedAI +{ + boss_eregosAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_oculus*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_oculus* m_pInstance; + bool m_bIsRegularMode; + + uint32 uiArcaneBarrageTimer; + uint32 uiArcaneVolleyTimer; + uint32 uiEnragedAssaultTimer; + uint32 uiSummonTimer; + + uint8 m_uiSummonCount; + std::list DragonsEntryList; + + bool m_bIsMove; + + void Reset() + { + m_creature->SetVisibility(VISIBILITY_ON); + if (m_pInstance) + { + m_pInstance->SetData(TYPE_EREGOS, NOT_STARTED); + if(m_pInstance->GetData(TYPE_UROM) == DONE) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + else + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + m_creature->SetLevitate(true); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_0, 50331648); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 50331648); + uiArcaneBarrageTimer = 12000; + uiArcaneVolleyTimer = 17000; + uiEnragedAssaultTimer = 24000; + uiSummonTimer = 15000; + m_uiSummonCount = 0; + m_bIsMove = true; + DragonsEntryList.clear(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if(pWho->GetTypeId() == TYPEID_PLAYER + && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) + && !((Player*)pWho)->isGameMaster() + && m_creature->IsWithinDistInMap(pWho, 100.0f) + && pWho->GetVehicle() + && m_pInstance->GetData(TYPE_UROM) == DONE) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EREGOS, FAIL); + } + + void Aggro(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_EREGOS, IN_PROGRESS); + } + + void KilledUnit(Unit *victim) + { + uint8 uiText = urand(0, 2); + switch (uiText) + { + case 0: DoScriptText(SAY_KILL_1, m_creature); break; + case 1: DoScriptText(SAY_KILL_2, m_creature); break; + case 2: DoScriptText(SAY_KILL_3, m_creature); break; + } + } + + void JustDied(Unit* killer) + { + m_creature->GetMap()->CreatureRelocation(m_creature, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()-100.0f, 0); + m_creature->MonsterMoveWithSpeed(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()-100.0f, 26); + DoScriptText(SAY_DEATH, m_creature); + if (m_pInstance) + { + m_pInstance->SetData(TYPE_EREGOS, DONE); + + DragonsEntryList.clear(); + GetCreatureListWithEntryInGrid(DragonsEntryList, m_creature, NPC_RED_DRAGON, 500.0f); + if (DragonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEV_RUBY_VOID, true); + DragonsEntryList.clear(); + + GetCreatureListWithEntryInGrid(DragonsEntryList, m_creature, NPC_GREEN_DRAGON, 500.0f); + if (DragonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEV_EMERALD_VOID, true); + DragonsEntryList.clear(); + + GetCreatureListWithEntryInGrid(DragonsEntryList, m_creature, NPC_YELLOW_DRAGON, 500.0f); + if (DragonsEntryList.empty()) + m_pInstance->SetSpecialAchievementCriteria(ACHIEV_AMBER_VOID, true); + DragonsEntryList.clear(); + } + + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + if(m_creature->HasAura(SPELL_PLANAR_SHIFT)) + damage = 0; + } + + void JustSummoned(Creature* pSummoned) override + { + if(pSummoned->GetEntry() == NPC_PLANAR_ANOMALY) + { + pSummoned->SetDisplayId(11686); + pSummoned->SetInCombatWithZone(); + if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + + if(pSummoned->GetEntry() == NPC_DRAGON) + { + pSummoned->SetInCombatWithZone(); + if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void AttackStart(Unit* who) + { + if (!who) + return; + + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void SummonAnomalies() + { + ThreatList t_list = m_creature->getThreatManager().getThreatList(); + if (t_list.size()) + { + for (ThreatList::iterator itr = t_list.begin(); itr != t_list.end(); ++itr) + { + Unit *pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); + if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) + DoCast(m_creature, SPELL_PLANAR_ANOMALIES_SUMMON, true); + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_creature->GetHealthPercent() < 50.0f && m_uiSummonCount == 0) + { + SummonAnomalies(); + m_uiSummonCount = 1; + m_creature->CastSpell(m_creature, SPELL_PLANAR_SHIFT,true); + } + + if(m_creature->GetHealthPercent() < 25.0f && m_uiSummonCount == 1) + { + SummonAnomalies(); + m_uiSummonCount = 2; + m_creature->CastSpell(m_creature, SPELL_PLANAR_SHIFT,true); + } + + if(m_creature->GetDistance2d(m_creature->getVictim()) > 35.0f && !m_bIsMove) + { + m_bIsMove = true; + SetCombatMovement(m_bIsMove); + if(Unit* pTarget = m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(pTarget); + } + + if(m_creature->GetDistance2d(m_creature->getVictim()) < 20.0f && m_bIsMove) + { + m_bIsMove = false; + SetCombatMovement(m_bIsMove); + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->StopMoving(); + } + + if(uiArcaneBarrageTimer <= diff) + { + if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsRegularMode ? SPELL_ARCANE_BARRAGE_N : SPELL_ARCANE_BARRAGE_H); + uiArcaneBarrageTimer = 3000; + } else uiArcaneBarrageTimer -= diff; + + if(uiSummonTimer <= diff) + { + for(uint8 i = 1; i < 3; i++) + DoCast(m_creature, SPELL_SUMMON_DRAKE, true); + uiSummonTimer = 15000; + } else uiSummonTimer -= diff; + + if(uiArcaneVolleyTimer <= diff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_VOLLEY_N : SPELL_ARCANE_VOLLEY_H); + uiArcaneVolleyTimer = 17000; + } else uiArcaneVolleyTimer -= diff; + + if(uiEnragedAssaultTimer <= diff) + { + DoCast(m_creature, SPELL_ENRAGED_ASSAULT, true); + uiEnragedAssaultTimer = 44000; + } else uiEnragedAssaultTimer -= diff; + } +}; + +struct MANGOS_DLL_DECL npc_planar_anomalyAI : public ScriptedAI +{ + npc_planar_anomalyAI(Creature *pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 uiPulseTimer; + uint32 uiDeathTimer; + + void Reset() + { + m_creature->SetDisplayId(11686); + m_creature->SetObjectScale(2.0f); + m_creature->SetLevitate(true); + m_creature->SetSpeedRate(MOVE_RUN, 1.5, true); + m_creature->setFaction(14); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(m_creature, SPELL_PLANAR_ANOMALIES_VISUAL, true); + uiDeathTimer = 20500; + uiPulseTimer = 19000; + } + + void UpdateAI(const uint32 diff) + { + if (uiPulseTimer < diff) + { + m_creature->RemoveAurasDueToSpell(SPELL_PLANAR_ANOMALIES_VISUAL); + m_creature->CastSpell(m_creature, SPELL_PLANAR_ANOMALIES_DMG, true); + uiPulseTimer = 6000; + } else uiPulseTimer -= diff; + + if (uiDeathTimer < diff) + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + else uiDeathTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_eregos(Creature* pCreature) +{ + return new boss_eregosAI (pCreature); +} + +CreatureAI* GetAI_npc_planar_anomaly(Creature* pCreature) +{ + return new npc_planar_anomalyAI (pCreature); +} + +void AddSC_boss_eregos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_eregos"; + newscript->GetAI = &GetAI_boss_eregos; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_planar_anomaly"; + newscript->GetAI = &GetAI_npc_planar_anomaly; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/boss_urom.cpp b/scripts/northrend/nexus/oculus/boss_urom.cpp new file mode 100644 index 0000000000..a736849a59 --- /dev/null +++ b/scripts/northrend/nexus/oculus/boss_urom.cpp @@ -0,0 +1,373 @@ +/* Copyright (C) 2006 - 2013 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_Urom +SD%Complete: 70% +SDComment: +SDAuthor: originally from TC, reworked by MaxXx2021 Aka Mioka, corrected by /dev/rsa +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" + +enum +{ + SAY_SUMMON_1 = -1578000, + SAY_SUMMON_2 = -1578001, + SAY_SUMMON_3 = -1578002, + SAY_AGGRO = -1578003, + SAY_EXPLOSION_1 = -1578004, + SAY_EXPLOSION_2 = -1578005, + SAY_KILL_1 = -1578006, + SAY_KILL_2 = -1578007, + SAY_KILL_3 = -1578008, + SAY_DEATH = -1578009, + + SPELL_ARCANE_BARRIER = 53813, //Dummy --> Channeled, shields the caster from damage. + SPELL_EMPOWERED_ARCANE_EXPLOSION = 51110, + SPELL_EMPOWERED_ARCANE_EXPLOSION_2 = 59377, + SPELL_FROSTBOMB = 51103, //Urom throws a bomb, hitting its target with the highest aggro which inflict directly 650 frost damage and drops a frost zone on the ground. This zone deals 650 frost damage per second and reduce the movement speed by 35%. Lasts 1 minute. + SPELL_SUMMON_MENAGERIE = 50476, //Summons an assortment of creatures and teleports the caster to safety. + SPELL_SUMMON_MENAGERIE_2 = 50495, + SPELL_SUMMON_MENAGERIE_3 = 50496, + SPELL_TELEPORT = 51112, //Teleports to the center of Oculus + SPELL_TIME_BOMB = 51121, //Deals arcane damage to a random player, and after 6 seconds, deals zone damage to nearby equal to the health missing of the target afflicted by the debuff. + SPELL_TIME_BOMB_2 = 59376, + + //NPCs + NPC_PHANTASMAL_MAMMOTH = 27642, + NPC_PHANTASMAL_WOLF = 27644, + NPC_PHANTASMAL_CLOUDSCRAPER = 27645, + NPC_PHANTASMAL_OGRE = 27647, + NPC_PHANTASMAL_NAGA = 27648, + NPC_PHANTASMAL_MURLOC = 27649, + NPC_PHANTASMAL_AIR = 27650, + NPC_PHANTASMAL_FIRE = 27651, + NPC_PHANTASMAL_WATER = 27653 +}; + +static LOCATION Teleport[]= +{ + {1177.469f, 937.721f, 527.405f, 2.21f}, //first platform + {968.5880f, 1042.58f, 527.321f, 0.13f}, //second platform + {1163.671f, 1171.02f, 527.321f, 4.19f}, //third platform + {1116.765f, 1075.93f, 508.361f, 4.26f}, //middle platform + {1103.659f, 1049.88f, 518.148f, 5.80f} //oculus center +}; + +struct MANGOS_DLL_DECL boss_uromAI : public BSWScriptedAI +{ + boss_uromAI(Creature *pCreature) : BSWScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiFrostBombTimer; + uint32 m_uiLiveBombTimer; + uint32 m_uiTeleportTimer; + uint32 m_uiArcaneExplodeTimer; + uint32 m_uiRelocateTimer; + uint32 m_uiBackTimer; + uint32 m_uiCheckTimer; + + bool m_bIsTeleported; + bool m_bIsTalk; + + void Reset() + { + m_uiFrostBombTimer = 9000; + m_uiLiveBombTimer = 14000; + m_uiTeleportTimer = 30000; + m_uiRelocateTimer = 31500; + m_uiBackTimer = 9000; + m_uiCheckTimer = 2000; + m_uiArcaneExplodeTimer = 1000; + + m_bIsTeleported = false; + m_bIsTalk = false; + + if (m_pInstance && m_pInstance->GetData(TYPE_UROM) != IN_PROGRESS) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_pInstance->SetData(TYPE_UROM, NOT_STARTED); + if(m_pInstance->GetData(TYPE_VAROS) == DONE) + { + m_creature->RemoveAurasDueToSpell(SPELL_ARCANE_BARRIER); + m_creature->InterruptNonMeleeSpells(false); +// m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + else + { + DoCast(m_creature, SPELL_ARCANE_BARRIER); + } + } + } + + void DoSummon(uint32 Entry01, uint32 Entry02, uint32 Entry03, uint32 Entry04, uint32 Entry05 = 0) + { + m_creature->SummonCreature(Entry01, m_creature->GetPositionX() - (10.0f) * cos(M_PI / 2), m_creature->GetPositionY() - (10.0f) * sin(M_PI / 2), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000); + m_creature->SummonCreature(Entry02, m_creature->GetPositionX() - (10.0f) * cos(M_PI * 2), m_creature->GetPositionY() - (10.0f) * sin(M_PI * 2), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000); + m_creature->SummonCreature(Entry03, m_creature->GetPositionX() - (10.0f) * cos(M_PI + M_PI / 2), m_creature->GetPositionY() - (10.0f) * sin(M_PI + M_PI / 2), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000); + m_creature->SummonCreature(Entry04, m_creature->GetPositionX() - (10.0f) * cos(M_PI), m_creature->GetPositionY() - (10.0f) * sin(M_PI), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000); + if(Entry05 != 0) + m_creature->SummonCreature(Entry05, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if(pSpell->Id == SPELL_SUMMON_MENAGERIE) //|| pSpell->Id == SPELL_SUMMON_MENAGERIE_2 || pSpell->Id == SPELL_SUMMON_MENAGERIE_3) + m_bIsTalk = false; + if(pSpell->Id == SPELL_SUMMON_MENAGERIE_2) + m_bIsTalk = false; + if(pSpell->Id == SPELL_SUMMON_MENAGERIE_3) + m_bIsTalk = false; + } + + void TeleportBoss(float X, float Y, float Z, float O) + { + m_creature->GetMap()->CreatureRelocation(m_creature, X, Y, Z, O); + m_creature->MonsterMoveWithSpeed(X, Y, Z, 26); + m_creature->Relocate(X, Y, Z, O); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if(m_pInstance->GetData(TYPE_UROM_PHASE) < 3) + return; + + if (m_bIsTeleported) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance) + return; + + if(pWho->GetTypeId() == TYPEID_PLAYER + && !((Player*)pWho)->isGameMaster() + && m_creature->IsWithinDistInMap(pWho, 30.0f) + && !pWho->GetVehicle() + && m_pInstance->GetData(TYPE_VAROS) == DONE + && !m_bIsTalk) + { + switch(m_pInstance->GetData(TYPE_UROM_PHASE)) + { + case 0: + m_bIsTalk = true; + SetCombatMovement(false); + m_pInstance->SetData(TYPE_UROM, IN_PROGRESS); + m_creature->InterruptNonMeleeSpells(false); + m_creature->RemoveAurasDueToSpell(53813); + DoScriptText(SAY_SUMMON_1, m_creature); + DoSummon(NPC_PHANTASMAL_FIRE, NPC_PHANTASMAL_FIRE, NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_WATER); + DoCast(m_creature, SPELL_SUMMON_MENAGERIE); + m_pInstance->SetData(TYPE_UROM_PHASE, 1); + break; + case 1: + m_bIsTalk = true; + DoScriptText(SAY_SUMMON_2, m_creature); + DoSummon(NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_NAGA, NPC_PHANTASMAL_MURLOC); + DoCast(m_creature, SPELL_SUMMON_MENAGERIE_2); + m_pInstance->SetData(TYPE_UROM_PHASE, 2); + break; + case 2: + m_bIsTalk = true; + DoScriptText(SAY_SUMMON_3, m_creature); + DoSummon(NPC_PHANTASMAL_MAMMOTH, NPC_PHANTASMAL_WOLF, NPC_PHANTASMAL_WOLF, NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_CLOUDSCRAPER); + DoCast(m_creature, SPELL_SUMMON_MENAGERIE_3); + m_pInstance->SetData(TYPE_UROM_PHASE, 3); + break; + case 3: + m_bIsTalk = true; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + SetCombatMovement(true); + AttackStart(pWho); + break; + default: + break; + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* pWho) + { + if(pWho->GetTypeId() != TYPEID_PLAYER) + EnterEvadeMode(); + else DoScriptText(SAY_AGGRO, m_creature); + } + + void JustSummoned(Creature* summoned) + { + if(!m_pInstance || !summoned) return; + + if (Unit* pTarget = doSelectRandomPlayerAtRange(100.0f)) + { + summoned->SetInCombatWith(pTarget); + summoned->AddThreat(pTarget,100.0f); + } + } + + void EnterEvadeMode() override + { + + if (!m_pInstance) + return; + + if( m_pInstance->GetData(TYPE_UROM_PHASE) < 3) + { + Map::PlayerList const &pList = m_creature->GetMap()->GetPlayers(); + if (!pList.isEmpty()) + return; + } + m_pInstance->SetData(TYPE_UROM, FAIL); + m_pInstance->SetData(TYPE_UROM_PHASE, 1); + ScriptedAI::EnterEvadeMode(); + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_UROM, DONE); + } + + void KilledUnit(Unit *victim) + { + uint8 uiText = urand(0, 2); + switch (uiText) + { + case 0: DoScriptText(SAY_KILL_1, m_creature); break; + case 1: DoScriptText(SAY_KILL_2, m_creature); break; + case 2: DoScriptText(SAY_KILL_3, m_creature); break; + } + } + + void CheckVehicle() + { + 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()->GetVehicle()) + EnterEvadeMode(); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(!m_bIsTeleported) + { + if(m_uiFrostBombTimer < uiDiff) + { + m_creature->CastSpell(m_creature->getVictim(), SPELL_FROSTBOMB, false); + m_uiFrostBombTimer = urand(5000, 7000); + } else m_uiFrostBombTimer -= uiDiff; + + if(m_uiLiveBombTimer < uiDiff) + { + if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsRegularMode ? SPELL_TIME_BOMB : SPELL_TIME_BOMB_2); + m_uiLiveBombTimer = urand(15000, 25000); + } else m_uiLiveBombTimer -= uiDiff; + + if(m_uiTeleportTimer < uiDiff) + { + DoCast(m_creature, SPELL_TELEPORT); + m_uiTeleportTimer = 31500; + } else m_uiTeleportTimer -= uiDiff; + + if(m_uiCheckTimer < uiDiff) + { + CheckVehicle(); + m_uiCheckTimer = 2000; + } else m_uiCheckTimer -= uiDiff; + + if(m_uiRelocateTimer < uiDiff) + { + m_bIsTeleported = true; + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->StopMoving(); + TeleportBoss(Teleport[4].x,Teleport[4].y,Teleport[4].z,Teleport[4].o); + m_uiRelocateTimer = 31500; + } else m_uiRelocateTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + else + { + if(m_uiArcaneExplodeTimer < uiDiff) + { + DoScriptText(urand(0,1) ? SAY_EXPLOSION_1 : SAY_EXPLOSION_2, m_creature); + DoCast(m_creature, SPELL_EMPOWERED_ARCANE_EXPLOSION); + m_uiArcaneExplodeTimer = 32000; + } else m_uiArcaneExplodeTimer -= uiDiff; + + if(m_uiBackTimer < uiDiff) + { + TeleportBoss((m_creature->getVictim())->GetPositionX(),(m_creature->getVictim())->GetPositionY(),(m_creature->getVictim())->GetPositionZ(),(m_creature->getVictim())->GetOrientation()); + m_creature->SetLevitate(false); + if(m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiBackTimer = 9000; + m_bIsTeleported = false; + m_uiArcaneExplodeTimer = 1000; + } else m_uiBackTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_urom(Creature* pCreature) +{ + return new boss_uromAI (pCreature); +} + +void AddSC_boss_urom() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_urom"; + newscript->GetAI = &GetAI_boss_urom; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/boss_varos.cpp b/scripts/northrend/nexus/oculus/boss_varos.cpp new file mode 100644 index 0000000000..1757905c7b --- /dev/null +++ b/scripts/northrend/nexus/oculus/boss_varos.cpp @@ -0,0 +1,442 @@ +/* Copyright (C) 2006 - 2013 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_Varos +SD%Complete: 70% +SDComment: +SDAuthor: originally from TC, reworked by MaxXx2021 Aka Mioka, corrected by /dev/rsa +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" + +enum +{ + SAY_AGGRO = -1578020, + SAY_KILL_1 = -1578026, + SAY_KILL_2 = -1578027, + SAY_DEATH = -1578028, + SAY_CALL_CAPTAIN_1 = -1578021, + SAY_CALL_CAPTAIN_2 = -1578022, + SAY_CALL_CAPTAIN_3 = -1578023, + + SPELL_ARCANE_SHIELD = 50053, + SPELL_ENERGIZE_CORES = 50785, //Damage 5938 to 6562, effec2 Triggers 54069, effect3 Triggers 56251 + SPELL_ENERGIZE_CORES_TRIGGER_1 = 54069, + SPELL_ENERGIZE_CORES_TRIGGER_2 = 56251, + SPELL_ENERGIZE_CORES_2 = 59372, //Damage 9025 to 9975, effect2 Triggers 54069, effect 56251 + SPELL_CALL_AZURE_RING_CAPTAIN = 51002, //Effect Send Event (12229) + SPELL_CALL_AZURE_RING_CAPTAIN_2 = 51006, //Effect Send Event (10665) + SPELL_CALL_AZURE_RING_CAPTAIN_3 = 51007, //Effect Send Event (18454) + SPELL_CALL_AZURE_RING_CAPTAIN_4 = 51008, //Effect Send Event (18455) + SPELL_CALL_AMPLIFY_MAGIC = 51054, + SPELL_CALL_AMPLIFY_MAGIC_2 = 59371, + + NPC_AZURE_CAPTAIN = 28236, + NPC_BEAM = 28239, + NPC_VAROS_CORE = 28183, + + SPELL_CORE_VISUAL = 50798, + SPELL_CORE_MISSILE = 61407, //need core fix max target 4, and spell script on 28183 + SPELL_BEAM = 51024, //need spell script on 28239 + SPELL_BEAM_DMG_AURA = 51019, + SPELL_BEAM_VISUAL_SOUND = 51022, //need script target 28239 + SPELL_SUMMON_BEAM = 51017 +}; + +struct dLocations +{ + float x1, y1, x2, y2; + uint32 id; +}; + +struct dLocations Regions[]= +{ + {0, 0, 0}, + {1323.0f, 1056.0f, 1333.0f, 1066.0f}, //first orb 1 + {1319.3f, 1084.0f, 1329.5f, 1094.0f}, //second orb 2 + {1288.3f, 1108.8f, 1298.3f, 1118.8f}, //third orb 3 + {1260.3f, 1104.2f, 1270.3f, 1114.2f}, //four orb 4 + {1237.7f, 1074.5f, 1247.7f, 1084.5f}, //fifth orb 5 + {1241.8f, 1046.1f, 1251.8f, 1056.1f}, // 6 + {1272.0f, 1022.1f, 1282.0f, 1032.1f}, // 7 + {1300.5f, 1026.2f, 1310.5f, 1036.2f} // 8 +}; + +struct MANGOS_DLL_DECL boss_varosAI : public ScriptedAI +{ + boss_varosAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint8 MinOrb; + uint8 MaxOrb; + + uint32 m_uiCoreTimer; + uint32 m_uiOrbCast; + uint32 m_uiDragonAttackTimer; + uint32 m_uiDragonMoveTimer; + uint32 m_uiCheckTimer; + + ObjectGuid m_uiAzureDrakeGUID; + + bool m_bIsCastChain; + + float angle01; + float angle02; + + void Reset() + { + MinOrb = 1; + MaxOrb = 4; + angle01 = 0; + angle02 = 0; + m_uiOrbCast = 7000; + m_uiCheckTimer = 2000; + m_uiDragonAttackTimer = 10000; + m_uiCoreTimer = urand(7000, 15000); + m_uiDragonMoveTimer = 16000; + m_bIsCastChain = false; + if(m_pInstance) + { + m_pInstance->SetData(TYPE_VAROS, NOT_STARTED); + if(m_pInstance->GetData(TYPE_ROBOTS) == 0) + { + m_creature->RemoveAurasDueToSpell(SPELL_ARCANE_SHIELD); + m_creature->InterruptNonMeleeSpells(false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + else + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(m_creature, SPELL_ARCANE_SHIELD); + } + if(Creature* Dragon = m_pInstance->instance->GetCreature(m_uiAzureDrakeGUID)) + Dragon->DealDamage(Dragon, Dragon->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + m_uiAzureDrakeGUID.Clear(); + } + + void CheckVehicle() + { + Map* map = m_creature->GetMap(); + if(map && 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()->GetVehicle()) + EnterEvadeMode(); + } + } + } + + void Aggro(Unit* who) + { + DoScriptText(SAY_AGGRO, m_creature); + + if(m_pInstance) + m_pInstance->SetData(TYPE_VAROS, IN_PROGRESS); + + if(Creature* Dragon = m_creature->SummonCreature(NPC_AZURE_CAPTAIN, (m_creature->GetPositionX()-45)+rand()%90, (m_creature->GetPositionY()-45)+rand()%90, m_creature->GetPositionZ() + 30.0f, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 100)) + { + Dragon->SetLevitate(true); + Dragon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiAzureDrakeGUID = Dragon->GetObjectGuid(); + } + } + + void AttackStart(Unit* pWho) override + { + if(m_pInstance) + if(m_pInstance->GetData(TYPE_ROBOTS) != 0) + return; + + ScriptedAI::AttackStart(pWho); + + } + + void JustDied(Unit* killer) + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VAROS, DONE); + } + + void KilledUnit(Unit *victim) + { + DoScriptText(urand(0,1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if(pSummoned->GetEntry() == NPC_BEAM) + { + pSummoned->setFaction(14); + pSummoned->SetDisplayId(11686); + pSummoned->CastSpell(pSummoned, SPELL_BEAM_VISUAL_SOUND, false); + pSummoned->CastSpell(pSummoned, SPELL_BEAM_DMG_AURA, false); + pSummoned->SetInCombatWithZone(); + if(Unit* pTarget = pSummoned->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + if(m_pInstance) + if(Creature* Dragon = m_pInstance->instance->GetCreature(m_uiAzureDrakeGUID)) + { + Dragon->GetMotionMaster()->MovementExpired(false); + Dragon->GetMotionMaster()->Clear(false); + Dragon->CastSpell(pSummoned, SPELL_BEAM, true); + } + } + } + + void SelectFourOrb() //huck work perfecly + { + MinOrb = MinOrb+2; + MaxOrb = MaxOrb+2; + if(MinOrb > 8) + MinOrb = 1; + if(MaxOrb > 8) + MaxOrb = 2; + + std::list m_pSpheres; + GetCreatureListWithEntryInGrid(m_pSpheres, m_creature, NPC_VAROS_CORE, DEFAULT_VISIBILITY_INSTANCE); + + if(!m_pSpheres.empty()) + for(std::list::iterator iter = m_pSpheres.begin(); iter != m_pSpheres.end(); ++iter) + { + for(uint8 i = 1; i < 9; i++) + if((i <= MaxOrb && i >= MinOrb) || (MinOrb == 7 && (i <= MaxOrb || i >= MinOrb))) + if((*iter)->GetPositionX() > Regions[i].x1 && (*iter)->GetPositionX() < Regions[i].x2) + if((*iter)->GetPositionY() > Regions[i].y1 && (*iter)->GetPositionY() < Regions[i].y2) + (*iter)->CastSpell(m_creature, SPELL_CORE_MISSILE, true); + } + } + + void CastEnergy() + { + std::list m_pSpheres; + GetCreatureListWithEntryInGrid(m_pSpheres, m_creature, NPC_VAROS_CORE, DEFAULT_VISIBILITY_INSTANCE); + + if(!m_pSpheres.empty()) + for(std::list::iterator iter = m_pSpheres.begin(); iter != m_pSpheres.end(); ++iter) + { + for(uint8 i = 1; i < 9; i++) + if((i <= MaxOrb && i >= MinOrb) || (MinOrb == 7 && (i <= MaxOrb || i >= MinOrb))) + if((*iter)->GetPositionX() > Regions[i].x1 && (*iter)->GetPositionX() < Regions[i].x2) + if((*iter)->GetPositionY() > Regions[i].y1 && (*iter)->GetPositionY() < Regions[i].y2) + { + (*iter)->CastSpell(m_creature, SPELL_ENERGIZE_CORES_TRIGGER_1, true); + + if(i == MinOrb) + angle01 = m_creature->GetAngle((*iter)); + if(i == MaxOrb) + angle02 = m_creature->GetAngle((*iter)); + + 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()) + { + float pAngle = m_creature->GetAngle(i->getSource()); + if(angle01 < angle02) + if(pAngle < angle02 && pAngle > angle01) + DoEnergy(i->getSource()); + if(angle01 > angle02) + if(pAngle < angle02 || pAngle > angle01) + DoEnergy(i->getSource()); + } + } + } + } + } + } + + void DoEnergy(Unit* pTarget) + { + m_creature->CastSpell(pTarget, m_bIsRegularMode ? SPELL_ENERGIZE_CORES : SPELL_ENERGIZE_CORES_2, true); + } + + /*void SpellHitTarget(Unit *target, const SpellEntry *spell) + { + if(spell->Id == (m_bIsRegularMode ? SPELL_ENERGIZE_CORES : SPELL_ENERGIZE_CORES_2) && target->GetTypeId() == TYPEID_PLAYER) + { + int32 uiDmg = m_bIsRegularMode ? urand(5938, 6562) : urand(9025, 9975); + m_creature->DealDamage(target, uiDmg,NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, NULL, false); + } + }*/ + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_uiCheckTimer < uiDiff) + { + CheckVehicle(); + m_uiCheckTimer = 2000; + } else m_uiCheckTimer -= uiDiff; + + if(m_uiDragonAttackTimer <= uiDiff) + { + DoCast(m_creature, SPELL_SUMMON_BEAM, true); + m_uiDragonAttackTimer = 25000; + m_uiDragonMoveTimer = 16000; + uint8 uiText = urand(0, 2); + switch (uiText) + { + 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; + } + } else m_uiDragonAttackTimer -= uiDiff; + + if(m_uiDragonMoveTimer <= uiDiff) + { + if(m_pInstance) + if(Creature* Dragon = m_pInstance->instance->GetCreature(m_uiAzureDrakeGUID)) + { + Dragon->GetMotionMaster()->MovementExpired(false); + Dragon->GetMotionMaster()->Clear(false); + Dragon->GetMotionMaster()->MovePoint(0, (m_creature->GetPositionX()-45)+rand()%90, (m_creature->GetPositionY()-45)+rand()%90, m_creature->GetPositionZ() + 30.0f); + } + m_uiDragonMoveTimer = 25000; + } else m_uiDragonMoveTimer -= uiDiff; + + if(!m_bIsCastChain) + { + if(m_uiOrbCast <= uiDiff) + { + m_uiOrbCast = 1000; + m_bIsCastChain = true; + SelectFourOrb(); + m_uiCoreTimer = 5000; + } else m_uiOrbCast -= uiDiff; + } + else + { + if(m_uiCoreTimer <= uiDiff) + { + m_uiCoreTimer = 5000; + m_bIsCastChain = false; + CastEnergy(); + m_uiOrbCast = 1000; + } else m_uiCoreTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +struct MANGOS_DLL_DECL npc_varos_orbAI : public ScriptedAI +{ + npc_varos_orbAI(Creature *pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->setFaction(14); + DoCast(m_creature, SPELL_CORE_VISUAL, true); + } + + void AttackStart(Unit* pWho) override + { + } + + void UpdateAI(const uint32 diff) + { + } +}; + +struct MANGOS_DLL_DECL npc_varos_beam_targetAI : public ScriptedAI +{ + npc_varos_beam_targetAI(Creature *pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + uint32 uiDeathTimer; + + void Reset() + { + m_creature->SetSpeedRate(MOVE_RUN, 0.5f, true); + uiDeathTimer = 15000; + } + + void UpdateAI(const uint32 diff) + { + if (uiDeathTimer < diff) + m_creature->ForcedDespawn(); + else uiDeathTimer -= diff; + } +}; + +CreatureAI* GetAI_boss_varos(Creature* pCreature) +{ + return new boss_varosAI (pCreature); +} + +CreatureAI* GetAI_npc_varos_orb(Creature* pCreature) +{ + return new npc_varos_orbAI (pCreature); +} + +CreatureAI* GetAI_npc_varos_beam_target(Creature* pCreature) +{ + return new npc_varos_beam_targetAI (pCreature); +} + +void AddSC_boss_varos() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_varos"; + newscript->GetAI = &GetAI_boss_varos; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_varos_orb"; + newscript->GetAI = &GetAI_npc_varos_orb; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_varos_beam_target"; + newscript->GetAI = &GetAI_npc_varos_beam_target; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/instance_oculus.cpp b/scripts/northrend/nexus/oculus/instance_oculus.cpp new file mode 100644 index 0000000000..e45df09c91 --- /dev/null +++ b/scripts/northrend/nexus/oculus/instance_oculus.cpp @@ -0,0 +1,251 @@ +/* Copyright (C) 2006 - 2013 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: instance_oculus +SD%Complete: 70% +SDComment: +SDAuthor: originally from TC, reworked by MaxXx2021 Aka Mioka, corrected by /dev/rsa +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" + +/* The Occulus encounters: +0 - Drakos the Interrogator +1 - Varos Cloudstrider +2 - Mage-Lord Urom +3 - Ley-Guardian Eregos */ + +enum +{ + SAY_VAROS_SPAWN = -1578043, +}; + +instance_oculus::instance_oculus(Map* pMap) : ScriptedInstance(pMap) +{ + m_bIsRegularMode = pMap->IsRegularDifficulty(); + Initialize(); +}; + + +void instance_oculus::Initialize() +{ + for (uint8 i = 0; i < MAX_ENCOUNTERS+1; ++i) + m_auiEncounter[i] = NOT_STARTED; + + m_auiEncounter[TYPE_ROBOTS] = 10; + m_auiEncounter[TYPE_UROM_PHASE] = 0; + for (uint8 i = 0; i < ACHIEV_COUNT; ++i) + m_bAchievCriteria[i] = false; +} + +void instance_oculus::OnObjectCreate(GameObject* pGo) +{ + switch(pGo->GetEntry()) + { + case GO_DRAGON_CAGE_DOOR_1: + break; + case GO_DRAGON_CAGE_DOOR_2: + break; + case GO_DRAGON_CAGE_DOOR_3: + break; + default: + return; + } + + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_oculus::OnCreatureCreate(Creature* pCreature) +{ + switch(pCreature->GetEntry()) + { + case NPC_VAROS: + pCreature->SetActiveObjectState(true); + case NPC_TRIGGER: + case NPC_ETERNOS: + case NPC_VERDISA: + case NPC_BELGAR: + case NPC_DRAKOS: + case NPC_UROM: + case NPC_EREGOS: + case NPC_BALGAR_IMAGE: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} + +bool instance_oculus::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRITERIA_RUBY_VOID: + return m_bAchievCriteria[ACHIEV_RUBY_VOID]; + case ACHIEV_CRITERIA_EMERALD_VOID: + return m_bAchievCriteria[ACHIEV_EMERALD_VOID]; + case ACHIEV_CRITERIA_AMBER_VOID: + return m_bAchievCriteria[ACHIEV_AMBER_VOID]; + default: + return false; + } +} + +void instance_oculus::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < ACHIEV_COUNT) + m_bAchievCriteria[uiType] = bIsMet; +} + +void instance_oculus::SetData(uint32 type, uint32 data) +{ + switch(type) + { + case TYPE_DRAKOS: + m_auiEncounter[type] = data; + if (data == IN_PROGRESS) + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_EREGOS_ID); + break; + case TYPE_VAROS: + case TYPE_UROM: + m_auiEncounter[type] = data; + break; + case TYPE_EREGOS: + m_auiEncounter[type] = data; + if (data == DONE) + { + DoRespawnGameObject(m_bIsRegularMode ? GO_EREGOS_CACHE : GO_EREGOS_CACHE_H, HOUR); + DoRespawnGameObject(GO_SPOTLIGHT, HOUR); + } + break; + case TYPE_ROBOTS: + m_auiEncounter[type] = m_auiEncounter[type] - data; + if(m_auiEncounter[type] == 0) + { + if(Creature* pVaros = GetSingleCreatureFromStorage(NPC_VAROS)) + { + DoScriptText(SAY_VAROS_SPAWN, pVaros); + pVaros->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pVaros->InterruptNonMeleeSpells(false); + pVaros->RemoveAurasDueToSpell(50053); + } + } + data = NOT_STARTED; + break; + case TYPE_UROM_PHASE: + m_auiEncounter[type] = data; + data = NOT_STARTED; + break; + default: + return; + } + + if (data == DONE) + { + OUT_SAVE_INST_DATA; + std::ostringstream saveStream; + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + saveStream << m_auiEncounter[i] << " "; + + strSaveData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_oculus::GetData(uint32 type) const +{ + switch(type) + { + case TYPE_DRAKOS: + case TYPE_VAROS: + case TYPE_UROM: + case TYPE_EREGOS: + case TYPE_ROBOTS: + case TYPE_UROM_PHASE: + return m_auiEncounter[type]; + default: + return 0; + } + return 0; +} + +const char* instance_oculus::Save() const +{ + return strSaveData.c_str(); +} + +void instance_oculus::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + std::istringstream loadStream(chrIn); + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + { + loadStream >> m_auiEncounter[i]; + + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + m_auiEncounter[TYPE_ROBOTS] = 10; + m_auiEncounter[TYPE_UROM_PHASE] = 0; + + OUT_LOAD_INST_DATA_COMPLETE; +} + +InstanceData* GetInstanceData_instance_oculus(Map* pMap) +{ + return new instance_oculus(pMap); +} + +/*### +# Oculus Orb +-####*/ +bool GOUse_go_oculus_portal(Player* pPlayer, GameObject* pGo) +{ + switch(pGo->GetEntry()) + { + case GO_ORB_OF_NEXUS: + pPlayer->TeleportTo(571,3876.159912f,6984.439941f,106.32f,6.279f); + return true; + } + return false; +} + + +void AddSC_instance_oculus() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_oculus"; + newscript->GetInstanceData = &GetInstanceData_instance_oculus; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "go_oculus_portal"; + newscript->pGOUse = GOUse_go_oculus_portal; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/oculus.cpp b/scripts/northrend/nexus/oculus/oculus.cpp new file mode 100644 index 0000000000..845e6e8b53 --- /dev/null +++ b/scripts/northrend/nexus/oculus/oculus.cpp @@ -0,0 +1,217 @@ +/* Copyright (C) 2006 - 2013 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: oculus +SD%Complete: ?% +SDComment: by /dev/rsa +SDCategory: Oculus - mobs and special +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" +enum Spells +{ + SPELL_GREEN_SEAT = 49346, + SPELL_YELLOW_SEAT = 49460, + SPELL_RED_SEAT = 49464, +}; + +struct MANGOS_DLL_DECL mob_oculus_dragonAI : public ScriptedAI +{ + mob_oculus_dragonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + bool Active; + ObjectGuid ownerGUID; + uint32 seatSpell; + uint32 StartTimer; + + void Reset() + { + Active = false; + ownerGUID = ObjectGuid(); + StartTimer = 2000; + switch (m_creature->GetEntry()) + { + case NPC_GREEN_DRAGON: + seatSpell = SPELL_GREEN_SEAT; + break; + case NPC_RED_DRAGON: + seatSpell = SPELL_RED_SEAT; + break; + case NPC_YELLOW_DRAGON: + seatSpell = SPELL_YELLOW_SEAT; + break; + default: + seatSpell = 0; + break; + } + ownerGUID = m_creature->GetCreatorGuid(); + + if (Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID)) + owner->RemoveAurasDueToSpell(53797); + } + + void AttackStart(Unit *) {} + void MoveInLineOfSight(Unit*) override { } + + void JustSummoned(){} + + void JustDied(Unit* killer) + { + if (!m_creature || m_creature->GetTypeId() != TYPEID_UNIT) + return; + + if (ownerGUID.IsEmpty()) + ownerGUID = m_creature->GetCreatorGuid(); + + Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID); + + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + owner->RemoveAurasDueToSpell(seatSpell); + owner->RemoveAurasDueToSpell(53797); + m_creature->SetCreatorGuid(ObjectGuid()); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE && uiPointId == 0) + return; + + if (Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID)) + { + m_creature->setFaction(owner->getFaction()); + owner->CastSpell(m_creature, seatSpell, true); + owner->CastSpell(owner, 53797, true); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + + if (ownerGUID.IsEmpty()) + ownerGUID = m_creature->GetCreatorGuid(); + + if (!ownerGUID.IsEmpty()) + { + if (StartTimer < uiDiff && !Active) + { + if (Unit* owner = m_creature->GetMap()->GetUnit(ownerGUID)) + { + float x, y, z; + owner->GetClosePoint(x, y, z, owner->GetObjectBoundingRadius(), 1.0f, owner->GetAngle(m_creature)); + m_creature->GetMotionMaster()->MovePoint(0, x, y, z); + Active = true; + } + } + else + StartTimer -= uiDiff; + } + else + if (StartTimer < uiDiff) + m_creature->ForcedDespawn(); + } +}; + +CreatureAI* GetAI_mob_oculus_dragon(Creature* pCreature) +{ + return new mob_oculus_dragonAI(pCreature); +} + +/*##### +# npc_robot +#####*/ + +struct MANGOS_DLL_DECL npc_oculus_robotAI : public ScriptedAI +{ + npc_oculus_robotAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset(){} + + void JustDied(Unit* pKiller) override + { + if(m_pInstance) + m_pInstance->SetData(TYPE_ROBOTS, 1); + } + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_oculus_robot(Creature* pCreature) +{ + return new npc_oculus_robotAI (pCreature); +} + +struct MANGOS_DLL_DECL npc_belgar_imageAI : public ScriptedAI +{ + npc_belgar_imageAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset(){} + + void UpdateAI(const uint32 diff) + { + if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + } +}; + +CreatureAI* GetAI_npc_belgar_image(Creature* pCreature) +{ + return new npc_belgar_imageAI (pCreature); +} + +void AddSC_oculus() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "mob_oculus_dragon"; + newscript->GetAI = &GetAI_mob_oculus_dragon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_oculus_robot"; + newscript->GetAI = &GetAI_npc_oculus_robot; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_belgar_image"; + newscript->GetAI = &GetAI_npc_belgar_image; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/oculus.h b/scripts/northrend/nexus/oculus/oculus.h new file mode 100644 index 0000000000..f858900062 --- /dev/null +++ b/scripts/northrend/nexus/oculus/oculus.h @@ -0,0 +1,113 @@ +/* Copyright (C) 2010 - 2013 by /dev/rsa for 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 + */ + +#ifndef DEF_OCULUS_H +#define DEF_OCULUS_H +#include "BSW_ai.h" +#include "BSW_instance.h" + +enum +{ + TYPE_DRAKOS, + TYPE_VAROS, + TYPE_UROM, + TYPE_EREGOS, + TYPE_ROBOTS, + TYPE_UROM_PHASE, + MAX_ENCOUNTERS, + + DATA_DRAKOS, + DATA_VAROS, + DATA_UROM, + DATA_EREGOS, + + NPC_TRIGGER = 11364, + + NPC_ETERNOS = 27659, + NPC_BELGAR = 27658, + NPC_VERDISA = 27657, + + NPC_ROBOT = 27641, + NPC_BALGAR_IMAGE = 28012, + NPC_DRAKOS = 27654, + NPC_VAROS = 27447, + NPC_UROM = 27655, + NPC_EREGOS = 27656, + + NPC_GREEN_DRAGON = 27692, + NPC_YELLOW_DRAGON = 27755, + NPC_RED_DRAGON = 27756, + + GO_DRAGON_CAGE_DOOR_1 = 193992, + GO_DRAGON_CAGE_DOOR_2 = 193993, + GO_DRAGON_CAGE_DOOR_3 = 193995, + GO_EREGOS_CACHE = 191349, + GO_EREGOS_CACHE_H = 193603, + GO_SPOTLIGHT = 191351, + GO_ORB_OF_NEXUS = 188715, + + BELGAR_TEXT_0 = 13267, + BELGAR_TEXT_1 = 13268, + BELGAR_TEXT_2 = 13269, + + // Yells after Drakos dies + SAY_VAROS_INTRO = -1578001, + SAY_BELGARISTRASZ_GREET = -1578002, + + // world states to show how many constructs are still alive + WORLD_STATE_CONSTRUCTS = 3524, + WORLD_STATE_CONSTRUCTS_COUNT = 3486, + + // Achievements + ACHIEV_START_EREGOS_ID = 18153, // eregos timed kill achiev + + ACHIEV_CRITERIA_AMBER_VOID = 7323, + ACHIEV_CRITERIA_EMERALD_VOID = 7324, + ACHIEV_CRITERIA_RUBY_VOID = 7325, + + ACHIEV_RUBY_VOID = 0, + ACHIEV_EMERALD_VOID = 1, + ACHIEV_AMBER_VOID = 2, + ACHIEV_COUNT = 3, +}; + +struct MANGOS_DLL_DECL instance_oculus : public ScriptedInstance +{ + public: + instance_oculus(Map* pMap); + void Initialize() override; + + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + + void SetData(uint32 type, uint32 data); + uint32 GetData(uint32 type) const; + + const char* Save() const override; + void Load(const char* chrIn) override; + + private: + uint32 m_auiEncounter[MAX_ENCOUNTERS+1]; + + std::string strSaveData; + bool m_bIsRegularMode; + bool m_bAchievCriteria[ACHIEV_COUNT]; +}; + +#endif diff --git a/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp b/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp index 881126b533..baa6e04946 100644 --- a/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp +++ b/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,6 +180,16 @@ 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 ######*/ @@ -164,12 +198,12 @@ struct MANGOS_DLL_DECL 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,43 +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_bIsBerserk = false; + m_bIsSoftEnraged = false; - m_uiTenebronTimer = 30000; - m_uiShadronTimer = 75000; - m_uiVesperonTimer = 120000; + m_uiEnrageTimer = 15 * MINUTE * IN_MILLISECONDS; + m_bIsHardEnraged = false; - m_uiFlameTsunamiTimer = 30000; - m_uiFlameBreathTimer = 20000; - m_uiTailSweepTimer = 20000; - m_uiCleaveTimer = 7000; - m_uiLavaStrikeTimer = 5000; + m_uiTenebronTimer = 30000; + m_uiShadronTimer = 75000; + m_uiVesperonTimer = 120000; - m_bHasCalledTenebron = false; - m_bHasCalledShadron = false; - m_bHasCalledVesperon = false; + m_uiFlameTsunamiTimer = 30000; + m_uiFlameBreathTimer = 20000; + m_uiTailSweepTimer = 20000; + m_uiCleaveTimer = 7000; + m_uiLavaStrikeTimer = urand(20000, 30000); - if (m_creature->HasAura(SPELL_TWILIGHT_REVENGE)) - m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_REVENGE); + m_bHasCalledTenebron = false; + m_bHasCalledShadron = false; + m_bHasCalledVesperon = false; } - void JustReachedHome() + void Aggro(Unit* /*pWho*/) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_SARTHARION_EVENT, NOT_STARTED); - } - - void Aggro(Unit* pWho) - { - DoScriptText(SAY_SARTHARION_AGGRO,m_creature); - - m_creature->SetInCombatWithZone(); + DoScriptText(SAY_SARTHARION_AGGRO, m_creature); if (m_pInstance) { @@ -237,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; @@ -255,18 +278,28 @@ 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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_TENEBRON)); - Creature* pShad = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SHADRON)); - Creature* pVesp = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_VESPERON)); + 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 - bool bCanUseWill = false; + // if at least one of the dragons are alive and are being called + uint8 uiCountFetchableDragons = 0; if (pTene && pTene->isAlive() && !pTene->getVictim()) { - bCanUseWill = true; + ++uiCountFetchableDragons; pTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ); if (!pTene->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) @@ -275,7 +308,7 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI if (pShad && pShad->isAlive() && !pShad->getVictim()) { - bCanUseWill = true; + ++uiCountFetchableDragons; pShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ); if (!pShad->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) @@ -284,34 +317,37 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI if (pVesp && pVesp->isAlive() && !pVesp->getVictim()) { - bCanUseWill = true; + ++uiCountFetchableDragons; pVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ); if (!pVesp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) pVesp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - if (bCanUseWill) + if (uiCountFetchableDragons) DoCastSpellIfCan(m_creature, SPELL_WILL_OF_SARTHARION); + + m_pInstance->SetData(TYPE_ALIVE_DRAGONS, uiCountFetchableDragons); } - void CallDragon(uint32 uiDataId) + void CallDragon(uint32 uiEntry) { if (m_pInstance) { - Creature* pTemp = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(uiDataId)); - - if (pTemp && pTemp->isAlive() && !pTemp->getVictim()) + Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(uiEntry); + if (pTemp && pTemp->isAlive()) { - if (pTemp->HasSplineFlag(SPLINEFLAG_WALKMODE)) - pTemp->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - 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(pTemp->GetEntry()) + switch (uiEntry) { case NPC_TENEBRON: iTextId = SAY_SARTHARION_CALL_TENEBRON; @@ -334,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 @@ -377,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; @@ -396,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; @@ -406,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; @@ -415,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; @@ -424,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(DATA_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(DATA_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(DATA_VESPERON); - m_bHasCalledVesperon = true; + if (m_uiVesperonTimer < uiDiff) + { + CallDragon(NPC_VESPERON); + m_bHasCalledVesperon = true; + } + else + m_uiVesperonTimer -= uiDiff; } - else - m_uiVesperonTimer -= uiDiff; DoMeleeAttackIfReady(); @@ -514,50 +562,84 @@ enum VespText SAY_VESPERON_SPECIAL_2 = -1615040 }; -//to control each dragons common abilities +// to control each dragons common abilities struct MANGOS_DLL_DECL 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(); @@ -566,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; @@ -584,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; @@ -657,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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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; @@ -712,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(); } }; @@ -721,61 +801,105 @@ struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI struct MANGOS_DLL_DECL 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; } }; @@ -790,67 +914,110 @@ CreatureAI* GetAI_mob_tenebron(Creature* pCreature) struct MANGOS_DLL_DECL 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; + } } }; @@ -865,61 +1032,102 @@ CreatureAI* GetAI_mob_shadron(Creature* pCreature) struct MANGOS_DLL_DECL 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; + } } }; @@ -929,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 MANGOS_DLL_DECL 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->instance->GetCreature(m_pInstance->GetData64(DATA_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->instance->GetCreature(m_pInstance->GetData64(DATA_SHADRON)); - if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) - pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); - } - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + m_creature->SetPhaseMask(PHASEMASK_NORMAL, true); + DoCastSpellIfCan(m_creature, uiSpellEntry, CAST_TRIGGERED); - 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 MANGOS_DLL_DECL 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(); @@ -1007,138 +1201,174 @@ 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->instance->GetCreature(m_pInstance->GetData64(DATA_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 MANGOS_DLL_DECL npc_flame_tsunamiAI : public ScriptedAI { - mob_twilight_eggsAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_flame_tsunamiAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void 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) { } - void MoveInLineOfSight(Unit* pWho) { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + m_creature->RemoveAllAuras(); + } + + 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 MANGOS_DLL_DECL 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(); + } - uint32 m_uiFadeArmorTimer; + ScriptedInstance* m_pInstance; + + void Reset() override { } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + 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() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_sartharion"; - newscript->GetAI = &GetAI_boss_sartharion; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_vesperon"; - newscript->GetAI = &GetAI_mob_vesperon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_shadron"; - newscript->GetAI = &GetAI_mob_shadron; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_tenebron"; - newscript->GetAI = &GetAI_mob_tenebron; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_acolyte_of_shadron"; - newscript->GetAI = &GetAI_mob_acolyte_of_shadron; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_acolyte_of_vesperon"; - newscript->GetAI = &GetAI_mob_acolyte_of_vesperon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_twilight_eggs"; - newscript->GetAI = &GetAI_mob_twilight_eggs; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_twilight_whelp"; - newscript->GetAI = &GetAI_mob_twilight_whelp; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_sartharion"; + pNewScript->GetAI = &GetAI_boss_sartharion; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_vesperon"; + pNewScript->GetAI = &GetAI_mob_vesperon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_shadron"; + pNewScript->GetAI = &GetAI_mob_shadron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_tenebron"; + pNewScript->GetAI = &GetAI_mob_tenebron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_twilight_eggs"; + pNewScript->GetAI = &GetAI_mob_twilight_eggs; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tenebron_egg_controller"; + pNewScript->GetAI = &GetAI_npc_tenebron_egg_controller; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_flame_tsunami"; + pNewScript->GetAI = &GetAI_npc_flame_tsunami; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 4a149fb12f..a5d3813132 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -28,80 +28,114 @@ EndScriptData */ 0 - Sartharion */ -struct MANGOS_DLL_DECL instance_obsidian_sanctum : public ScriptedInstance +instance_obsidian_sanctum::instance_obsidian_sanctum(Map* pMap) : ScriptedInstance(pMap), + m_uiAliveDragons(0) { - instance_obsidian_sanctum(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint64 m_uiSartharionGUID; - uint64 m_uiTenebronGUID; - uint64 m_uiShadronGUID; - uint64 m_uiVesperonGUID; +void instance_obsidian_sanctum::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + for (uint8 i = 0; i < MAX_TWILIGHT_DRAGONS; ++i) + m_bPortalActive[i] = false; +} - m_uiSartharionGUID = 0; - m_uiTenebronGUID = 0; - m_uiShadronGUID = 0; - m_uiVesperonGUID = 0; +void instance_obsidian_sanctum::OnCreatureCreate(Creature* pCreature) +{ + 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 + case NPC_TENEBRON: + case NPC_SHADRON: + case NPC_VESPERON: + pCreature->SetActiveObjectState(true); + case NPC_SARTHARION: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_FIRE_CYCLONE: + m_lFireCycloneGuidList.push_back(pCreature->GetObjectGuid()); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_obsidian_sanctum::SetData(uint32 uiType, uint32 uiData) +{ + if (uiType == TYPE_SARTHARION_EVENT) { - switch(pCreature->GetEntry()) - { - case NPC_SARTHARION: - m_uiSartharionGUID = pCreature->GetGUID(); - break; - //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: - m_uiTenebronGUID = pCreature->GetGUID(); - pCreature->SetActiveObjectState(true); - break; - case NPC_SHADRON: - m_uiShadronGUID = pCreature->GetGUID(); - pCreature->SetActiveObjectState(true); - break; - case NPC_VESPERON: - m_uiVesperonGUID = pCreature->GetGUID(); - pCreature->SetActiveObjectState(true); - break; - } + m_auiEncounter[0] = uiData; + if (uiData == IN_PROGRESS) + m_sVolcanoBlowFailPlayers.clear(); } - - void SetData(uint32 uiType, uint32 uiData) + else if (uiType == TYPE_ALIVE_DRAGONS) + m_uiAliveDragons = uiData; + else if (uiType == TYPE_VOLCANO_BLOW_FAILED) { - if (uiType == TYPE_SARTHARION_EVENT) - m_auiEncounter[0] = uiData; + // 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); } - uint32 GetData(uint32 uiType) - { - if (uiType == TYPE_SARTHARION_EVENT) - return m_auiEncounter[0]; + // No need to save anything here +} - return 0; +uint32 instance_obsidian_sanctum::GetData(uint32 uiType) const +{ + if (uiType == TYPE_SARTHARION_EVENT) + return m_auiEncounter[0]; + + return 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) + { + case ACHIEV_DRAGONS_ALIVE_1_N: + case ACHIEV_DRAGONS_ALIVE_1_H: + return m_uiAliveDragons >= 1; + case ACHIEV_DRAGONS_ALIVE_2_N: + case ACHIEV_DRAGONS_ALIVE_2_H: + return m_uiAliveDragons >= 2; + 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; } +} - uint64 GetData64(uint32 uiData) +bool instance_obsidian_sanctum::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource conditionSourceType) const +{ + switch (uiInstanceConditionId) { - switch(uiData) - { - case DATA_SARTHARION: - return m_uiSartharionGUID; - case DATA_TENEBRON: - return m_uiTenebronGUID; - case DATA_SHADRON: - return m_uiShadronGUID; - case DATA_VESPERON: - return m_uiVesperonGUID; - } - return 0; + 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) { @@ -110,9 +144,10 @@ InstanceData* GetInstanceData_instance_obsidian_sanctum(Map* pMap) void AddSC_instance_obsidian_sanctum() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_obsidian_sanctum"; - newscript->GetInstanceData = GetInstanceData_instance_obsidian_sanctum; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_obsidian_sanctum"; + pNewScript->GetInstanceData = GetInstanceData_instance_obsidian_sanctum; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h b/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h index b43ecb090b..ed0339a104 100644 --- a/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h +++ b/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -10,17 +10,74 @@ enum MAX_ENCOUNTER = 1, TYPE_SARTHARION_EVENT = 1, + // internal used types for achievement + TYPE_ALIVE_DRAGONS = 2, + TYPE_VOLCANO_BLOW_FAILED = 3, - DATA_SARTHARION = 10, - DATA_TENEBRON = 11, - DATA_SHADRON = 12, - DATA_VESPERON = 13, + 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, - GO_TWILIGHT_PORTAL = 193988 + + NPC_FIRE_CYCLONE = 30648, + + GO_TWILIGHT_PORTAL = 193988, + + // Achievement related + ACHIEV_CRIT_VOLCANO_BLOW_N = 7326, // achievs 2047, 2048 (Go When the Volcano Blows) -- This is individual achievement! + ACHIEV_CRIT_VOLCANO_BLOW_H = 7327, + ACHIEV_DRAGONS_ALIVE_1_N = 7328, // achievs 2049, 2052 (Twilight Assist) + ACHIEV_DRAGONS_ALIVE_1_H = 7331, + ACHIEV_DRAGONS_ALIVE_2_N = 7329, // achievs 2050, 2053 (Twilight Duo) + ACHIEV_DRAGONS_ALIVE_2_H = 7332, + ACHIEV_DRAGONS_ALIVE_3_N = 7330, // achievs 2051, 2054 (The Twilight Zone) + ACHIEV_DRAGONS_ALIVE_3_H = 7333, +}; + +class MANGOS_DLL_DECL instance_obsidian_sanctum : public ScriptedInstance +{ + public: + instance_obsidian_sanctum(Map* pMap); + + void Initialize() override; + void OnCreatureCreate(Creature* pCreature) override; + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + ObjectGuid SelectRandomFireCycloneGuid(); + + bool IsActivePortal() + { + for (uint8 i = 0; i < MAX_TWILIGHT_DRAGONS; ++i) + { + if (m_bPortalActive[i]) + return true; + } + + 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, ConditionSource 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 bb0493cfbd..d46eba426d 100644 --- a/scripts/northrend/ruby_sanctum/boss_baltharus.cpp +++ b/scripts/northrend/ruby_sanctum/boss_baltharus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2013 /dev/rsa for 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 @@ -16,9 +16,425 @@ /* ScriptData SDName: boss_baltharus -SD%Complete: -SDComment: placeholder +SD%Complete: 90% +SDComment: by notagain && /dev/rsa && carlos93 SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" + +static LOCATION SpawnLoc[]= +{ + {3152.329834f, 359.41757f, 85.301605f}, // Baltharus target point + {3153.06f, 389.486f, 86.2596f}, // Baltharus initial point +}; + +enum Says +{ + //SAY_BALTHARUS_INTRO = -1724001, + SAY_BALTHARUS_AGGRO = -1724010, + SAY_BALTHARUS_SLAY_1 = -1724011, + SAY_BALTHARUS_SLAY_2 = -1724012, + SAY_BALTHARUS_DEATH = -1724013, + SAY_BALTHARUS_SPLIT = -1724014, + SAY_BALTHARUS_YELL = -1666305, +}; + +enum BossSpells +{ + SPELL_BLADE_TEMPEST = 75125, // every 22 secs + SPELL_ENERVATING_BRAND = 74502, // friendlys in 12yards = 74505 + SPELL_REPELLING_WAVE = 74509, // once if call clone + SPELL_SABER_LASH = 40504, // every 10-15 secs + SPELL_SUMMON_CLONE = 74511, // summons npc 39899 (Clone) + SPELL_CHANNEL_SPELL = 76221, // Channeling dummy spell +}; + +/*###### +## boss_baltharus +######*/ + +struct MANGOS_DLL_DECL boss_baltharusAI : public ScriptedAI +{ + boss_baltharusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance *m_pInstance; + Difficulty m_uiMapDifficulty; + Creature* pDummyTarget; + Creature* pClone; + bool m_bInCombat; + bool m_bIntro; + bool m_bIs25Man; + bool m_bIsHeroic; + uint32 m_uiStage; + uint32 m_uiBladeTempestTimer; + uint32 m_uiEnervatingBrandTimer; + uint32 m_uiSaberLashTimer; + + void Reset() + { + if (!m_pInstance) + return; + + if (m_creature->isAlive()) + m_pInstance->SetData(TYPE_BALTHARUS, NOT_STARTED); + + m_creature->SetRespawnDelay(7*DAY); + pClone = NULL; + m_uiStage = 0; + m_uiBladeTempestTimer = 22000; + m_uiEnervatingBrandTimer = 10000; + m_uiSaberLashTimer = 5000; + m_bInCombat = false; + m_bIntro = false; + pDummyTarget = m_pInstance->GetSingleCreatureFromStorage(NPC_BALTHARUS_TARGET); + if (pDummyTarget) + { + if (!pDummyTarget->isAlive()) + pDummyTarget->Respawn(); + + pDummyTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pDummyTarget->GetMotionMaster()->MoveIdle(); + } + else + { + pDummyTarget = m_creature->SummonCreature(NPC_BALTHARUS_TARGET, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 1000); + if (pDummyTarget) + { + pDummyTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pDummyTarget->GetMotionMaster()->MoveIdle(); + } + } + + if (Creature* pTarget = m_pInstance->GetSingleCreatureFromStorage(NPC_XERESTRASZA)) + m_creature->SetGuidValue(UNIT_FIELD_TARGET, pTarget->GetObjectGuid()); + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_BALTHARUS, FAIL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + ScriptedAI::MoveInLineOfSight(pWho); + + if (!m_pInstance || m_bIntro || pWho->GetTypeId() != TYPEID_PLAYER || !pWho->IsWithinDistInMap(m_creature, 60.0f)) + return; + + m_pInstance->SetData(TYPE_EVENT, 10); + DoScriptText(SAY_BALTHARUS_YELL,m_creature); + m_bIntro = true; + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + DoScriptText(SAY_BALTHARUS_DEATH,m_creature); + m_pInstance->SetData(TYPE_BALTHARUS, DONE); + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(SAY_BALTHARUS_SLAY_1 - urand(0,1),m_creature,pVictim); + } + + void JustSummoned(Creature* pSummoned) override + { + if (!m_pInstance || !pSummoned) + return; + + if (pSummoned->GetEntry() != NPC_BALTHARUS_TARGET ) + { + if (!pClone) + pClone = pSummoned; + else if (!pClone->isAlive()) + pClone = pSummoned; + + pClone->SetInCombatWithZone(); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) + { + if (!m_pInstance || !pSummoned) + return; + + if (pSummoned == pClone) + pClone = NULL; + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + if (pWho->GetTypeId() != TYPEID_PLAYER) + return; + + if (pDummyTarget) + pDummyTarget->ForcedDespawn(); + + m_bInCombat = true; + m_creature->InterruptNonMeleeSpells(true); + SetCombatMovement(true); + m_pInstance->SetData(TYPE_BALTHARUS, IN_PROGRESS); + DoScriptText(SAY_BALTHARUS_AGGRO,m_creature); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!m_pInstance) + return; + + if (!m_creature || !m_creature->isAlive()) + return; + + if (pClone && pClone->isAlive()) + uiDamage = 0; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (!m_bInCombat && !m_creature->IsNonMeleeSpellCasted(false)) + m_creature->CastSpell(pDummyTarget, SPELL_CHANNEL_SPELL, false); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiStage) + { + case 0: + if (m_creature->GetHealthPercent() <= 66.0f) + m_uiStage = 1; + + break; + case 1: + m_creature->InterruptNonMeleeSpells(true); + if (m_bIs25Man) + { + m_creature->CastSpell(m_creature, SPELL_SUMMON_CLONE, true); + DoScriptText(SAY_BALTHARUS_SPLIT, m_creature); + } + m_uiStage = 2; + break; + case 2: + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + if (m_bIs25Man) + m_creature->CastSpell(m_creature, SPELL_REPELLING_WAVE, false); + + m_uiStage = 3; + break; + case 3: + if (m_creature->GetHealthPercent() <= 50.0f) + m_uiStage = 4; + + break; + case 4: + m_creature->InterruptNonMeleeSpells(true); + if (!m_bIs25Man) + { + m_creature->CastSpell(m_creature, SPELL_SUMMON_CLONE, true); + DoScriptText(SAY_BALTHARUS_SPLIT, m_creature); + } + m_uiStage = 5; + break; + case 5: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + m_creature->CastSpell(m_creature, SPELL_REPELLING_WAVE, false); + m_uiStage = 6; + break; + case 6: + if (m_creature->GetHealthPercent() <= 33.0f) + m_uiStage = 7; + + break; + case 7: + m_creature->InterruptNonMeleeSpells(true); + if (m_bIs25Man) + { + m_creature->CastSpell(m_creature, SPELL_SUMMON_CLONE, true); + DoScriptText(SAY_BALTHARUS_SPLIT, m_creature); + } + m_uiStage = 8; + break; + case 8: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + if (m_bIs25Man) + m_creature->CastSpell(m_creature, SPELL_REPELLING_WAVE, false); + + m_uiStage = 9; + break; + case 9: + break; + default: + break; + } + + if (m_uiBladeTempestTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLADE_TEMPEST) == CAST_OK) + m_uiBladeTempestTimer = urand(20000, 25000); + } + 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 = urand(10000, 13000); + } + } + else + m_uiEnervatingBrandTimer -= uiDiff; + + if (m_uiSaberLashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SABER_LASH) == CAST_OK) + m_uiSaberLashTimer = urand(8000, 12000); + } + else + m_uiSaberLashTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_baltharus(Creature* pCreature) +{ + return new boss_baltharusAI(pCreature); +} + +/*###### +## mob_baltharus_clone +######*/ + +struct MANGOS_DLL_DECL mob_baltharus_cloneAI : public ScriptedAI +{ + mob_baltharus_cloneAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance *m_pInstance; + uint32 m_uiBladeTempestTimer; + uint32 m_uiEnervatingBrandTimer; + uint32 m_uiSaberLashTimer; + + void Reset() + { + if (!m_pInstance) + return; + + m_creature->SetRespawnDelay(7*DAY); + m_uiBladeTempestTimer = 22000; + m_uiEnervatingBrandTimer = 10000; + m_uiSaberLashTimer = 5000; + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(SAY_BALTHARUS_SLAY_1 - urand(0,1),m_creature,pVictim); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + m_creature->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_BALTHARUS) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBladeTempestTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLADE_TEMPEST) == CAST_OK) + m_uiBladeTempestTimer = urand(20000, 25000); + } + 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 = urand(10000, 13000); + } + } + else + m_uiEnervatingBrandTimer -= uiDiff; + + if (m_uiSaberLashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SABER_LASH) == CAST_OK) + m_uiSaberLashTimer = urand(8000, 12000); + } + else + m_uiSaberLashTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_baltharus_clone(Creature* pCreature) +{ + return new mob_baltharus_cloneAI(pCreature); +} + +void AddSC_boss_baltharus() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_baltharus"; + newscript->GetAI = &GetAI_boss_baltharus; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_baltharus_clone"; + newscript->GetAI = &GetAI_mob_baltharus_clone; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/ruby_sanctum/boss_halion.cpp b/scripts/northrend/ruby_sanctum/boss_halion.cpp index f8542d35c8..5b537cfd47 100644 --- a/scripts/northrend/ruby_sanctum/boss_halion.cpp +++ b/scripts/northrend/ruby_sanctum/boss_halion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2013 /dev/rsa for 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 @@ -16,9 +16,1875 @@ /* ScriptData SDName: boss_halion -SD%Complete: -SDComment: placeholder +SD%Complete: 90% +SDComment: by notagain, corrected by /dev/rsa && ukulutl SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" + +enum +{ + //All + SPELL_CLEAVE = 74524, + SPELL_TWILIGHT_PRECISION = 78243, // Increases Halion's chance to hit by 5% and decreases all players' chance to dodge by 20% + SPELL_BERSERK = 47008, // Increases the caster's attack and movement speeds by 150% and all damage it deals by 500% for 5 min. Also grants immunity to Taunt effects. + SPELL_START_PHASE2 = 74808, // Phases the caster into the Twilight realm, leaving behind a large rift. + SPELL_TWILIGHT_ENTER = 74807, // Phases the caster into the Twilight realm - phase 32 + SPELL_TWILIGHT_ENTER2 = 74812, // + SPELL_SUMMON_TWILIGHT_PORTAL = 74809, // + SPELL_TAIL_LASH = 74531, // A sweeping tail strike hits all enemies behind the caster, inflicting 3063 to 3937 damage and stunning them for 2 sec. + SPELL_TWILIGHT_DIVISION = 75063, // Phases the caster, allowing him to exist and act simultaneously in both the material and Twilight realms. + SPELL_TWILIGHT_CUTTER = 74768, // Inflicts 13,875 to 16,125 Shadow damage every second to players touched by the shadow beam + //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% + //METEOR STRIKE + SPELL_METEOR = 74637, // Script Start (summon NPC_METEOR_STRIKE) + SPELL_METEOR_IMPACT = 74641, // IMPACT ZONE FOR METEOR + SPELL_METEOR_STRIKE = 74648, // Inflicts 18,750 to 21,250 Fire damage to enemies within 12 yards of the targeted area. Takes about 5 seconds to land. + SPELL_METEOR_FLAME = 74718, // FLAME FROM METEOR + //N10 + SPELL_FLAME_BREATH = 74525, // Inflicts 17,500 to 22,500 Fire damage to players in front of Halion + SPELL_DARK_BREATH = 74806, // Inflicts 17,500 to 22,500 Shadow damage to players in front of Halion + SPELL_DUSK_SHROUD = 75476, // Inflicts 3,000 Shadow damage every 2 seconds to everyone in the Twilight Realm + //Combustion + NPC_COMBUSTION = 40001, + SPELL_MARK_OF_COMBUSTION = 74567, // Dummy effect only + SPELL_FIERY_COMBUSTION = 74562, // Inflicts 4,000 Fire damage every 2 seconds for 30 seconds to a random raider. Every time Fiery Combustion does damage, it applies a stackable Mark of Combustion. + SPELL_COMBUSTION_EXPLODE = 74607, + SPELL_COMBUSTION_AURA = 74629, + //Consumption + NPC_CONSUMPTION = 40135, + SPELL_MARK_OF_CONSUMPTION = 74795, // Dummy effect only + SPELL_SOUL_CONSUMPTION = 74792, // Inflicts 4,000 Shadow damage every 2 seconds for 30 seconds to a random raider. Every time Soul Consumption does damage, it applies a stackable Mark of Consumption. + SPELL_CONSUMPTION_EXPLODE = 74799, + SPELL_CONSUMPTION_AURA = 74803, + // Living Ember + SPELL_AWAKEN_FLAMES = 75889, + // Living Inferno + SPELL_BLAZING_AURA = 75885, + //Summons + NPC_METEOR_STRIKE = 40029, //casts "impact zone" then meteor + NPC_METEOR_STRIKE_1 = 40041, + NPC_METEOR_STRIKE_2 = 40042, + NPC_LIVING_INFERNO = 40681, + NPC_LIVING_EMBER = 40683, + + FR_RADIUS = 45, + + //SAYS + SAY_HALION_SPAWN = -1724024, + SAY_HALION_AGGRO = -1724025, + SAY_HALION_SLAY_1 = -1724026, + //SAY_HALION_SLAY_2 = -1666103, //17502 Ha Ha Ha! + SAY_HALION_DEATH = -1724027, + SAY_HALION_BERSERK = -1724028, + SAY_HALION_FIREBALL = -1724029, + SAY_HALION_SPHERES = -1724030, + SAY_HALION_PHASE_2 = -1724031, + SAY_HALION_PHASE_3 = -1724032, + EMOTE_SPHERES = -1724033, + EMOTE_OUT_OF_TWILIGHT = -1724034, + EMOTE_OUT_OF_PHYSICAL = -1724035, + EMOTE_INTO_TWILLIGHT = -1724036, + EMOTE_INTO_PHYSICAL = -1724037, + EMOTE_REGENERATE = -1724038, +}; + +static LOCATION SpawnLoc[]= +{ + {3154.99f, 535.637f, 72.8887f}, // 0 - Halion spawn point (center) + {3116.91f, 547.758f, 72.8887f}, // 1 - Portal 2 + {3183.96f, 525.440f, 72.8887f}, // 2 - Portal 3 +}; + +/*###### +## boss_halion_real (Physical version) +######*/ +struct MANGOS_DLL_DECL boss_halion_realAI : public ScriptedAI +{ + boss_halion_realAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIntro; + uint8 m_uiNextPoint; + bool m_bMovementStarted; + bool m_bEnrage; + uint32 m_uiStage; + uint32 m_uiTailLashTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiFieryCombustionTimer; + uint32 m_uiMeteorTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiEnrageTimer; + + void Reset() + { + if(!m_pInstance) + return; + m_creature->SetRespawnDelay(7*DAY); + + if (m_creature->isAlive()) + { + m_pInstance->SetData(TYPE_HALION, NOT_STARTED); + m_pInstance->SetData(TYPE_HALION_EVENT, FAIL); + } + + m_uiStage = 0; + m_uiNextPoint = 0; + m_uiTailLashTimer = 10000; + m_uiCleaveTimer = urand(5000, 10000); + m_uiFieryCombustionTimer = 15000; + m_uiMeteorTimer = 20000; + m_uiEnrageTimer = 8*MINUTE*IN_MILLISECONDS; + m_bIntro = false; + m_bEnrage = false; + SetCombatMovement(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_1)) + pGoPortal->Delete(); + if (GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_2)) + pGoPortal->Delete(); + if (GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_3)) + pGoPortal->Delete(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (!pWho || pWho->GetTypeId() != TYPEID_PLAYER) + return; + + if (!m_bIntro && pWho->IsWithinDistInMap(m_creature, 60.0f)) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + DoScriptText(SAY_HALION_SPAWN,m_creature); + m_bIntro = true; + m_creature->SetActiveObjectState(true); + } + + if (m_bIntro && !m_creature->isInCombat() && pWho->IsWithinDistInMap(m_creature, 20.0f)) + AttackStart(pWho); + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_HALION_EVENT) != FAIL) + return + + ScriptedAI::JustReachedHome(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_pInstance->SetData(TYPE_HALION, FAIL); + + m_creature->SetActiveObjectState(false); + } + + void EnterEvadeMode() override + { + + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_HALION_EVENT) != FAIL) + return; + + ScriptedAI::EnterEvadeMode(); + + m_creature->SetActiveObjectState(false); + } + + void EndBattle() + { + // remove all encounter auras + Map *pMap = m_creature->GetMap(); + if(pMap) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if(itr->getSource()->HasAura(SPELL_TWILIGHT_ENTER)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_ENTER); + + if(itr->getSource()->HasAura(SPELL_MARK_OF_COMBUSTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_MARK_OF_COMBUSTION); + + if(itr->getSource()->HasAura(SPELL_FIERY_COMBUSTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_FIERY_COMBUSTION); + + if(itr->getSource()->HasAura(SPELL_MARK_OF_CONSUMPTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_MARK_OF_CONSUMPTION); + + if(itr->getSource()->HasAura(SPELL_SOUL_CONSUMPTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_SOUL_CONSUMPTION); + } + } + + // remove temporary objects and creatures + if(Creature* pControl = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_CONTROL)) + pControl->ForcedDespawn(); + + if(GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_1)) + pGoPortal->Delete(); + + if(GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_2)) + pGoPortal->Delete(); + + if(GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_3)) + pGoPortal->Delete(); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + m_creature->SetActiveObjectState(false); + + if (Creature* pclone = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + { + if (!pclone->isAlive()) + { + m_pInstance->SetData(TYPE_HALION, DONE); + m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + m_pInstance->SetData(TYPE_COUNTER, COUNTER_OFF); + DoScriptText(SAY_HALION_DEATH,m_creature); + EndBattle(); + } + else + { + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + pKiller->DealDamage(pclone, pclone->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_HALION_SLAY_1 - urand(0,1), m_creature, pVictim); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->CastSpell(m_creature, SPELL_TWILIGHT_PRECISION, true); + m_creature->SetInCombatWithZone(); + m_pInstance->SetData(TYPE_HALION, IN_PROGRESS); + DoScriptText(SAY_HALION_AGGRO,m_creature); + } + + void MovementInform(uint32 type, uint32 id) + { + if (!m_pInstance) + return; + + if (type != POINT_MOTION_TYPE || !m_bMovementStarted) + return; + + if (id == m_uiNextPoint) + { + m_creature->GetMotionMaster()->MovementExpired(); + m_bMovementStarted = false; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + + void StartMovement(uint32 id) + { + m_uiNextPoint = id; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(id, SpawnLoc[id].x, SpawnLoc[id].y, SpawnLoc[id].z); + m_bMovementStarted = true; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEnrageTimer < uiDiff && !m_bEnrage) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_HALION_BERSERK, m_creature); + m_uiEnrageTimer = 8*MINUTE*IN_MILLISECONDS; + m_bEnrage = true; + } + } + else m_uiEnrageTimer -= uiDiff; + + switch (m_uiStage) + { + case 0: //PHASE 1 PHYSICAL REALM + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + // Tail Lash + if (m_uiTailLashTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(15000, 25000); + } + else m_uiTailLashTimer -= uiDiff; + + // Cleave + if (m_uiCleaveTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 15000); + } + else m_uiCleaveTimer -= uiDiff; + + // Flame Breath + if (m_uiFlameBreathTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BREATH) == CAST_OK) + m_uiFlameBreathTimer = urand(15000, 20000); + } + else m_uiFlameBreathTimer -= uiDiff; + + // Fiery Combustion + if (m_uiFieryCombustionTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIERY_COMBUSTION) == CAST_OK) + m_uiFieryCombustionTimer = 25000; + } + } + else m_uiFieryCombustionTimer -= uiDiff; + + // Meteor + if (m_uiMeteorTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_METEOR) == CAST_OK) + { + m_uiMeteorTimer = 25000; + DoScriptText(SAY_HALION_FIREBALL, m_creature); + } + } + } + else m_uiMeteorTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 75.0f) + m_uiStage = 1; + + break; + case 1: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + m_creature->AttackStop(); + m_creature->InterruptNonMeleeSpells(true); + DoScriptText(SAY_HALION_PHASE_2,m_creature); + SetCombatMovement(false); + StartMovement(0); + m_uiStage = 2; + + { + Creature* pControl = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_CONTROL); + if (!pControl) + pControl = m_creature->SummonCreature(NPC_HALION_CONTROL, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 0); + else if (!pControl->isAlive()) + pControl->Respawn(); + + pControl->SetActiveObjectState(true); + pControl->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetInCombatWith(pControl); + pControl->SetInCombatWith(m_creature); + } + + break; + case 2: + if (m_bMovementStarted) + return; + + if (GameObject* pGoPortal = m_creature->SummonGameobject(GO_HALION_PORTAL_1, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, 0, 0)) + pGoPortal->SetPhaseMask(31,true); + if (GameObject* pGoRing = m_pInstance->GetSingleGameObjectFromStorage(GO_FLAME_RING)) + pGoRing->SetPhaseMask(65535,true); + + m_uiStage = 3; + + break; + case 3: + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + m_creature->SetActiveObjectState(true); + m_creature->CastSpell(m_creature, SPELL_START_PHASE2, true); + m_uiStage = 4; + + break; + case 4: + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Creature* pControl = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_CONTROL)) + { + m_creature->SetInCombatWith(pControl); + pControl->SetInCombatWith(m_creature); + } + + Creature* pTwilight = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT); + if (!pTwilight) + pTwilight = m_creature->SummonCreature(NPC_HALION_TWILIGHT, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 1000); + else if (!pTwilight->isAlive()) + pTwilight->Respawn(); + + pTwilight->SetCreatorGuid(ObjectGuid()); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiStage = 5; + } + + break; + case 5: // HALION awaiting end battle in TWILIGHT REALM + if (m_pInstance->GetData(TYPE_HALION_EVENT) == IN_PROGRESS) + { + m_pInstance->SetData(TYPE_HALION_EVENT, SPECIAL); + m_creature->RemoveAurasDueToSpell(SPELL_START_PHASE2); + + if (Creature* pControl = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_CONTROL)) + { + m_creature->SetInCombatWith(pControl); + pControl->SetInCombatWith(m_creature); + } + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetHealth(m_creature->GetMaxHealth()/2); + m_creature->SetInCombatWithZone(); + m_uiStage = 6; + } + + break; + case 6: // Switch to phase 3 + DoScriptText(SAY_HALION_PHASE_3,m_creature); + m_uiStage = 7; + + break; + case 7: + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + if (m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) + return; + + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiStage = 8; + + break; + case 8: //PHASE 3 BOTH REALMS + if ((!m_creature->getVictim()->GetObjectGuid().IsPlayer()) && (!m_creature->getVictim()->GetObjectGuid().IsPet())) + { + if (Creature* pClone = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + { + pClone->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + else if ((m_creature->getVictim()->GetTypeId() == TYPEID_PLAYER) || (m_creature->getVictim()->GetObjectGuid().IsPet())) + { + if (Creature* pClone = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + { + pClone->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + // Tail Lash + if (m_uiTailLashTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(15000, 25000); + } + else m_uiTailLashTimer -= uiDiff; + + // Cleave + if (m_uiCleaveTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 15000); + } + else m_uiCleaveTimer -= uiDiff; + + // Flame Breath + if (m_uiFlameBreathTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BREATH) == CAST_OK) + m_uiFlameBreathTimer = urand(15000, 20000); + } + else m_uiFlameBreathTimer -= uiDiff; + + // Fiery Combustion + 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; + + // Meteor + if (m_uiMeteorTimer < uiDiff) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_METEOR) == CAST_OK) + { + m_uiMeteorTimer = 25000; + DoScriptText(SAY_HALION_FIREBALL, m_creature); + } + } + } + else m_uiMeteorTimer -= uiDiff; + + break; + default: + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_halion_real(Creature* pCreature) +{ + return new boss_halion_realAI(pCreature); +} + +/*###### +## boss_halion_twilight (Twilight version) +######*/ + +struct MANGOS_DLL_DECL boss_halion_twilightAI : public ScriptedAI +{ + boss_halion_twilightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiStage; + bool m_bIntro; + bool m_bEnrage; + uint32 m_uiTailLashTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiDarkBreathTimer; + uint32 m_uiSoulConsumptionTimer; + + void Reset() + { + if(!m_pInstance) + return; + + m_creature->SetRespawnDelay(7*DAY); + m_uiStage = 0; + m_uiTailLashTimer = 10000; + m_uiCleaveTimer = urand(5000, 10000); + m_uiDarkBreathTimer = 15000; + m_uiSoulConsumptionTimer = 20000; + m_bIntro = false; + m_bEnrage = false; + m_creature->SetInCombatWithZone(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + + if (Creature* pControl = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_CONTROL)) + { + m_creature->SetInCombatWith(pControl); + pControl->SetInCombatWith(m_creature); + } + + Creature* pFocus = m_pInstance->GetSingleCreatureFromStorage(NPC_ORB_ROTATION_FOCUS); + if (!pFocus) + pFocus = m_creature->SummonCreature(NPC_ORB_ROTATION_FOCUS, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, 0, TEMPSUMMON_MANUAL_DESPAWN, 1000); + else if (!pFocus->isAlive()) + pFocus->Respawn(); + + if (Creature* pReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + if (pReal->isAlive()) + m_creature->SetHealth(pReal->GetHealth()); + + if (!m_creature->HasAura(SPELL_TWILIGHT_ENTER)) + m_creature->CastSpell(m_creature, SPELL_TWILIGHT_ENTER, true); + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_HALION_EVENT) != FAIL || m_uiStage == 0) + return; + + ScriptedAI::JustReachedHome(); + } + + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_HALION_EVENT) != FAIL || m_uiStage == 0) + return; + + ScriptedAI::EnterEvadeMode(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (!pWho || pWho->GetTypeId() != TYPEID_PLAYER) + return; + + if (!m_bIntro && pWho->IsWithinDistInMap(m_creature, 20.0f)) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_bIntro = true; + AttackStart(pWho); + m_uiStage = 1; + m_creature->CastSpell(m_creature, SPELL_TWILIGHT_PRECISION, true); + if (Creature* pReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + if (pReal->isAlive()) + m_creature->SetHealth(pReal->GetHealth()); + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void EndBattle() + { + // remove all encounter auras + Map *pMap = m_creature->GetMap(); + if(pMap) + { + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if(itr->getSource()->HasAura(SPELL_TWILIGHT_ENTER)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_TWILIGHT_ENTER); + + if(itr->getSource()->HasAura(SPELL_MARK_OF_COMBUSTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_MARK_OF_COMBUSTION); + + if(itr->getSource()->HasAura(SPELL_FIERY_COMBUSTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_FIERY_COMBUSTION); + + if(itr->getSource()->HasAura(SPELL_MARK_OF_CONSUMPTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_MARK_OF_CONSUMPTION); + + if(itr->getSource()->HasAura(SPELL_SOUL_CONSUMPTION)) + itr->getSource()->RemoveAurasDueToSpell(SPELL_SOUL_CONSUMPTION); + } + } + + // remove temporal objects and creatures + if(Creature* pControl = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_CONTROL)) + pControl->ForcedDespawn(); + + if(GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_1)) + pGoPortal->Delete(); + + if(GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_2)) + pGoPortal->Delete(); + + if(GameObject* pGoPortal = m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_3)) + pGoPortal->Delete(); + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + if (Creature* pReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + { + if (!pReal->isAlive()) + { + m_pInstance->SetData(TYPE_HALION, DONE); + pReal->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + m_pInstance->SetData(TYPE_COUNTER, COUNTER_OFF); + DoScriptText(SAY_HALION_DEATH, m_creature); + EndBattle(); + } + else pKiller->DealDamage(pReal, pReal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + + m_creature->SetVisibility(VISIBILITY_OFF); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_HALION_SLAY_1 - urand(0,1), m_creature, pVictim); + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + + if (!m_creature->HasAura(SPELL_TWILIGHT_ENTER)) + m_creature->CastSpell(m_creature, SPELL_TWILIGHT_ENTER, true); + + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS || m_pInstance->GetData(TYPE_HALION_EVENT) == FAIL) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiStage) + { + case 0: + break; + case 1: //SPAWNED - Twilight realm + if (!m_creature->HasAura(SPELL_DUSK_SHROUD)) + m_creature->CastSpell(m_creature, SPELL_DUSK_SHROUD, true); + + // Tail Lash + if (m_uiTailLashTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(15000, 25000); + } + else m_uiTailLashTimer -= uiDiff; + + // Cleave + if (m_uiCleaveTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 15000); + } + else m_uiCleaveTimer -= uiDiff; + + // Dark Breath + if (m_uiDarkBreathTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_BREATH) == CAST_OK) + m_uiDarkBreathTimer = urand(15000, 20000); + } + else m_uiDarkBreathTimer -= uiDiff; + + // Soul Consumption + 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; + + if (m_creature->GetHealthPercent() < 50.0f) + m_uiStage = 2; + + break; + case 2: //To two realms + m_pInstance->SetData(TYPE_HALION_EVENT, IN_PROGRESS); + DoScriptText(SAY_HALION_PHASE_3,m_creature); + + if (GameObject *pGoPortal1 = m_creature->SummonGameobject(GO_HALION_PORTAL_2, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 0, 0)) + pGoPortal1->SetPhaseMask(32,true); + + if (GameObject *pGoPortal2 = m_creature->SummonGameobject(GO_HALION_PORTAL_3, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z, 0, 0)) + pGoPortal2->SetPhaseMask(32,true); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiStage = 3; + + break; + case 3: //PHASE 3 BOTH REALMS + if ((!m_creature->getVictim()->GetObjectGuid().IsPlayer()) && (!m_creature->getVictim()->GetObjectGuid().IsPet())) + { + if (Creature* pReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + { + pReal->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + else if ((m_creature->getVictim()->GetObjectGuid().IsPlayer()) || (m_creature->getVictim()->GetObjectGuid().IsPet())) + { + if (Creature* pReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + pReal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + if (!m_creature->HasAura(SPELL_DUSK_SHROUD)) + m_creature->CastSpell(m_creature, SPELL_DUSK_SHROUD, true); + + // Tail Lash + if (m_uiTailLashTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(15000, 25000); + } + else m_uiTailLashTimer -= uiDiff; + + // Cleave + if (m_uiCleaveTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 15000); + } + else m_uiCleaveTimer -= uiDiff; + + // Dark Breath + if (m_uiDarkBreathTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_BREATH) == CAST_OK) + m_uiDarkBreathTimer = urand(15000, 20000); + } + else m_uiDarkBreathTimer -= uiDiff; + + // Soul Consumption + 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; + + break; + default: + break; + } + + if (Creature* pReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + { + if(pReal->HasAura(SPELL_BERSERK) && !m_bEnrage) + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_bEnrage = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_halion_twilight(Creature* pCreature) +{ + return new boss_halion_twilightAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_halion_meteorAI : public ScriptedAI +{ + mob_halion_meteorAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance *m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + float direction, x, y, radius; + uint32 m_uiWaitTimer; + bool m_bStrike; + + void Reset() + { + DoCastSpellIfCan(m_creature, SPELL_METEOR_IMPACT, CAST_TRIGGERED); + m_creature->SetRespawnDelay(7*DAY); + SetCombatMovement(false); + + m_creature->SetInCombatWithZone(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiWaitTimer = 6000; + m_bStrike = false; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiWaitTimer < uiDiff && !m_bStrike) + { + if (DoCastSpellIfCan(m_creature, SPELL_METEOR_STRIKE) == CAST_OK) + { + if (m_bIsHeroic) + m_creature->SummonCreature(NPC_LIVING_INFERNO, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(),0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + + direction = 2.0f*M_PI_F*((float)urand(0,15)/16.0f); + radius = 0.0f; + for(uint8 i = 0; i < 10; ++i) + { + radius += 5.0f; + m_creature->GetNearPoint2D(x, y, radius, direction); + m_creature->SummonCreature(NPC_METEOR_STRIKE_1, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); + if (m_bIsHeroic && m_bIs25Man && (i%4) == 0) + m_creature->SummonCreature(NPC_LIVING_EMBER, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->GetNearPoint2D(x, y, radius, direction+M_PI_F); + m_creature->SummonCreature(NPC_METEOR_STRIKE_1, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); + if (m_bIsHeroic && m_bIs25Man && (i%4) == 0) + m_creature->SummonCreature(NPC_LIVING_EMBER, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + direction += M_PI_F/4; + radius = 0.0f; + for(uint8 i = 0; i < 10; ++i) + { + radius += 5.0f; + m_creature->GetNearPoint2D(x, y, radius, direction); + m_creature->SummonCreature(NPC_METEOR_STRIKE_1, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); + if (m_bIsHeroic && m_bIs25Man && (i%4) == 0) + m_creature->SummonCreature(NPC_LIVING_EMBER, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->GetNearPoint2D(x, y, radius, direction+M_PI_F); + m_creature->SummonCreature(NPC_METEOR_STRIKE_1, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); + if (m_bIsHeroic && m_bIs25Man && (i%4) == 0) + m_creature->SummonCreature(NPC_LIVING_EMBER, x, y, m_creature->GetPositionZ(),0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + m_creature->ForcedDespawn(10000); + m_bStrike = true; + m_uiWaitTimer = 1000; + } + } + else + m_uiWaitTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_halion_meteor(Creature* pCreature) +{ + return new mob_halion_meteorAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_halion_flameAI : public ScriptedAI +{ + mob_halion_flameAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance *m_pInstance; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetDisplayId(11686); + m_creature->SetRespawnDelay(7*DAY); + SetCombatMovement(false); + m_creature->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->HasAura(SPELL_METEOR_FLAME)) + m_creature->CastSpell(m_creature, SPELL_METEOR_FLAME, true); + } + +}; + +CreatureAI* GetAI_mob_halion_flame(Creature* pCreature) +{ + return new mob_halion_flameAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_living_emberAI : public ScriptedAI +{ + mob_living_emberAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance *m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + uint32 m_uiWaitTimer; + + void Reset() + { + m_uiWaitTimer = 6000; + } + + void Aggro(Unit *pWho) + { + SetCombatMovement(false); + m_creature->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiWaitTimer < uiDiff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + m_creature->ForcedDespawn(); + + SetCombatMovement(true); + DoMeleeAttackIfReady(); + + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + else m_uiWaitTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_living_ember(Creature* pCreature) +{ + return new mob_living_emberAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_living_infernoAI : public ScriptedAI +{ + mob_living_infernoAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance *m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + uint32 m_uiWaitTimer; + + void Reset() + { + m_uiWaitTimer = 6000; + } + + void Aggro(Unit *pWho) + { + SetCombatMovement(false); + m_creature->SetInCombatWithZone(); + m_creature->CastSpell(m_creature, SPELL_BLAZING_AURA, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_uiWaitTimer < uiDiff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + m_creature->ForcedDespawn(); + + if (!m_creature->HasAura(SPELL_BLAZING_AURA)) + m_creature->CastSpell(m_creature, SPELL_BLAZING_AURA, true); + + SetCombatMovement(true); + DoMeleeAttackIfReady(); + + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + else m_uiWaitTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_living_inferno(Creature* pCreature) +{ + return new mob_living_infernoAI(pCreature); +}; + +struct HalionBuffLine +{ + float uiDiff; // Health uiDiff in percent + uint32 real, twilight; // Buff pair + uint8 disp_corp; // Displayed Corporeality +}; + +static HalionBuffLine Buff[]= +{ + {-10.0f, SPELL_CORPOREALITY_100D , SPELL_CORPOREALITY_100I , 0 }, + {-8.0f, SPELL_CORPOREALITY_80D , SPELL_CORPOREALITY_80I , 10 }, + {-6.0f, SPELL_CORPOREALITY_60D , SPELL_CORPOREALITY_60I , 20 }, + {-4.0f, SPELL_CORPOREALITY_40D , SPELL_CORPOREALITY_40I , 30 }, + {-2.0f, SPELL_CORPOREALITY_20D , SPELL_CORPOREALITY_20I , 40 }, + {-1.0f, SPELL_CORPOREALITY_EVEN , SPELL_CORPOREALITY_EVEN , 50 }, + {1.0f, SPELL_CORPOREALITY_EVEN , SPELL_CORPOREALITY_EVEN , 50 }, + {2.0f, SPELL_CORPOREALITY_20I , SPELL_CORPOREALITY_20D , 60 }, + {4.0f, SPELL_CORPOREALITY_40I , SPELL_CORPOREALITY_40D , 70 }, + {6.0f, SPELL_CORPOREALITY_60I , SPELL_CORPOREALITY_60D , 80 }, + {8.0f, SPELL_CORPOREALITY_80I , SPELL_CORPOREALITY_80D , 90 }, + {10.0f, SPELL_CORPOREALITY_100I , SPELL_CORPOREALITY_100D , 100 }, +}; + +struct MANGOS_DLL_DECL mob_halion_controlAI : public ScriptedAI +{ + mob_halion_controlAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + Difficulty m_uiMapDifficulty; + bool m_bIsHeroic; + bool m_bIs25Man; + + uint32 m_lastBuffReal, m_lastBuffTwilight; + uint32 m_corporealityTimer; + bool wipe; + + bool p_Last; + + float p_RealDamage, p_TwilightDamage; + float p_LastHP; + + float p_RealCorp, p_TwilightCorp; + + void Reset() + { + if (!m_pInstance) + return; + + m_creature->SetDisplayId(11686); + m_creature->SetPhaseMask(65535, true); + m_creature->SetRespawnDelay(7*DAY); + SetCombatMovement(false); + m_lastBuffReal = 0; + m_lastBuffTwilight = 0; + m_corporealityTimer = 5000; + wipe = false; + m_creature->SetActiveObjectState(true); + m_pInstance->SetData(TYPE_COUNTER, COUNTER_OFF); + m_pInstance->SetData(TYPE_HALION_EVENT, NOT_STARTED); + + p_Last = false; + p_RealDamage = p_TwilightDamage = 0; + p_RealCorp = p_TwilightCorp = m_bIs25Man ? (m_bIsHeroic ? 29284500 : 20220000) : (m_bIsHeroic ? 7669500 : 5578000); + } + + void AttackStart(Unit *who) + { + //ignore all attackstart commands + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_pInstance) + return; + + wipe = true; + + Map *pMap = m_creature->GetMap(); + if(!pMap) return; + + Map::PlayerList const &players = pMap->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if(itr->getSource()->isAlive()) + { + wipe = false; + break; + } + } + + if (wipe) + { + m_pInstance->SetData(TYPE_HALION_EVENT, FAIL); + m_pInstance->SetData(TYPE_HALION, FAIL); + m_creature->ForcedDespawn(); + } + + if(!m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_1)) + { + if (GameObject* pGoPortal1 = m_creature->SummonGameobject(GO_HALION_PORTAL_1, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z, 0, 0)) + pGoPortal1->SetPhaseMask(31,true); + } + + if (m_pInstance->GetData(TYPE_HALION_EVENT) != SPECIAL) return; + + if(!m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_2)) + { + if (GameObject *pGoPortal2 = m_creature->SummonGameobject(GO_HALION_PORTAL_2, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z, 0, 0)) + pGoPortal2->SetPhaseMask(32,true); + } + + if(!m_pInstance->GetSingleGameObjectFromStorage(GO_HALION_PORTAL_3)) + { + if (GameObject *pGoPortal3 = m_creature->SummonGameobject(GO_HALION_PORTAL_3, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z, 0, 0)) + pGoPortal3->SetPhaseMask(32,true); + } + + Creature* pHalionReal = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL); + Creature* pHalionTwilight = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT); + + if (!pHalionTwilight || !pHalionReal) + return; + + pHalionTwilight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + // CORPOREALITY + if (m_corporealityTimer <= uiDiff) + { + // calculate damage for corporeality + float p_RealHP = (pHalionReal && pHalionReal->isAlive()) ? pHalionReal->GetHealth() : 0.0f; + float p_TwilightHP = (pHalionTwilight && pHalionTwilight->isAlive()) ? pHalionTwilight->GetHealth() : 0.0f; + + if(!p_Last) + { + p_LastHP = p_RealHP >= p_TwilightHP ? p_RealHP : p_TwilightHP; + p_Last = true; + } + + if(pHalionTwilight->isAlive() && pHalionReal->isAlive()) + { + p_RealDamage = p_LastHP - p_RealHP; + p_TwilightDamage = p_LastHP - p_TwilightHP; + + p_LastHP = p_RealHP >= p_TwilightHP ? p_TwilightHP - p_RealDamage : p_RealHP - p_TwilightDamage; + p_LastHP = p_LastHP > 0 ? p_LastHP : 1; + + pHalionReal->SetHealth(p_LastHP); + pHalionTwilight->SetHealth(p_LastHP); + } + + p_TwilightCorp -= p_TwilightDamage; + p_RealCorp -= p_RealDamage; + + // calculate corporeality (halion hp %) + float m_uiDiff = + (p_RealCorp / (m_bIs25Man ? (m_bIsHeroic ? 585690 : 404400) : (m_bIsHeroic ? 153390 : 111560))) + - + (p_TwilightCorp / (m_bIs25Man ? (m_bIsHeroic ? 585690 : 404400) : (m_bIsHeroic ? 153390 : 111560))); + + uint8 buffnum = 0; + if (m_uiDiff <= Buff[0].uiDiff) + { + buffnum = 0; + } + else + { + for (uint8 i = 0; i < 11; i++) + { + if (m_uiDiff >= Buff[i].uiDiff) + { + buffnum = i+1; + } + else + { + break; + } + } + } + + if (!m_lastBuffReal || m_lastBuffReal != Buff[buffnum].real) + { + if (m_lastBuffReal) + { + pHalionReal->RemoveAurasDueToSpell(m_lastBuffReal); + } + + if(Buff[buffnum].real > m_lastBuffReal) DoScriptText(EMOTE_OUT_OF_TWILIGHT, pHalionTwilight); + + pHalionReal->CastSpell(pHalionReal, Buff[buffnum].real, true); + m_lastBuffReal = Buff[buffnum].real; + } + + if (!m_lastBuffTwilight || m_lastBuffTwilight != Buff[buffnum].twilight) + { + if (m_lastBuffTwilight) + { + pHalionTwilight->RemoveAurasDueToSpell(m_lastBuffTwilight); + } + + if(Buff[buffnum].twilight > m_lastBuffTwilight) DoScriptText(EMOTE_OUT_OF_PHYSICAL, pHalionReal); + + pHalionTwilight->CastSpell(pHalionTwilight, Buff[buffnum].twilight, true); + m_lastBuffTwilight = Buff[buffnum].twilight; + } + + m_pInstance->SetData(TYPE_COUNTER, (uint32)Buff[buffnum].disp_corp); + + m_corporealityTimer = 5000; + } + else m_corporealityTimer -= uiDiff; + } + +}; + +CreatureAI* GetAI_mob_halion_control(Creature* pCreature) +{ + return new mob_halion_controlAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_orb_rotation_focusAI : public ScriptedAI +{ + mob_orb_rotation_focusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->GetDifficulty() > RAID_DIFFICULTY_25MAN_NORMAL; + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_timer; + float m_direction, m_nextdirection; + bool m_warning; + + void Reset() + { + m_creature->SetDisplayId(11686); + m_creature->SetRespawnDelay(7*DAY); + m_creature->SetPhaseMask(65535, true); + SetCombatMovement(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_direction = 0.0f; + m_nextdirection = 0.0f; + m_timer = 30000; + m_warning = false; + + Creature* pPulsar1 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_N); + if (!pPulsar1 ) + { + float x,y; + m_creature->GetNearPoint2D(x, y, FR_RADIUS, m_direction); + pPulsar1 = m_creature->SummonCreature(NPC_SHADOW_PULSAR_N, x, y, m_creature->GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + } + else if (!pPulsar1->isAlive()) pPulsar1->Respawn(); + + Creature* pPulsar2 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_S); + if (!pPulsar2) + { + float x,y; + m_creature->GetNearPoint2D(x, y, FR_RADIUS, m_direction + M_PI_F); + pPulsar2 = m_creature->SummonCreature(NPC_SHADOW_PULSAR_S, x, y, m_creature->GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + } + else if (!pPulsar2->isAlive()) pPulsar2->Respawn(); + + if(m_bIsHeroic) + {/* TODO: + Creature* pPulsar3 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_E); + if (!pPulsar3) + { + float x,y; + m_creature->GetNearPoint2D(x, y, FR_RADIUS, m_direction + M_PI_F); + pPulsar3 = m_creature->SummonCreature(NPC_SHADOW_PULSAR_E, x, y, m_creature->GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + } + else if (!pPulsar3->isAlive()) pPulsar3->Respawn(); + + Creature* pPulsar4 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_W); + if (!pPulsar4) + { + float x,y; + m_creature->GetNearPoint2D(x, y, FR_RADIUS, m_direction + M_PI_F); + pPulsar4 = m_creature->SummonCreature(NPC_SHADOW_PULSAR_W, x, y, m_creature->GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + } + else if (!pPulsar4->isAlive()) pPulsar4->Respawn(); + */} + } + + void AttackStart(Unit *who) + { + //ignore all attackstart commands + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (m_pInstance->GetData(DATA_ORB_S) == DONE && m_pInstance->GetData(DATA_ORB_N) == DONE) + { + m_direction = m_nextdirection; + m_nextdirection = (m_direction - M_PI_F/64.0f); + + if (m_nextdirection < 0.0f ) m_nextdirection = m_nextdirection + 2.0f*M_PI_F; + + m_pInstance->SetData(DATA_ORB_DIRECTION, (uint32)(m_nextdirection*1000)); + m_pInstance->SetData(DATA_ORB_N, SPECIAL); + m_pInstance->SetData(DATA_ORB_S, SPECIAL); + debug_log("EventMGR: creature %u send direction %u ",m_creature->GetEntry(),m_pInstance->GetData(DATA_ORB_DIRECTION)); + } + + if (m_timer - 6000 <= uiDiff && !m_warning) + { + DoScriptText(EMOTE_SPHERES, m_creature); + m_warning = true; + } + + if (m_timer <= uiDiff) + { + float x,y; + m_creature->GetNearPoint2D(x, y, FR_RADIUS, m_nextdirection); + m_creature->SummonCreature(NPC_ORB_CARRIER, x, y, m_creature->GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 5000); + m_timer = 30000; + m_warning = false; + + //cast twilight cutter + Creature* pPulsar1 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_N); + Creature* pPulsar2 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_S); + if(pPulsar1 && pPulsar2) + { + // uncomment when implemented in core + //pPulsar1->CastSpell(pPulsar2, SPELL_TWILIGHT_CUTTER, true); + } + + if(m_bIsHeroic) + {/* TODO: + Creature* pPulsar3 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_E); + Creature* pPulsar4 = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADOW_PULSAR_W); + if(pPulsar3 && pPulsar4) + { + pPulsar3->CastSpell(pPulsar4, SPELL_TWILIGHT_CUTTER, true); + }*/ + } + } + else m_timer -= uiDiff; + } +}; + +CreatureAI* GetAI_mob_orb_rotation_focus(Creature* pCreature) +{ + return new mob_orb_rotation_focusAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_halion_orbAI : public ScriptedAI +{ + mob_halion_orbAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + + ScriptedInstance *m_pInstance; + float m_direction,m_delta; + uint32 m_flag; + uint32 m_flag1; + bool m_bMovementStarted; + Creature* focus; + uint32 m_uiNextPoint; + + void Reset() + { + if (!m_pInstance) + return; + + m_creature->SetRespawnDelay(7*DAY); + SetCombatMovement(false); + m_creature->SetPhaseMask(32, true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (m_creature->GetEntry() == NPC_SHADOW_PULSAR_N) + { + m_flag = DATA_ORB_N; + m_delta = 0.0f; + } + else if (m_creature->GetEntry() == NPC_SHADOW_PULSAR_S) + { + m_flag = DATA_ORB_S; + m_delta = M_PI_F; + } + + m_direction = 0.0f; + m_uiNextPoint = 0; + m_bMovementStarted = false; + m_pInstance->SetData(m_flag, DONE); + debug_log("EventMGR: creature %u assume m_flag %u ",m_creature->GetEntry(),m_flag); + } + + void AttackStart(Unit *who) + { + //ignore all attackstart commands + return; + } + + void MovementInform(uint32 type, uint32 id) + { + if (!m_pInstance) return; + + if (type != POINT_MOTION_TYPE || !m_bMovementStarted) return; + + if (id == m_uiNextPoint) + { + m_creature->GetMotionMaster()->MovementExpired(); + m_bMovementStarted = false; + m_pInstance->SetData(m_flag, DONE); + } + } + + void StartMovement(uint32 id) + { + if (!m_pInstance) + return; + + m_uiNextPoint = id; + float x,y; + m_pInstance->SetData(m_flag, IN_PROGRESS); + m_bMovementStarted = true; + m_direction = ((float)m_pInstance->GetData(DATA_ORB_DIRECTION)/1000 + m_delta); + + if (m_direction > 2.0f*M_PI_F) + m_direction = m_direction - 2.0f*M_PI_F; + + focus = m_pInstance->GetSingleCreatureFromStorage(NPC_ORB_ROTATION_FOCUS); + if (focus) + { + focus->GetNearPoint2D(x, y, FR_RADIUS, m_direction); + } + else + { + m_creature->ForcedDespawn(); + } + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(id, x, y, m_creature->GetPositionZ()); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_bMovementStarted && m_pInstance->GetData(m_flag) == SPECIAL) + { + StartMovement(1); + } + + } +}; + +CreatureAI* GetAI_mob_halion_orb(Creature* pCreature) +{ + return new mob_halion_orbAI(pCreature); +} + +struct MANGOS_DLL_DECL mob_orb_carrierAI : public ScriptedAI +{ + mob_orb_carrierAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bMovementStarted; + + void Reset() + { + m_creature->SetRespawnDelay(7*DAY); + SetCombatMovement(false); + m_creature->SetPhaseMask(32, true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_bMovementStarted = false; + m_creature->SetWalk(false); + m_creature->SetSpeedRate(MOVE_RUN, 6.0f); + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void MovementInform(uint32 type, uint32 id) + { + if (!m_pInstance) return; + + if (type != POINT_MOTION_TYPE || !m_bMovementStarted) return; + + if (id == 1) + { + m_creature->GetMotionMaster()->MovementExpired(); + m_bMovementStarted = false; + m_creature->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_bMovementStarted) + { + float x,y; + float m_direction = ((float)m_pInstance->GetData(DATA_ORB_DIRECTION)/1000.0f + M_PI_F - M_PI_F/32.0f); + + if (m_direction > 2.0f*M_PI_F) m_direction = m_direction - 2.0f*M_PI_F; + + if (Creature* focus = m_pInstance->GetSingleCreatureFromStorage(NPC_ORB_ROTATION_FOCUS)) + focus->GetNearPoint2D(x, y, FR_RADIUS, m_direction); + else + m_creature->ForcedDespawn(); + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(1, x, y, m_creature->GetPositionZ()); + m_bMovementStarted = true; + } + + } + +}; + +CreatureAI* GetAI_mob_orb_carrier(Creature* pCreature) +{ + return new mob_orb_carrierAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_soul_consumptionAI : public ScriptedAI +{ + mob_soul_consumptionAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + bool m_bIs25Man; + Difficulty m_uiMapDifficulty; + + void Reset() + { + if (!m_bIsHeroic) + m_creature->SetPhaseMask(32,true); + else + m_creature->SetPhaseMask(65535,true); + + SetCombatMovement(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->CastSpell(m_creature, SPELL_CONSUMPTION_AURA, true); + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if(m_pInstance && m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + m_creature->ForcedDespawn(20000); + } +}; + +CreatureAI* GetAI_mob_soul_consumption(Creature* pCreature) +{ + return new mob_soul_consumptionAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_fiery_combustionAI : public ScriptedAI +{ + mob_fiery_combustionAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + bool m_bIs25Man; + Difficulty m_uiMapDifficulty; + + void Reset() + { + if (!m_bIsHeroic) + m_creature->SetPhaseMask(31,true); + else + m_creature->SetPhaseMask(65535,true); + + SetCombatMovement(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->CastSpell(m_creature, SPELL_COMBUSTION_AURA, true); + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if(m_pInstance && m_pInstance->GetData(TYPE_HALION) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + m_creature->ForcedDespawn(20000); + } + +}; + +CreatureAI* GetAI_mob_fiery_combustion(Creature* pCreature) +{ + return new mob_fiery_combustionAI(pCreature); +}; + + +bool GOHello_go_halion_portal_twilight(Player *player, GameObject* pGo) +{ + ScriptedInstance* m_pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + + if(!m_pInstance) return false; + + player->CastSpell(player,SPELL_TWILIGHT_ENTER,false); + + return true; +} + +bool GOHello_go_halion_portal_real(Player *player, GameObject* pGo) +{ + ScriptedInstance* m_pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + + if(!m_pInstance) return false; + + player->RemoveAurasDueToSpell(SPELL_TWILIGHT_ENTER); + + return true; +} + +void AddSC_boss_halion() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_halion_real"; + newscript->GetAI = &GetAI_boss_halion_real; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "boss_halion_twilight"; + newscript->GetAI = &GetAI_boss_halion_twilight; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_halion_meteor"; + newscript->GetAI = &GetAI_mob_halion_meteor; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_halion_flame"; + newscript->GetAI = &GetAI_mob_halion_flame; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_living_ember"; + newscript->GetAI = &GetAI_mob_living_ember; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_living_inferno"; + newscript->GetAI = &GetAI_mob_living_inferno; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_halion_orb"; + newscript->GetAI = &GetAI_mob_halion_orb; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_halion_control"; + newscript->GetAI = &GetAI_mob_halion_control; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_orb_rotation_focus"; + newscript->GetAI = &GetAI_mob_orb_rotation_focus; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_orb_carrier"; + newscript->GetAI = &GetAI_mob_orb_carrier; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_soul_consumption"; + newscript->GetAI = &GetAI_mob_soul_consumption; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_fiery_combustion"; + newscript->GetAI = &GetAI_mob_fiery_combustion; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "go_halion_portal_twilight"; + newscript->pGOUse = &GOHello_go_halion_portal_twilight; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "go_halion_portal_real"; + newscript->pGOUse = &GOHello_go_halion_portal_real; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/ruby_sanctum/boss_saviana.cpp b/scripts/northrend/ruby_sanctum/boss_saviana.cpp index 1a44e564eb..3a5bda3904 100644 --- a/scripts/northrend/ruby_sanctum/boss_saviana.cpp +++ b/scripts/northrend/ruby_sanctum/boss_saviana.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2013 /dev/rsa for 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 @@ -16,9 +16,240 @@ /* ScriptData SDName: boss_saviana -SD%Complete: -SDComment: placeholder +SD%Complete: 99% +SDComment: by notagain && /dev/rsa && carlos93 SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" + +enum BossSpells +{ + SPELL_ENRAGE = 78722, //soft enrage + fire nova + SPELL_FLAME_BREATH = 74404, + SPELL_BEACON = 74453, //mark for conflag, in enter to fly phase, 2 in 10, 5 in 25 + SPELL_CONFLAGATION = 74452, // after fly up + SPELL_CONFLAGATION_1 = 74455, // Triggered? + SPELL_CONFLAGATION_2 = 74456, // Aura +}; + +enum Yells +{ + SAY_AGGRO = -1724015, + SAY_SLAY_1 = -1724016, + SAY_SLAY_2 = -1724017, + //SAY_DEATH = -1666403, + SAY_SPECIAL = -1724018, + //SAY_ENRAGE = -1666405, +}; + +enum +{ + PHASE_GROUND = 0, + PHASE_FLYING = 1, + PHASE_AIR = 2, + + POINT_LAND = 0, + POINT_AIR = 1, +}; + +static LOCATION SpawnLoc[]= +{ + {3151.3898f, 636.8519f, 78.7396f}, // 0 Saviana start point + {3149.6350f, 668.9644f, 90.5070f}, // 1 Saviana fly phase, o=4,69 +}; + +struct MANGOS_DLL_DECL boss_savianaAI : public ScriptedAI +{ + boss_savianaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_uiMapDifficulty = pCreature->GetMap()->GetDifficulty(); + m_bIsHeroic = m_uiMapDifficulty > RAID_DIFFICULTY_25MAN_NORMAL; + m_bIs25Man = (m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_NORMAL || m_uiMapDifficulty == RAID_DIFFICULTY_25MAN_HEROIC); + Reset(); + } + + ScriptedInstance *m_pInstance; + Difficulty m_uiMapDifficulty; + + bool m_bIs25Man; + bool m_bIsHeroic; + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiFlyingTimer; + + void Reset() + { + if (!m_pInstance) + return; + + m_creature->SetRespawnDelay(7*DAY); + + if (m_creature->isAlive()) + m_pInstance->SetData(TYPE_RAGEFIRE, NOT_STARTED); + + m_uiPhase = PHASE_GROUND; + m_uiPhaseTimer = 32000; + m_uiEnrageTimer = urand(20000,30000); + m_uiFlameBreathTimer = urand(6000, 10000); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_AIR) + { + m_uiPhase = PHASE_AIR; + + int max = m_bIs25Man ? 5 : 2; + + for (int i = 0; i < max; ++i) + { + if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BEACON, SELECT_FLAG_PLAYER)) + m_creature->CastSpell(pTarget, SPELL_BEACON, true); + } + } + else if (uiData == POINT_LAND) + { + m_uiPhase = PHASE_GROUND; + SetCombatMovement(true); + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_SLAY_1 - urand(0, 1), m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_RAGEFIRE, FAIL); + + SetCombatMovement(true); + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); + } + + void Aggro(Unit *who) + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_RAGEFIRE, IN_PROGRESS); + m_creature->SetInCombatWithZone(); + DoScriptText(SAY_AGGRO, m_creature, who); + } + + void JustDied(Unit *killer) + { + if (!m_pInstance) + return; + + m_pInstance->SetData(TYPE_RAGEFIRE, DONE); + //DoScriptText(SAY_DEATH, m_creature, killer); + } + + 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(10000,15000); + if (m_uiPhaseTimer <= 5000) + m_uiPhaseTimer = 5000; + } + else + m_uiFlameBreathTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + if(DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + m_uiEnrageTimer = urand(20000,30000); + //DoScriptText(SAY_ENRAGE, m_creature); + if (m_uiPhaseTimer <= 10000) + m_uiPhaseTimer = 10000; + } + } + else + m_uiEnrageTimer -= uiDiff; + + if (m_uiPhaseTimer < uiDiff) + { + m_uiPhaseTimer = 15000; + m_uiPhase = PHASE_FLYING; + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_AIR, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + } + else + m_uiPhaseTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + case PHASE_FLYING: + if (m_creature->IsNonMeleeSpellCasted(true)) + return; + + if (m_uiFlyingTimer <= uiDiff) + { + m_uiFlyingTimer = 30000; + m_creature->AI()->EnterEvadeMode(); + return; + } + else + m_uiFlyingTimer -= uiDiff; + + return; + case PHASE_AIR: + if (m_uiPhaseTimer < uiDiff) + { + m_uiPhase = PHASE_FLYING; + m_uiPhaseTimer = 30000; + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_LAND, SpawnLoc[0].x, SpawnLoc[0].y, SpawnLoc[0].z); + } + else + m_uiPhaseTimer -= uiDiff; + + return; + default: + break; + } + } +}; + +CreatureAI* GetAI_boss_saviana(Creature* pCreature) +{ + return new boss_savianaAI(pCreature); +} + +void AddSC_boss_saviana() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_saviana"; + newscript->GetAI = &GetAI_boss_saviana; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp b/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp new file mode 100644 index 0000000000..9bcbc43aa3 --- /dev/null +++ b/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp @@ -0,0 +1,229 @@ +/* Copyright (C) 2013 /dev/rsa for 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_zarithrian +SD%Complete: 90% +SDComment: by /dev/rsa && notagain +SDCategory: Ruby Sanctum +EndScriptData */ + +// Need correct timers + +#include "precompiled.h" +#include "ruby_sanctum.h" + +enum BossSpells +{ + SPELL_CALL_FLAMECALLER = 74398, + SPELL_CLEAVE_ARMOR = 74367, + SPELL_IMTIMIDATING_ROAR = 74384, + SPELL_LAVA_GOUT = 74394, + SPELL_BLAST_NOVA = 74392, + + NPC_FLAMECALLER = 39814, +}; + +enum Equipment +{ + EQUIP_MAIN = 47156, + EQUIP_OFFHAND = 51812, + EQUIP_RANGED = EQUIP_NO_CHANGE, + EQUIP_DONE = EQUIP_NO_CHANGE, +}; + +static LOCATION SpawnLoc[]= +{ + {3008.552734f, 530.471680f, 89.195290f}, // 0 - Zarithrian start point, o = 6,16 + {3014.313477f, 486.453735f, 89.255096f}, // 1 - Mob spawn 1 + {3025.324951f, 580.588501f, 88.593185f}, // 2 - Mob spawn 2 +}; + +enum +{ + SAY_AGGRO = -1724019, + SAY_SLAY_1 = -1724020, + SAY_SLAY_2 = -1724021, + SAY_DEATH = -1724022, + SAY_SUMMON = -1724023, +}; + +struct MANGOS_DLL_DECL boss_zarithrianAI : public BSWScriptedAI +{ + boss_zarithrianAI(Creature* pCreature) : BSWScriptedAI(pCreature) + { + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance *pInstance; + + void Reset() + { + if(!pInstance) + return; + + if (m_creature->isAlive()) + { + pInstance->SetData(TYPE_ZARITHRIAN, NOT_STARTED); + resetTimers(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + setStage(0); + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (getStage()) + ScriptedAI::MoveInLineOfSight(pWho); + + if (!getStage() && + pInstance->GetData(TYPE_XERESTRASZA) == DONE && + pInstance->GetData(TYPE_BALTHARUS) == DONE && + pInstance->GetData(TYPE_RAGEFIRE) == DONE) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + setStage(1); + }; + } + + void KilledUnit(Unit* pVictim) override + { + switch (urand(0,1)) + { + case 0: + DoScriptText(SAY_SLAY_1,m_creature,pVictim); + break; + case 1: + DoScriptText(SAY_SLAY_2,m_creature,pVictim); + break; + }; + } + + void JustReachedHome() override + { + if (!pInstance) return; + pInstance->SetData(TYPE_ZARITHRIAN, FAIL); + } + + void JustSummoned(Creature* summoned) + { + if(!pInstance || !summoned) return; + + summoned->SetInCombatWithZone(); + if (Unit* pTarget = doSelectRandomPlayerAtRange(60.0f)) + { + summoned->AddThreat(pTarget, 100.0f); + summoned->GetMotionMaster()->MoveChase(pTarget); + } + + } + + void Aggro(Unit *who) + { + if(!pInstance) return; + + SetEquipmentSlots(false, EQUIP_MAIN, EQUIP_OFFHAND, EQUIP_RANGED); + pInstance->SetData(TYPE_ZARITHRIAN, IN_PROGRESS); + DoScriptText(SAY_AGGRO,m_creature); + } + + void JustDied(Unit *killer) + { + if(!pInstance) return; + + pInstance->SetData(TYPE_ZARITHRIAN, DONE); + DoScriptText(SAY_DEATH,m_creature); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (timedQuery(SPELL_CALL_FLAMECALLER, diff)) + { + doSummon(NPC_FLAMECALLER, SpawnLoc[1].x, SpawnLoc[1].y, SpawnLoc[1].z); + doSummon(NPC_FLAMECALLER, SpawnLoc[2].x, SpawnLoc[2].y, SpawnLoc[2].z); + +// if (currentDifficulty == RAID_DIFFICULTY_25MAN_NORMAL +// || currentDifficulty == RAID_DIFFICULTY_25MAN_HEROIC) +// doCast(SPELL_CALL_FLAMECALLER); + + DoScriptText(SAY_SUMMON,m_creature); + } + + timedCast(SPELL_CLEAVE_ARMOR, diff); + timedCast(SPELL_IMTIMIDATING_ROAR, diff); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_zarithrian(Creature* pCreature) +{ + return new boss_zarithrianAI(pCreature); +}; + +struct MANGOS_DLL_DECL mob_flamecaller_rubyAI : public BSWScriptedAI +{ + mob_flamecaller_rubyAI(Creature *pCreature) : BSWScriptedAI(pCreature) + { + pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + + ScriptedInstance *pInstance; + + void Reset() + { + if(!pInstance) return; + resetTimers(); + m_creature->SetRespawnDelay(7*DAY); + } + + void UpdateAI(const uint32 diff) + { + + if (pInstance && pInstance->GetData(TYPE_ZARITHRIAN) != IN_PROGRESS) + m_creature->ForcedDespawn(); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + doCastAll(diff); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_flamecaller_ruby(Creature* pCreature) +{ + return new mob_flamecaller_rubyAI(pCreature); +}; + +void AddSC_boss_zarithrian() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_zarithrian"; + newscript->GetAI = &GetAI_boss_zarithrian; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_flamecaller_ruby"; + newscript->GetAI = &GetAI_mob_flamecaller_ruby; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp b/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp new file mode 100644 index 0000000000..3568f4031b --- /dev/null +++ b/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp @@ -0,0 +1,376 @@ +/* Copyright (C) 2006 - 2013 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: instance_ruby_sanctum +SD%Complete: 50% +SDComment: by notagain, corrected by /dev/rsa +SDCategory: ruby_sanctum +EndScriptData */ + +//TODO: Trash mobs, spawn and removal of fire ring/walls, spawn of halion + +#include "precompiled.h" +#include "ruby_sanctum.h" + +struct MANGOS_DLL_DECL instance_ruby_sanctum : public BSWScriptedInstance +{ + instance_ruby_sanctum(Map* pMap) : BSWScriptedInstance(pMap) + { + Initialize(); + } + + bool needSave; + std::string strSaveData; + + //Creatures GUID + uint32 m_auiEncounter[MAX_ENCOUNTERS+1]; + + uint32 m_auiEventTimer; + uint32 m_auiHalionEvent; + + uint32 m_auiOrbDirection; + uint32 m_auiOrbNState; + uint32 m_auiOrbSState; + + uint64 m_uiHalion_pGUID; + uint64 m_uiHalion_tGUID; + uint64 m_uiHalionControlGUID; + uint64 m_uiRagefireGUID; + uint64 m_uiZarithrianGUID; + uint64 m_uiBaltharusGUID; + uint64 m_uiCloneGUID; + uint64 m_uiXerestraszaGUID; + + uint64 m_uiOrbNGUID; + uint64 m_uiOrbSGUID; + uint64 m_uiOrbFocusGUID; + uint64 m_uiOrbCarrierGUID; + + //object GUID + uint64 m_uiHalionPortal1GUID; + uint64 m_uiHalionPortal2GUID; + uint64 m_uiHalionPortal3GUID; + uint64 m_uiHalionFireWallSGUID; + uint64 m_uiHalionFireWallMGUID; + uint64 m_uiHalionFireWallLGUID; + uint64 m_uiBaltharusTargetGUID; + + uint64 m_uiFireFieldGUID; + uint64 m_uiFlameWallsGUID; + uint64 m_uiFlameRingGUID; + + void Initialize() override + { + for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + m_auiEncounter[i] = NOT_STARTED; + + m_auiEventTimer = 1000; + + m_uiHalion_pGUID = 0; + m_uiHalion_tGUID = 0; + m_uiRagefireGUID = 0; + m_uiZarithrianGUID = 0; + m_uiBaltharusGUID = 0; + m_uiCloneGUID = 0; + m_uiHalionPortal1GUID = 0; + m_uiHalionPortal2GUID = 0; + m_uiHalionPortal3GUID = 0; + m_uiXerestraszaGUID = 0; + m_uiHalionFireWallSGUID = 0; + m_uiHalionFireWallMGUID = 0; + m_uiHalionFireWallLGUID = 0; + m_uiBaltharusTargetGUID = 0; + m_auiOrbDirection = 0; + m_uiOrbNGUID = 0; + m_uiOrbSGUID = 0; + m_uiOrbFocusGUID = 0; + m_auiOrbNState = NOT_STARTED; + m_auiOrbSState = NOT_STARTED; + + } + + bool IsEncounterInProgress() const override + { + for(uint8 i = 1; i < MAX_ENCOUNTERS ; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + + return false; + } + + void UpdateWorldState(bool command, uint32 value) + { + Map::PlayerList const &players = instance->GetPlayers(); + + if (command) + { + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + if(Player* pPlayer = i->getSource()) + { + if(pPlayer->isAlive()) + { + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_SHOW,0); + if (pPlayer->HasAura(74807)) + { + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_COUNT_T, 100 - value); + } + else + { + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_COUNT_R, value); + } + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_SHOW,1); + } + } + } + } + else + { + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + if(Player* pPlayer = i->getSource()) + { + if(pPlayer->isAlive()) + { + pPlayer->SendUpdateWorldState(UPDATE_STATE_UI_SHOW,0); + } + } + } + } + } + + void OpenAllDoors() + { + if (m_auiEncounter[TYPE_RAGEFIRE] == DONE && + m_auiEncounter[TYPE_BALTHARUS] == DONE && + m_auiEncounter[TYPE_XERESTRASZA] == DONE) + DoOpenDoor(GO_FLAME_WALLS); + else + DoCloseDoor(GO_FLAME_WALLS); + } + + void OnCreatureCreate(Creature* pCreature) override + { + switch(pCreature->GetEntry()) + { + case NPC_HALION_REAL: + case NPC_HALION_TWILIGHT: + case NPC_HALION_CONTROL: + case NPC_RAGEFIRE: + case NPC_ZARITHRIAN: + case NPC_BALTHARUS: + case NPC_BALTHARUS_TARGET: + case NPC_CLONE: + case NPC_XERESTRASZA: + case NPC_SHADOW_PULSAR_N: + case NPC_SHADOW_PULSAR_S: + case NPC_ORB_ROTATION_FOCUS: + case NPC_ORB_CARRIER: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } + } + + void OnObjectCreate(GameObject* pGo) override + { + switch(pGo->GetEntry()) + { + case GO_HALION_PORTAL_1: + case GO_HALION_PORTAL_2: + case GO_HALION_PORTAL_3: + case GO_FLAME_WALLS: + case GO_FLAME_RING: + case GO_FIRE_FIELD: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + } + OpenAllDoors(); + } + + void SetData(uint32 uiType, uint32 uiData) override + { + switch(uiType) + { + case TYPE_EVENT: m_auiEncounter[uiType] = uiData; uiData = NOT_STARTED; break; + case TYPE_RAGEFIRE: m_auiEncounter[uiType] = uiData; + OpenAllDoors(); + break; + case TYPE_BALTHARUS: m_auiEncounter[uiType] = uiData; + OpenAllDoors(); + break; + case TYPE_XERESTRASZA: m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + DoOpenDoor(GO_FIRE_FIELD); + else if (uiData == NOT_STARTED) + { + DoCloseDoor(GO_FIRE_FIELD); + OpenAllDoors(); + } + else if (uiData == DONE) + { + OpenAllDoors(); + if (m_auiEncounter[TYPE_ZARITHRIAN] == DONE) + { + m_auiEncounter[TYPE_EVENT] = 200; + m_auiEventTimer = 30000; + }; + } + break; + case TYPE_ZARITHRIAN: m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoOpenDoor(GO_FLAME_WALLS); + m_auiEncounter[TYPE_EVENT] = 200; + m_auiEventTimer = 30000; + } + else if (uiData == IN_PROGRESS) + DoCloseDoor(GO_FLAME_WALLS); + else if (uiData == FAIL) + DoOpenDoor(GO_FLAME_WALLS); + break; + case TYPE_HALION: m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + DoCloseDoor(GO_FLAME_RING); + else + DoOpenDoor(GO_FLAME_RING); + break; + case TYPE_HALION_EVENT: m_auiHalionEvent = uiData; uiData = NOT_STARTED; break; + case TYPE_EVENT_TIMER: m_auiEventTimer = uiData; uiData = NOT_STARTED; break; + + case DATA_ORB_DIRECTION: m_auiOrbDirection = uiData; uiData = NOT_STARTED; break; + case DATA_ORB_N: m_auiOrbNState = uiData; uiData = NOT_STARTED; break; + case DATA_ORB_S: m_auiOrbSState = uiData; uiData = NOT_STARTED; break; + case TYPE_COUNTER: + if (uiData == COUNTER_OFF) + { + UpdateWorldState(false,0); + } + else + { + UpdateWorldState(true,uiData); + } + uiData = NOT_STARTED; + break; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + saveStream << m_auiEncounter[i] << " "; + + strSaveData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + const char* Save() const override + { + return strSaveData.c_str(); + } + + uint32 GetData(uint32 uiType) const override + { + switch(uiType) + { + case TYPE_RAGEFIRE: return m_auiEncounter[uiType]; + case TYPE_BALTHARUS: return m_auiEncounter[uiType]; + case TYPE_XERESTRASZA: return m_auiEncounter[uiType]; + case TYPE_ZARITHRIAN: return m_auiEncounter[uiType]; + case TYPE_HALION: return m_auiEncounter[uiType]; + + case TYPE_EVENT: return m_auiEncounter[uiType]; + + case TYPE_HALION_EVENT: return m_auiHalionEvent; + + case TYPE_EVENT_TIMER: return m_auiEventTimer; + case TYPE_EVENT_NPC: switch (m_auiEncounter[TYPE_EVENT]) + { + case 10: + case 20: + case 30: + case 40: + case 50: + case 60: + case 70: + case 80: + case 90: + case 100: + case 110: + case 200: + case 210: + return NPC_XERESTRASZA; + break; + default: + break; + }; + return 0; + + case DATA_ORB_DIRECTION: return m_auiOrbDirection; + case DATA_ORB_N: return m_auiOrbNState; + case DATA_ORB_S: return m_auiOrbSState; + + } + return 0; + } + + void Load(const char* chrIn) override + { + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + + for(uint8 i = 0; i < MAX_ENCOUNTERS; ++i) + { + loadStream >> m_auiEncounter[i]; + + if (m_auiEncounter[i] == IN_PROGRESS + || m_auiEncounter[i] == FAIL) + m_auiEncounter[i] = NOT_STARTED; + } + + m_auiEncounter[TYPE_XERESTRASZA] = NOT_STARTED; + + OUT_LOAD_INST_DATA_COMPLETE; + OpenAllDoors(); + } +}; + +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.cpp b/scripts/northrend/ruby_sanctum/ruby_sanctum.cpp new file mode 100644 index 0000000000..074d7e0f8b --- /dev/null +++ b/scripts/northrend/ruby_sanctum/ruby_sanctum.cpp @@ -0,0 +1,251 @@ +/* Copyright (C) 2013 /dev/rsa for 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: ruby_sanctum mobs +SD%Complete: 10% +SDComment: by notagain, corrected by /dev/rsa +SDCategory: ruby_sanctum +EndScriptData */ + +#include "precompiled.h" +#include "ruby_sanctum.h" + +enum +{ + // Xerestrasza intro and outro texts + XERESTRASZA_SAY_HELP = -1724000, + XERESTRASZA_SAY_THANKS = -1724002, + XERESTRASZA_SAY_OUTRO_1 = -1724003, + XERESTRASZA_SAY_OUTRO_2 = -1724004, + XERESTRASZA_SAY_OUTRO_3 = -1724005, + XERESTRASZA_SAY_OUTRO_4 = -1724006, + XERESTRASZA_SAY_OUTRO_5 = -1724007, + XERESTRASZA_SAY_OUTRO_6 = -1724008, + XERESTRASZA_SAY_OUTRO_7 = -1724009, +}; + +static LOCATION SpawnLoc[]= +{ + {3155.540039f, 342.391998f, 84.596802f}, // 0 - start point + {3152.329834f, 359.41757f, 85.301605f}, // 1 - second say + {3152.078369f, 383.939178f, 86.337875f}, // 2 - other says and staying + {3154.99f, 535.637f, 72.8887f}, // 3 - Halion spawn point +}; + +struct MANGOS_DLL_DECL mob_xerestraszaAI : public ScriptedAI +{ + mob_xerestraszaAI(Creature *pCreature) : ScriptedAI(pCreature) + { + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* pInstance; + uint32 nextEvent; + uint32 nextPoint; + uint32 UpdateTimer; + bool movementstarted; + bool onSessionEvent; + + void Reset() + { + if (!pInstance) + return; + + nextEvent = 0; + nextPoint = 0; + movementstarted = false; + UpdateTimer = 2000; + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pInstance->SetData(TYPE_XERESTRASZA, NOT_STARTED); + m_creature->SetWalk(true); + m_creature->SetSpeedRate(MOVE_WALK, 0.8f); + m_creature->SetRespawnDelay(7*DAY); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !movementstarted) + return; + + if (id == nextPoint) + { + movementstarted = false; + pInstance->SetData(TYPE_EVENT, nextEvent); + m_creature->GetMotionMaster()->MovementExpired(); + } + } + + void StartMovement(uint32 id, uint32 _nextEvent) + { + nextPoint = id; + nextEvent = _nextEvent; + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(id, SpawnLoc[id].x, SpawnLoc[id].y, SpawnLoc[id].z); + pInstance->SetData(TYPE_EVENT,0); + movementstarted = true; + } + + void AttackStart(Unit *who) + { + //ignore all attackstart commands + return; + } + + void MoveInLineOfSight(Unit* who) override + { + if (!pInstance || !who || who->GetTypeId() != TYPEID_PLAYER) + return; + + if (pInstance->GetData(TYPE_BALTHARUS) != DONE || pInstance->GetData(TYPE_XERESTRASZA) != NOT_STARTED) + return; + + if (!who->IsWithinDistInMap(m_creature, 60.0f)) + return; + + pInstance->SetData(TYPE_XERESTRASZA, IN_PROGRESS); + pInstance->SetData(TYPE_EVENT, 30); + onSessionEvent = true; + } + + void UpdateAI(const uint32 diff) + { + if (!pInstance) + return; + + if (pInstance->GetData(TYPE_EVENT_NPC) == NPC_XERESTRASZA) + { + UpdateTimer = pInstance->GetData(TYPE_EVENT_TIMER); + if (UpdateTimer <= diff) + { + debug_log("EventMGR: creature %u received signal %u ",m_creature->GetEntry(),pInstance->GetData(TYPE_EVENT)); + switch (pInstance->GetData(TYPE_EVENT)) + { + case 0: + break; + // Xerestrasza intro + case 10: + UpdateTimer = 7000; + pInstance->SetData(TYPE_EVENT, 20); + break; + case 20: + DoScriptText(XERESTRASZA_SAY_HELP, m_creature); + pInstance->SetData(TYPE_EVENT,0); + break; + // Xerestrasza event + case 30: + m_creature->SetActiveObjectState(true); + DoScriptText(XERESTRASZA_SAY_THANKS, m_creature); + StartMovement(1,40); + break; + case 40: + DoScriptText(XERESTRASZA_SAY_OUTRO_1, m_creature); + StartMovement(2,50); + break; + case 50: + DoScriptText(XERESTRASZA_SAY_OUTRO_2, m_creature); + UpdateTimer = 12000; + pInstance->SetData(TYPE_EVENT,60); + break; + case 60: + DoScriptText(XERESTRASZA_SAY_OUTRO_3, m_creature); + UpdateTimer = 12000; + pInstance->SetData(TYPE_EVENT,70); + break; + case 70: + DoScriptText(XERESTRASZA_SAY_OUTRO_4, m_creature); + UpdateTimer = 10000; + pInstance->SetData(TYPE_EVENT,80); + break; + case 80: + DoScriptText(XERESTRASZA_SAY_OUTRO_5, m_creature); + UpdateTimer = 10000; + pInstance->SetData(TYPE_EVENT,90); + break; + case 90: + DoScriptText(XERESTRASZA_SAY_OUTRO_6, m_creature); + UpdateTimer = 10000; + pInstance->SetData(TYPE_EVENT,100); + break; + case 100: + DoScriptText(XERESTRASZA_SAY_OUTRO_7, m_creature); + UpdateTimer = 4000; + pInstance->SetData(TYPE_EVENT,110); + break; + case 110: + UpdateTimer = 2000; + pInstance->SetData(TYPE_EVENT,0); + pInstance->SetData(TYPE_XERESTRASZA, DONE); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetActiveObjectState(false); + break; + // Halion spawn + case 200: + m_creature->SetActiveObjectState(true); + { + Creature* pHalion = pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL); + if (pInstance->GetData(TYPE_BALTHARUS) == DONE && + pInstance->GetData(TYPE_RAGEFIRE) == DONE && + pInstance->GetData(TYPE_XERESTRASZA) == DONE && + pInstance->GetData(TYPE_ZARITHRIAN) == DONE && + pInstance->GetData(TYPE_HALION) != DONE) + { + if (!pHalion) + pHalion = m_creature->SummonCreature(NPC_HALION_REAL, SpawnLoc[3].x, SpawnLoc[3].y, SpawnLoc[3].z, 6.23f, TEMPSUMMON_MANUAL_DESPAWN, HOUR*IN_MILLISECONDS); + + if (pHalion && !pHalion->isAlive()) + pHalion->Respawn(); + + if (pHalion) + pHalion->SetCreatorGuid(ObjectGuid()); + } + } + UpdateTimer = 4000; + pInstance->SetData(TYPE_EVENT,210); + break; + case 210: + m_creature->SetActiveObjectState(false); + UpdateTimer = 2000; + pInstance->SetData(TYPE_EVENT,0); + break; + default: + break; + } + } + else + UpdateTimer -= diff; + + pInstance->SetData(TYPE_EVENT_TIMER, UpdateTimer); + } + } +}; + +CreatureAI* GetAI_mob_xerestrasza(Creature* pCreature) +{ + return new mob_xerestraszaAI(pCreature); +} + +void AddSC_ruby_sanctum() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "mob_xerestrasza"; + newscript->GetAI = &GetAI_mob_xerestrasza; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/ruby_sanctum/ruby_sanctum.h b/scripts/northrend/ruby_sanctum/ruby_sanctum.h new file mode 100644 index 0000000000..0e75c45a0b --- /dev/null +++ b/scripts/northrend/ruby_sanctum/ruby_sanctum.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2013 by /dev/rsa for ScriptDev2 + * 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 +#include "BSW_ai.h" +#include "BSW_instance.h" + +enum +{ + MAX_ENCOUNTERS = 6, + + TYPE_EVENT = 0, + TYPE_RAGEFIRE = 1, + TYPE_BALTHARUS = 2, + TYPE_XERESTRASZA = 3, + TYPE_ZARITHRIAN = 4, + TYPE_HALION = 5, + + TYPE_COUNTER = 6, // for WorldUpdateState + TYPE_HALION_EVENT = 7, + + COUNTER_OFF = 255, + + TYPE_EVENT_TIMER = 50, + TYPE_EVENT_NPC = 51, + + NPC_HALION_REAL = 39863, // Halion Physical Realm NPC + NPC_HALION_TWILIGHT = 40142, // Halion Twilight Realm NPC + NPC_HALION_CONTROL = 40146, + + NPC_BALTHARUS = 39751, + NPC_CLONE = 39899, + NPC_ZARITHRIAN = 39746, + NPC_RAGEFIRE = 39747, + + NPC_XERESTRASZA = 40429, + + NPC_BALTHARUS_TARGET = 16, + NPC_ZARITHRIAN_SPAWN_STALKER = 39794, + + // Orb rotation + NPC_SHADOW_PULSAR_N = 40083, //spinning orb N spawn + NPC_SHADOW_PULSAR_S = 40100, //spinning orb S spawn + NPC_ORB_CARRIER = 40081, + NPC_ORB_ROTATION_FOCUS = 40091, + + + GO_HALION_PORTAL_1 = 202794, //1327 ENTRY + GO_HALION_PORTAL_2 = 202795, //1327 ENTRY + GO_HALION_PORTAL_3 = 202796, //1327 EXIT + + GO_FIRE_FIELD = 203005, + GO_FLAME_WALLS = 203006, + GO_FLAME_RING = 203007, + + DATA_EVENT_TIMER = 101, + DATA_EVENT = 102, + + DATA_ORB_DIRECTION = 110, + DATA_ORB_S = 111, + DATA_ORB_N = 112, + +}; + +enum uiWorldStates +{ + UPDATE_STATE_UI_COUNT_R = 5049, + UPDATE_STATE_UI_COUNT_T = 5050, + UPDATE_STATE_UI_SHOW = 5051, +}; + +#endif diff --git a/scripts/northrend/sholazar_basin.cpp b/scripts/northrend/sholazar_basin.cpp index e35517e86d..90e17578eb 100644 --- a/scripts/northrend/sholazar_basin.cpp +++ b/scripts/northrend/sholazar_basin.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,19 +17,187 @@ /* ScriptData SDName: Sholazar_Basin SD%Complete: 100 -SDComment: Quest support: 12573, 12570, 12580 +SDComment: Quest support: 12570, 12580, 12644, 12688 SDCategory: Sholazar Basin EndScriptData */ /* ContentData +npc_helice npc_injured_rainspeaker npc_mosswalker_victim -npc_vekjik - TODO, can be moved to database (already exist) +npc_tipsy_mcmanus +npc_wants_fruit_credit +go_quest_still_at_it_credit EndContentData */ #include "precompiled.h" #include "escort_ai.h" +/*###### +## npc_helice +######*/ + +enum +{ + QUEST_ENGINEERING_DISASTER = 12688, + + SAY_HELICE_ACCEPT = -1000657, + SAY_HELICE_EXPLOSIVES_1 = -1000658, + SAY_HELICE_EXPLODE_1 = -1000659, + SAY_HELICE_MOVE_ON = -1000660, + SAY_HELICE_EXPLOSIVES_2 = -1000661, + SAY_HELICE_EXPLODE_2 = -1000662, + SAY_HELICE_COMPLETE = -1000663, + + SPELL_DETONATE_EXPLOSIVES_1 = 52369, // first "barrel" + SPELL_DETONATE_EXPLOSIVES_2 = 52371, // second "barrel" +}; + +struct MANGOS_DLL_DECL npc_heliceAI : public npc_escortAI +{ + npc_heliceAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_uiExplodeTimer = 5000; + m_uiExplodePhase = 0; + m_bFirstBarrel = true; + Reset(); + } + + uint32 m_uiExplodeTimer; + uint32 m_uiExplodePhase; + bool m_bFirstBarrel; + + void Reset() override + { + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + { + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_HELICE_EXPLOSIVES_1, m_creature, pPlayer); + SetEscortPaused(true); + } + break; + } + case 13: + { + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_HELICE_EXPLOSIVES_2, m_creature, pPlayer); + SetEscortPaused(true); + } + break; + } + case 22: + { + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_HELICE_COMPLETE, m_creature, pPlayer); + pPlayer->GroupEventHappens(QUEST_ENGINEERING_DISASTER, m_creature); + } + break; + } + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + if (HasEscortState(STATE_ESCORT_PAUSED)) + { + if (m_uiExplodeTimer < uiDiff) + { + if (m_bFirstBarrel) + { + switch (m_uiExplodePhase) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_DETONATE_EXPLOSIVES_1); + + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_HELICE_EXPLODE_1, m_creature, pPlayer); + + m_uiExplodeTimer = 2500; + ++m_uiExplodePhase; + break; + case 1: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_HELICE_MOVE_ON, m_creature, pPlayer); + + m_uiExplodeTimer = 2500; + ++m_uiExplodePhase; + break; + case 2: + SetEscortPaused(false); + m_uiExplodePhase = 0; + m_uiExplodeTimer = 5000; + m_bFirstBarrel = false; + break; + } + } + else + { + switch (m_uiExplodePhase) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_DETONATE_EXPLOSIVES_2); + + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_HELICE_EXPLODE_2, m_creature, pPlayer); + + m_uiExplodeTimer = 2500; + ++m_uiExplodePhase; + break; + case 1: + SetEscortPaused(false); + m_uiExplodePhase = 0; + m_uiExplodeTimer = 5000; + m_bFirstBarrel = true; + break; + } + } + } + else + m_uiExplodeTimer -= uiDiff; + } + + return; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_helice(Creature* pCreature) +{ + return new npc_heliceAI(pCreature); +} + +bool QuestAccept_npc_helice(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ENGINEERING_DISASTER) + { + DoScriptText(SAY_HELICE_ACCEPT, pCreature, pPlayer); + + if (npc_heliceAI* pEscortAI = dynamic_cast(pCreature->AI())) + { + pEscortAI->Start(false, pPlayer, pQuest); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + } + } + + return false; +} + /*###### ## npc_injured_rainspeaker ######*/ @@ -44,38 +212,41 @@ enum SAY_START = -1000606, SAY_END_1 = -1000607, SAY_END_2 = -1000608, - SAY_TRACKER = -1000609, + SAY_TRACKER = -1000609, // not used in escort (aggro text for trackers? something for vekjik?) NPC_FRENZYHEART_TRACKER = 28077, + SPELL_ORACLE_ESCORT_START = 51341, // unknown purpose SPELL_FEIGN_DEATH = 51329, SPELL_ORACLE_INTRO = 51448, }; -// TODO: add, if faction change is expected. struct MANGOS_DLL_DECL 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()) + { DoScriptText(SAY_START, m_creature, pPlayer); + DoCastSpellIfCan(m_creature, SPELL_ORACLE_ESCORT_START); + } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 22: { if (Player* pPlayer = GetPlayerForEscort()) { DoScriptText(SAY_END_1, m_creature, pPlayer); - // more likely m_creature->player, doesn't seem to work though. - pPlayer->CastSpell(pPlayer, SPELL_ORACLE_INTRO, true); + pPlayer->AreaExploredOrEventHappens(QUEST_FORTUNATE_MISUNDERSTAND); + DoCastSpellIfCan(m_creature, SPELL_ORACLE_INTRO); } break; } @@ -96,12 +267,7 @@ struct MANGOS_DLL_DECL npc_injured_rainspeakerAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) - { - DoScriptText(SAY_TRACKER, pSummoned); - } - - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 /*uiDiff*/) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -124,7 +290,10 @@ bool QuestAccept_npc_injured_rainspeaker(Player* pPlayer, Creature* pCreature, c // Workaround, GossipHello/GossipSelect doesn't work well when object already has gossip from database if (npc_injured_rainspeakerAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(true, pPlayer->GetGUID(), pQuest); + { + pEscortAI->Start(true, pPlayer, pQuest); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + } } return false; @@ -136,7 +305,7 @@ bool GossipHello_npc_injured_rainspeaker(Player* pPlayer, Creature* pCreature) if (pPlayer->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTAND) == QUEST_STATUS_INCOMPLETE) { pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } @@ -150,7 +319,7 @@ bool GossipSelect_npc_injured_rainspeaker(Player* pPlayer, Creature* pCreature, pPlayer->CLOSE_GOSSIP_MENU(); if (npc_injured_rainspeakerAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(true, pPlayer->GetGUID()); + pEscortAI->Start(true, pPlayer); } return false; @@ -190,17 +359,17 @@ 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); } - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INJURED, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INJURED, pCreature->GetObjectGuid()); 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) { @@ -212,9 +381,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; @@ -226,7 +395,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; @@ -244,69 +413,371 @@ bool GossipSelect_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature, ui } /*###### -## npc_vekjik - TODO, can be moved to database (already exist) +## npc_tipsy_mcmanus ######*/ -#define GOSSIP_VEKJIK_ITEM1 "Shaman Vekjik, I have spoken with the big-tongues and they desire peace. I have brought this offering on their behalf." -#define GOSSIP_VEKJIK_ITEM2 "No no... I had no intentions of betraying your people. I was only defending myself. it was all a misunderstanding." - enum { - GOSSIP_TEXTID_VEKJIK1 = 13137, - GOSSIP_TEXTID_VEKJIK2 = 13138, + 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, +}; - SAY_TEXTID_VEKJIK1 = -1000208, +struct StillAtItData +{ + int32 iText; + uint32 uiOwnerEntry; +}; - SPELL_FREANZYHEARTS_FURY = 51469, +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}, +}; - QUEST_MAKING_PEACE = 12573 +static const StillAtItData aStillAtItMachines[2] = +{ + {SAY_LIGHT_BRAZIER, GO_BRAZIER}, + {SAY_OPEN_VALVE, GO_PRESSURE_VALVE}, }; -bool GossipHello_npc_vekjik(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_tipsy_mcmanusAI : public ScriptedAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_tipsy_mcmanusAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint8 m_uiTaskIndex; + uint32 m_uiTaskOwnerEntry; + uint32 m_uiTaskTimer; + uint32 m_uiActionTimer; - if (pPlayer->GetQuestStatus(QUEST_MAKING_PEACE) == QUEST_STATUS_INCOMPLETE) + void Reset() override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_VEKJIK_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VEKJIK1, pCreature->GetGUID()); - return true; + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + m_uiTaskIndex = 0; + m_uiTaskOwnerEntry = 0; + m_uiTaskTimer = 0; + m_uiActionTimer = 0; } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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_vekjik(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_tipsy_mcmanus(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(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) { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_VEKJIK_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VEKJIK2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - DoScriptText(SAY_TEXTID_VEKJIK1, pCreature, pPlayer); - pPlayer->AreaExploredOrEventHappens(QUEST_MAKING_PEACE); - pCreature->CastSpell(pPlayer, SPELL_FREANZYHEARTS_FURY, false); - break; + 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; +} + +/*###################### +# Quest The Taste Test # +######################*/ + +enum TasteTest +{ + SPELL_OFFER_JUNGLE_PUNCH = 51962, + + NPC_HEMET_NESINGWAY = 27986, + NPC_HADRIUS_HARLOWE = 28047, + NPC_TAMARA_WOBBLESPROCKET = 28568 +}; + +int32 HemetText[3] = {-1999791, -1999790, -1999789}; +int32 HadriusText[3] = {-1999788, -1999787, -1999786}; +int32 TamaraText[3] = {-1999785, -1999784, -1999783}; + +struct MANGOS_DLL_DECL mob_taste_testAI : public ScriptedAI +{ + mob_taste_testAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool bTasteing; + uint8 Phase; + uint32 m_uiEventTimer; + ObjectGuid m_playersGUID; + + void Reset() + { + bTasteing = false; + Phase = 0; + m_playersGUID.Clear(); + m_uiEventTimer = 5000; + } + + void UpdateAI (const uint32 uiDiff) + { + if (bTasteing) + { + if (m_uiEventTimer <= uiDiff) + { + switch(m_creature->GetEntry()) + { + case NPC_HEMET_NESINGWAY: DoScriptText(HemetText[Phase], m_creature); break; + case NPC_HADRIUS_HARLOWE: DoScriptText(HadriusText[Phase], m_creature); break; + case NPC_TAMARA_WOBBLESPROCKET: DoScriptText(TamaraText[Phase], m_creature); break; + default: break; + } + if (Phase == 2) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playersGUID)) + pPlayer->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); + Reset(); + return; + } + ++Phase; + m_uiEventTimer = 5000; + } else m_uiEventTimer -= uiDiff; + } + } +}; + +bool EffectDummyNPC_mob_taste_test(Unit *pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pCreatureTarget, ObjectGuid originalCasterGuid) +{ + if (spellId == SPELL_OFFER_JUNGLE_PUNCH && effIndex == EFFECT_INDEX_1 && pCaster->GetTypeId() == TYPEID_PLAYER && pCreatureTarget) + { + if (pCreatureTarget->AI()) + { + ((mob_taste_testAI*)pCreatureTarget->AI())->bTasteing = true; + ((mob_taste_testAI*)pCreatureTarget->AI())->m_playersGUID = pCaster->GetObjectGuid(); + } + } return true; } +CreatureAI* GetAI_mob_taste_test(Creature* pCreature) +{ + return new mob_taste_testAI(pCreature); +} + void AddSC_sholazar_basin() { Script* pNewScript; + pNewScript = new Script; + pNewScript->Name = "npc_helice"; + pNewScript->GetAI = &GetAI_npc_helice; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_helice; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "npc_injured_rainspeaker"; pNewScript->GetAI = &GetAI_npc_injured_rainspeaker; - pNewScript->pQuestAccept = &QuestAccept_npc_injured_rainspeaker; - //pNewScript->pGossipHello = &GossipHello_npc_injured_rainspeaker; - //pNewScript->pGossipSelect = &GossipSelect_npc_injured_rainspeaker; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_injured_rainspeaker; + // pNewScript->pGossipHello = &GossipHello_npc_injured_rainspeaker; + // pNewScript->pGossipSelect = &GossipSelect_npc_injured_rainspeaker; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -316,8 +787,25 @@ void AddSC_sholazar_basin() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_vekjik"; - pNewScript->pGossipHello = &GossipHello_npc_vekjik; - pNewScript->pGossipSelect = &GossipSelect_npc_vekjik; + 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(); + + pNewScript = new Script; + pNewScript->Name = "mob_taste_test"; + pNewScript->GetAI = &GetAI_mob_taste_test; + pNewScript->pEffectDummyNPC = &EffectDummyNPC_mob_taste_test; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/storm_peaks.cpp b/scripts/northrend/storm_peaks.cpp index ec03553a57..b212309504 100644 --- a/scripts/northrend/storm_peaks.cpp +++ b/scripts/northrend/storm_peaks.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,259 +17,231 @@ /* ScriptData SDName: Storm_Peaks SD%Complete: 100 -SDComment: Vendor Support (31247). Quest support: 12970, 12684 +SDComment: Quest support: 12832, 12977. SDCategory: Storm Peaks EndScriptData */ /* ContentData -npc_loklira_the_crone -npc_roxi_ramrocket -npc_frostborn_scout +npc_floating_spirit +npc_restless_frostborn +npc_injured_miner EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### -## npc_frostborn_scout +## npc_floating_spirit ######*/ -enum Scout +enum { - QUEST_MISSING_SCOUT = 12864, + SPELL_BLOW_HODIRS_HORN = 55983, + SPELL_SUMMON_FROST_GIANG_SPIRIT = 55986, + SPELL_SUMMON_FROST_WARRIOR_SPIRIT = 55991, + SPELL_SUMMON_FROST_GHOST_SPIRIT = 55992, - GOSSIP_TEXTID_SCOUT_1 = 13611, - GOSSIP_TEXTID_SCOUT_2 = 13612, - GOSSIP_TEXTID_SCOUT_3 = 13613, - GOSSIP_TEXTID_SCOUT_4 = 13614 + NPC_FROST_GIANT_GHOST_KC = 30138, + NPC_FROST_DWARF_GHOST_KC = 30139, + NPC_NIFFELEM_FOREFATHER = 29974, + NPC_FROSTBORN_WARRIOR = 30135, + NPC_FROSTBORN_GHOST = 30144, }; -#define GOSSIP_ITEM_SCOUT_1 "Are you okay? I've come to take you back to Frosthold if you can stand." -#define GOSSIP_ITEM_SCOUT_2 "I'm sorry that I didn't get here sooner. What happened?" -#define GOSSIP_ITEM_SCOUT_3 "I'll go get some help. Hang in there." - -bool GossipHello_npc_frostborn_scout(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_floating_spiritAI : public ScriptedAI { - if (pPlayer->GetQuestStatus(QUEST_MISSING_SCOUT) == QUEST_STATUS_INCOMPLETE) + npc_floating_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SCOUT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SCOUT_1, pCreature->GetGUID()); - return true; - } + // Simple animation for the floating spirit + m_creature->SetLevitate(true); + m_creature->ForcedDespawn(5000); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 50.0f); + } +}; -bool GossipSelect_npc_frostborn_scout(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +CreatureAI* GetAI_npc_floating_spirit(Creature* pCreature) { - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SCOUT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SCOUT_2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SCOUT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SCOUT_3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SCOUT_4, pCreature->GetGUID()); - pPlayer->AreaExploredOrEventHappens(QUEST_MISSING_SCOUT); - break; - } - return true; + return new npc_floating_spiritAI(pCreature); } /*###### -## npc_loklira_the_crone +## npc_restless_frostborn ######*/ -#define GOSSIP_ITEM_TELL_ME "Tell me about this proposal." -#define GOSSIP_ITEM_WHAT_HAPPENED "What happened then?" -#define GOSSIP_ITEM_YOU_WANT_ME "You want me to take part in the Hyldsmeet to end the war?" -#define GOSSIP_ITEM_VERY_WELL "Very well. I'll take part in this competition." - -enum -{ - GOSSIP_TEXTID_LOKLIRA1 = 13777, - GOSSIP_TEXTID_LOKLIRA2 = 13778, - GOSSIP_TEXTID_LOKLIRA3 = 13779, - GOSSIP_TEXTID_LOKLIRA4 = 13780, - - QUEST_THE_HYLDSMEET = 12970, - - CREDIT_LOKLIRA = 30467 -}; - -bool GossipHello_npc_loklira_the_crone(Player* pPlayer, Creature* pCreature) +bool EffectDummyCreature_npc_restless_frostborn(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(QUEST_THE_HYLDSMEET) == QUEST_STATUS_INCOMPLETE) + if (uiSpellId == SPELL_BLOW_HODIRS_HORN && uiEffIndex == EFFECT_INDEX_0 && !pCreatureTarget->isAlive() && pCaster->GetTypeId() == TYPEID_PLAYER) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELL_ME, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOKLIRA1, pCreature->GetGUID()); + 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; } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_loklira_the_crone(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_WHAT_HAPPENED, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOKLIRA2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_YOU_WANT_ME, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOKLIRA3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERY_WELL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_LOKLIRA4, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->TalkedToCreature(CREDIT_LOKLIRA, pCreature->GetGUID()); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - } - return true; + return false; } /*###### -## npc_thorim +## npc_injured_miner ######*/ -#define GOSSIP_ITEM_THORIM1 "Can you tell me what became of Sif?" -#define GOSSIP_ITEM_THORIM2 "He did more than that, Thorim. He controls Ulduar now." -#define GOSSIP_ITEM_THORIM3 "It needn't end this way." - enum { - QUEST_SIBLING_RIVALRY = 13064, - - SPELL_THORIM_STORY_KILL_CREDIT = 56940, - - GOSSIP_TEXTID_THORIM1 = 13799, - GOSSIP_TEXTID_THORIM2 = 13801, - GOSSIP_TEXTID_THORIM3 = 13802, - GOSSIP_TEXTID_THORIM4 = 13803 + // 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, }; -bool GossipHello_npc_thorim(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_injured_minerAI : public npc_escortAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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); + } + } - if (pPlayer->GetQuestStatus(QUEST_SIBLING_RIVALRY) == QUEST_STATUS_INCOMPLETE) + void WaypointReached(uint32 uiPointId) override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THORIM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM1, pCreature->GetGUID()); + 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; + } } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); +}; - return true; +CreatureAI* GetAI_npc_injured_miner(Creature* pCreature) +{ + return new npc_injured_minerAI(pCreature); } -bool GossipSelect_npc_thorim(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipHello_npc_injured_miner(Player* pPlayer, Creature* pCreature) { - switch(uiAction) + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + if (!pCreature->HasAura(SPELL_FEIGN_DEATH)) { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THORIM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THORIM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_THORIM4, pCreature->GetGUID()); - pCreature->CastSpell(pPlayer, SPELL_THORIM_STORY_KILL_CREDIT, true); - break; + 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; } -/*###### -## npc_roxi_ramrocket -######*/ - -#define GOSSIP_TEXT_RAMROCKET1 "How do you fly in this cold climate?" -#define GOSSIP_TEXT_RAMROCKET2 "I hear you sell motorcycle parts." - -enum -{ - SPELL_MECHANO_HOG = 60866, - SPELL_MEKGINEER_CHOPPER = 60867 -}; - -bool GossipHello_npc_roxi_ramrocket(Player* pPlayer, Creature* pCreature) +bool GossipSelect_npc_injured_miner(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (pCreature->isTrainer()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, GOSSIP_TEXT_RAMROCKET1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - if (pCreature->isVendor()) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { - if (pPlayer->HasSpell(SPELL_MECHANO_HOG) || pPlayer->HasSpell(SPELL_MEKGINEER_CHOPPER)) - { - if (pPlayer->HasSkill(SKILL_ENGINEERING) && pPlayer->GetBaseSkillValue(SKILL_ENGINEERING) >= 450) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_RAMROCKET2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - } + pPlayer->CLOSE_GOSSIP_MENU(); + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pCreature); } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); return true; } -bool GossipSelect_npc_roxi_ramrocket(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestAccept_npc_injured_miner(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - switch(uiAction) + if (pQuest->GetQuestId() == QUEST_ID_BITTER_DEPARTURE) { - case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetGUID()); - break; - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; } - return true; + return false; } void AddSC_storm_peaks() { - Script* newscript; - - newscript = new Script; - newscript->Name = "npc_frostborn_scout"; - newscript->pGossipHello = &GossipHello_npc_frostborn_scout; - newscript->pGossipSelect = &GossipSelect_npc_frostborn_scout; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_loklira_the_crone"; - newscript->pGossipHello = &GossipHello_npc_loklira_the_crone; - newscript->pGossipSelect = &GossipSelect_npc_loklira_the_crone; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_thorim"; - newscript->pGossipHello = &GossipHello_npc_thorim; - newscript->pGossipSelect = &GossipSelect_npc_thorim; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_roxi_ramrocket"; - newscript->pGossipHello = &GossipHello_npc_roxi_ramrocket; - newscript->pGossipSelect = &GossipSelect_npc_roxi_ramrocket; - newscript->RegisterSelf(); + 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 b1a5b3c6c1..3c62f7b885 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, @@ -40,36 +40,29 @@ enum EMOTE_DEFENSIVE_STANCE = -1602010, SPELL_DEFENSIVE_STANCE = 53790, - //SPELL_DEFENSIVE_AURA = 41105, SPELL_SPELL_REFLECTION = 36096, SPELL_PUMMEL = 12555, SPELL_KNOCK_AWAY = 52029, SPELL_IRONFORM = 52022, SPELL_BERSEKER_STANCE = 53791, - //SPELL_BERSEKER_AURA = 41107, SPELL_INTERCEPT = 58769, SPELL_WHIRLWIND = 52027, SPELL_CLEAVE = 15284, SPELL_BATTLE_STANCE = 53792, - //SPELL_BATTLE_AURA = 41106, 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, SPELL_RENEW_STEEL_N = 52774, SPELL_RENEW_STEEL_H = 59160, - EQUIP_SWORD = 37871, - EQUIP_SHIELD = 35642, - EQUIP_MACE = 43623, - STANCE_DEFENSIVE = 0, STANCE_BERSERKER = 1, STANCE_BATTLE = 2 @@ -81,12 +74,11 @@ enum struct MANGOS_DLL_DECL 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(); m_uiStance = STANCE_DEFENSIVE; - memset(&m_auiStormforgedLieutenantGUID, 0, sizeof(m_auiStormforgedLieutenantGUID)); Reset(); } @@ -98,80 +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_uiReflection_Timer; - uint32 m_uiKnockAway_Timer; - uint32 m_uiPummel_Timer; - uint32 m_uiIronform_Timer; + uint32 m_uiChargeTimer; + uint32 m_uiChangeStanceTimer; - uint32 m_uiIntercept_Timer; - uint32 m_uiWhirlwind_Timer; - uint32 m_uiCleave_Timer; + uint32 m_uiReflectionTimer; + uint32 m_uiKnockAwayTimer; + uint32 m_uiPummelTimer; + uint32 m_uiIronformTimer; - uint32 m_uiMortalStrike_Timer; - uint32 m_uiSlam_Timer; + uint32 m_uiInterceptTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiCleaveTimer; - uint64 m_auiStormforgedLieutenantGUID[2]; + uint32 m_uiMortalStrikeTimer; + uint32 m_uiSlamTimer; - void Reset() + void Reset() override { - m_bIsChangingStance = false; + m_bIsChangingStance = false; - m_uiChargingStatus = 0; - m_uiCharge_Timer = 1000; + m_uiChargingStatus = 0; + m_uiChargeTimer = 1000; - m_uiChangeStance_Timer = urand(20000, 25000); + m_uiChangeStanceTimer = urand(20000, 25000); - m_uiReflection_Timer = 8000; - m_uiKnockAway_Timer = 20000; - m_uiPummel_Timer = 10000; - m_uiIronform_Timer = 25000; + m_uiReflectionTimer = 8000; + m_uiKnockAwayTimer = 20000; + m_uiPummelTimer = 10000; + m_uiIronformTimer = 25000; - m_uiIntercept_Timer = 5000; - m_uiWhirlwind_Timer = 10000; - m_uiCleave_Timer = 8000; + m_uiInterceptTimer = 5000; + m_uiWhirlwindTimer = 10000; + m_uiCleaveTimer = 8000; - m_uiMortalStrike_Timer = 8000; - m_uiSlam_Timer = 10000; - - for(uint8 i = 0; i < 2; ++i) - { - if (Creature* pStormforgedLieutenant = m_creature->GetMap()->GetCreature(m_auiStormforgedLieutenantGUID[i])) - { - if (!pStormforgedLieutenant->isAlive()) - pStormforgedLieutenant->Respawn(); - } - } + m_uiMortalStrikeTimer = 8000; + m_uiSlamTimer = 10000; if (m_uiStance != STANCE_DEFENSIVE) { - DoRemoveStanceAura(m_uiStance); DoCastSpellIfCan(m_creature, SPELL_DEFENSIVE_STANCE); m_uiStance = STANCE_DEFENSIVE; } - - SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SHIELD, EQUIP_NO_CHANGE); - - if (m_pInstance) - m_pInstance->SetData(TYPE_BJARNGRIM, NOT_STARTED); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - //must get both lieutenants here and make sure they are with him - m_creature->CallForHelp(30.0f); - 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; @@ -179,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); @@ -187,157 +165,141 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI m_pInstance->SetData(TYPE_BJARNGRIM, DONE); } - //TODO: remove when removal is done by mangos - void DoRemoveStanceAura(uint8 uiStance) + void JustReachedHome() override { - switch(uiStance) - { - case STANCE_DEFENSIVE: - m_creature->RemoveAurasDueToSpell(SPELL_DEFENSIVE_STANCE); - break; - case STANCE_BERSERKER: - m_creature->RemoveAurasDueToSpell(SPELL_BERSEKER_STANCE); - break; - case STANCE_BATTLE: - m_creature->RemoveAurasDueToSpell(SPELL_BATTLE_STANCE); - break; - } + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, FAIL); } - 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; // 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; - DoRemoveStanceAura(m_uiStance); - - 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); DoScriptText(EMOTE_DEFENSIVE_STANCE, m_creature); DoCastSpellIfCan(m_creature, SPELL_DEFENSIVE_STANCE); - SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SHIELD, EQUIP_NO_CHANGE); break; case STANCE_BERSERKER: DoScriptText(SAY_BERSEKER_STANCE, m_creature); DoScriptText(EMOTE_BERSEKER_STANCE, m_creature); DoCastSpellIfCan(m_creature, SPELL_BERSEKER_STANCE); - SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SWORD, EQUIP_NO_CHANGE); break; case STANCE_BATTLE: DoScriptText(SAY_BATTLE_STANCE, m_creature); DoScriptText(EMOTE_BATTLE_STANCE, m_creature); DoCastSpellIfCan(m_creature, SPELL_BATTLE_STANCE); - SetEquipmentSlots(false, EQUIP_MACE, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); 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; } @@ -353,7 +315,7 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI struct MANGOS_DLL_DECL 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(); @@ -363,55 +325,43 @@ struct MANGOS_DLL_DECL mob_stormforged_lieutenantAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 m_uiArcWeld_Timer; - uint32 m_uiRenewSteel_Timer; + uint32 m_uiArcWeldTimer; + uint32 m_uiRenewSteelTimer; - void Reset() + void Reset() override { - m_uiArcWeld_Timer = urand(20000, 21000); - m_uiRenewSteel_Timer = urand(10000, 11000); - } - - void Aggro(Unit* pWho) - { - if (m_pInstance) - { - if (Creature* pBjarngrim = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_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) { - if (Creature* pBjarngrim = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = m_pInstance->GetSingleCreatureFromStorage(NPC_BJARNGRIM)) { if (pBjarngrim->isAlive()) 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(); } @@ -429,15 +379,15 @@ CreatureAI* GetAI_mob_stormforged_lieutenant(Creature* pCreature) void AddSC_boss_bjarngrim() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_bjarngrim"; - newscript->GetAI = &GetAI_boss_bjarngrim; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_bjarngrim"; + pNewScript->GetAI = &GetAI_boss_bjarngrim; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_stormforged_lieutenant"; - newscript->GetAI = &GetAI_mob_stormforged_lieutenant; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_stormforged_lieutenant"; + pNewScript->GetAI = &GetAI_mob_stormforged_lieutenant; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp index 26701c87eb..dd02eab7ae 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, @@ -59,7 +59,7 @@ enum struct MANGOS_DLL_DECL 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,29 +68,29 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI ScriptedInstance* m_pInstance; - std::list m_lSparkGUIDList; + GuidList m_lSparkGUIDList; bool m_bIsRegularMode; + bool m_bIsDesperseCasting; bool m_bIsSplitPhase; - uint32 m_uiSplit_Timer; + uint32 m_uiSplitTimer; uint32 m_uiSparkAtHomeCount; - uint32 m_uiStaticOverload_Timer; - uint32 m_uiBallLightning_Timer; + uint32 m_uiStaticOverloadTimer; + uint32 m_uiBallLightningTimer; uint32 m_uiHealthAmountModifier; - void Reset() + void Reset() override { - m_lSparkGUIDList.clear(); - m_bIsSplitPhase = true; - m_uiSplit_Timer = 25000; + m_bIsDesperseCasting = false; + m_uiSplitTimer = 25000; m_uiSparkAtHomeCount = 0; - m_uiStaticOverload_Timer = urand(5000, 6000); - m_uiBallLightning_Timer = urand(10000, 11000); + m_uiStaticOverloadTimer = urand(5000, 6000); + m_uiBallLightningTimer = urand(10000, 11000); m_uiHealthAmountModifier = 1; @@ -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,13 +117,15 @@ 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, NOT_STARTED); + m_pInstance->SetData(TYPE_IONAR, FAIL); + + DespawnSpark(); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, true)) { @@ -136,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(); @@ -145,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; @@ -157,10 +159,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI void DespawnSpark() { - if (m_lSparkGUIDList.empty()) - return; - - for(std::list::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)) { @@ -172,21 +171,18 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI m_lSparkGUIDList.clear(); } - //make sparks come back + // make sparks come back void CallBackSparks() { - //should never be empty here, but check - if (m_lSparkGUIDList.empty()) - return; - - for(std::list::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)) { if (pSpark->isAlive()) { - if (pSpark->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - pSpark->GetMotionMaster()->MovementExpired(); + // Required to prevent combat movement, elsewise they might switch movement on aggro-change + if (ScriptedAI* pSparkAI = dynamic_cast(pSpark->AI())) + pSparkAI->SetCombatMovement(false); pSpark->GetMotionMaster()->MovePoint(POINT_CALLBACK, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); } @@ -199,35 +195,30 @@ 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) { pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_SPARK_VISUAL_TRIGGER_N : SPELL_SPARK_VISUAL_TRIGGER_H, true); - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (m_creature->getVictim()) - pSummoned->AI()->AttackStart(pTarget ? pTarget : m_creature->getVictim()); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); - m_lSparkGUIDList.push_back(pSummoned->GetGUID()); + m_lSparkGUIDList.push_back(pSummoned->GetObjectGuid()); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + // Splitted if (m_creature->GetVisibility() == VISIBILITY_OFF) { - if (!m_creature->isInCombat()) + if (m_uiSplitTimer < uiDiff) { - Reset(); - return; - } - - if (m_uiSplit_Timer < uiDiff) - { - m_uiSplit_Timer = 2500; + m_uiSplitTimer = 2500; // Return sparks to where Ionar splitted if (m_bIsSplitPhase) @@ -239,13 +230,12 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI else if (m_uiSparkAtHomeCount == MAX_SPARKS) { m_creature->SetVisibility(VISIBILITY_ON); - m_creature->CastSpell(m_creature, SPELL_SPARK_DESPAWN, false); - - DespawnSpark(); + DoCastSpellIfCan(m_creature, SPELL_SPARK_DESPAWN); m_uiSparkAtHomeCount = 0; - m_uiSplit_Timer = 25000; + m_uiSplitTimer = 25000; m_bIsSplitPhase = true; + m_bIsDesperseCasting = false; if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) { @@ -255,44 +245,43 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI } } else - m_uiSplit_Timer -= uiDiff; + m_uiSplitTimer -= uiDiff; return; } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiStaticOverload_Timer < uiDiff) + if (m_uiStaticOverloadTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_STATIC_OVERLOAD_N : SPELL_STATIC_OVERLOAD_H); - - m_uiStaticOverload_Timer = urand(5000, 6000); + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_STATIC_OVERLOAD_N : SPELL_STATIC_OVERLOAD_H) == CAST_OK) + m_uiStaticOverloadTimer = urand(5000, 6000); + } } else - m_uiStaticOverload_Timer -= uiDiff; + m_uiStaticOverloadTimer -= uiDiff; - if (m_uiBallLightning_Timer < uiDiff) + if (m_uiBallLightningTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - m_creature->CastSpell(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_bIsRegularMode ? SPELL_BALL_LIGHTNING_N : SPELL_BALL_LIGHTNING_H, false, NULL, NULL, m_creature->GetGUID()); - m_uiBallLightning_Timer = urand(10000, 11000); + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_BALL_LIGHTNING_N : SPELL_BALL_LIGHTNING_H) == CAST_OK) + m_uiBallLightningTimer = urand(10000, 11000); + } } else - m_uiBallLightning_Timer -= uiDiff; + 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; - DoScriptText(urand(0, 1) ? SAY_SPLIT_1 : SAY_SPLIT_2, m_creature); - - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(m_creature, SPELL_DISPERSE); + if (!m_bIsDesperseCasting && DoCastSpellIfCan(m_creature, SPELL_DISPERSE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SPLIT_1 : SAY_SPLIT_2, m_creature); + m_bIsDesperseCasting = true; + } } DoMeleeAttackIfReady(); @@ -304,15 +293,15 @@ 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) return true; - for(uint8 i = 0; i < MAX_SPARKS; ++i) + for (uint8 i = 0; i < MAX_SPARKS; ++i) pCreatureTarget->CastSpell(pCreatureTarget, SPELL_SUMMON_SPARK, true); pCreatureTarget->AttackStop(); @@ -321,7 +310,17 @@ 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) + { + if (pCreatureTarget->GetEntry() != NPC_IONAR) + return true; + + if (boss_ionarAI* pIonarAI = dynamic_cast(pCreatureTarget->AI())) + pIonarAI->DespawnSpark(); + return true; } return false; @@ -333,7 +332,7 @@ bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, SpellEffect struct MANGOS_DLL_DECL 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(); @@ -341,16 +340,16 @@ 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; if (uiPointId == POINT_CALLBACK) { - if (Creature* pIonar = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_IONAR))) + if (Creature* pIonar = m_pInstance->GetSingleCreatureFromStorage(NPC_IONAR)) { if (!pIonar->isAlive()) { @@ -374,16 +373,16 @@ CreatureAI* GetAI_mob_spark_of_ionar(Creature* pCreature) void AddSC_boss_ionar() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_ionar"; - newscript->GetAI = &GetAI_boss_ionar; - newscript->pEffectDummyCreature = &EffectDummyCreature_boss_ionar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_spark_of_ionar"; - newscript->GetAI = &GetAI_mob_spark_of_ionar; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ionar"; + pNewScript->GetAI = &GetAI_boss_ionar; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_boss_ionar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_spark_of_ionar"; + pNewScript->GetAI = &GetAI_mob_spark_of_ionar; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp index 21f0f330f5..53afaa5d91 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 }; @@ -56,7 +56,7 @@ enum struct MANGOS_DLL_DECL 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; @@ -219,10 +173,10 @@ CreatureAI* GetAI_boss_loken(Creature* pCreature) void AddSC_boss_loken() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_loken"; - newscript->GetAI = &GetAI_boss_loken; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_loken"; + pNewScript->GetAI = &GetAI_boss_loken; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp index 4e9b7e809c..12b8573474 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss Volkhan -SD%Complete: 60% -SDComment: Not considered complete. Some events may fail and need further development +SD%Complete: 80% +SDComment: The dummy spells need more research and should be handled in core SDCategory: Halls of Lightning EndScriptData */ @@ -38,32 +38,30 @@ enum EMOTE_TO_ANVIL = -1602041, EMOTE_SHATTER = -1602042, - SPELL_HEAT_N = 52387, + SPELL_HEAT = 52387, SPELL_HEAT_H = 59528, - SPELL_SHATTERING_STOMP_N = 52237, + 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_N = 52433, + SPELL_IMMOLATION_STRIKE = 52433, SPELL_IMMOLATION_STRIKE_H = 59530, - SPELL_SHATTER_N = 52429, + SPELL_SHATTER = 52429, SPELL_SHATTER_H = 59527, - NPC_VOLKHAN_ANVIL = 28823, NPC_MOLTEN_GOLEM = 28695, NPC_BRITTLE_GOLEM = 28681, - POINT_ID_ANVIL = 0, - MAX_GOLEM = 2 + MAX_GOLEM = 2, + MAX_ACHIEV_GOLEMS = 4 }; /*###### @@ -72,7 +70,7 @@ enum struct MANGOS_DLL_DECL 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(); @@ -81,39 +79,25 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI ScriptedInstance* m_pInstance; - std::list m_lGolemGUIDList; + GuidList m_lGolemGUIDList; bool m_bIsRegularMode; - bool m_bHasTemper; - bool m_bIsStriking; - bool m_bCanShatterGolem; bool m_bHasShattered; - uint32 m_uiPause_Timer; - uint32 m_uiShatter_Timer; - - uint32 m_uiHealthAmountModifier; + uint32 m_uiShatterTimer; + uint32 m_uiHeatTimer; + uint32 m_uiTemperTimer; - void Reset() + void Reset() override { - m_bIsStriking = false; - m_bHasTemper = false; - m_bCanShatterGolem = false; m_bHasShattered = false; - m_uiPause_Timer = 3500; - m_uiShatter_Timer = 5000; - - m_uiHealthAmountModifier = 1; - - DespawnGolem(); - m_lGolemGUIDList.clear(); - - if (m_pInstance) - m_pInstance->SetData(TYPE_VOLKHAN, NOT_STARTED); + m_uiShatterTimer = 3000; + m_uiHeatTimer = 30000; + m_uiTemperTimer = 10000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -121,31 +105,26 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI m_pInstance->SetData(TYPE_VOLKHAN, IN_PROGRESS); } - void AttackStart(Unit* pWho) + void JustDied(Unit* /*pKiller*/) override { - if (m_creature->Attack(pWho, true)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); + DoScriptText(SAY_DEATH, m_creature); + DespawnGolems(); - if (!m_bHasTemper) - m_creature->GetMotionMaster()->MoveChase(pWho); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLKHAN, DONE); } - void JustDied(Unit* pKiller) + void JustReachedHome() override { - DoScriptText(SAY_DEATH, m_creature); - DespawnGolem(); + DespawnGolems(); if (m_pInstance) - m_pInstance->SetData(TYPE_VOLKHAN, DONE); + 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; @@ -153,12 +132,12 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI } } - void DespawnGolem() + void DespawnGolems() { if (m_lGolemGUIDList.empty()) return; - for(std::list::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)) { @@ -166,112 +145,120 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI pTemp->ForcedDespawn(); } } - - m_lGolemGUIDList.clear(); } - void ShatterGolem() + void ShatterGolems() { if (m_lGolemGUIDList.empty()) return; - for(std::list::iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + uint8 m_uiBrittleGolemsCount = 0; + + 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 - if (pTemp->isAlive() && pTemp->GetEntry() == NPC_BRITTLE_GOLEM) - pTemp->CastSpell(pTemp, m_bIsRegularMode ? SPELL_SHATTER_N : SPELL_SHATTER_H, false); + // only shatter brittle golems + if (pTemp->GetEntry() == NPC_BRITTLE_GOLEM) + { + pTemp->CastSpell(pTemp, m_bIsRegularMode ? SPELL_SHATTER : SPELL_SHATTER_H, true); + ++m_uiBrittleGolemsCount; + } } } - } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) - { - if (pSpell->Id == SPELL_TEMPER_DUMMY) - m_bIsStriking = true; + // If shattered more than 4 golems mark achiev as failed + if (m_uiBrittleGolemsCount > MAX_ACHIEV_GOLEMS) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLKHAN, SPECIAL); + } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_MOLTEN_GOLEM) { - m_lGolemGUIDList.push_back(pSummoned->GetGUID()); + m_lGolemGUIDList.push_back(pSummoned->GetObjectGuid()); if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); - - //why healing when just summoned? - pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_HEAT_N : SPELL_HEAT_H, false, NULL, NULL, m_creature->GetGUID()); } } - void UpdateAI(const uint32 uiDiff) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) return; - if (m_bIsStriking) - { - if (m_uiPause_Timer < uiDiff) - { - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - { - if (m_creature->getVictim()) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - } - - m_bHasTemper = false; - m_bIsStriking = false; - m_uiPause_Timer = 3500; - } - else - m_uiPause_Timer -= uiDiff; + DoCastSpellIfCan(m_creature, SPELL_TEMPER); + SetCombatMovement(true); + } + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - } - // he shatters only one time, at 20% - if (m_creature->GetHealthPercent() <= 20.0f && !m_bHasShattered) + // he shatters only one time, at 25% + if (m_creature->GetHealthPercent() <= 25.0f && !m_bHasShattered) { // should he stomp even if he has no brittle golem to shatter? <-yes! - if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHATTERING_STOMP_N : SPELL_SHATTERING_STOMP_H) == CAST_OK) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHATTERING_STOMP : SPELL_SHATTERING_STOMP_H) == CAST_OK) { DoScriptText(urand(0, 1) ? SAY_STOMP_1 : SAY_STOMP_2, m_creature); DoScriptText(EMOTE_SHATTER, m_creature); - m_bCanShatterGolem = true; + m_uiShatterTimer = 3000; m_bHasShattered = true; } } // Shatter Golems 3 seconds after Shattering Stomp - if (m_bCanShatterGolem) + if (m_uiShatterTimer) { - if (m_uiShatter_Timer < uiDiff) + if (m_uiShatterTimer <= uiDiff) { - ShatterGolem(); - m_uiShatter_Timer = 3000; - m_bCanShatterGolem = false; + ShatterGolems(); + m_uiShatterTimer = 0; } else - m_uiShatter_Timer -= uiDiff; + m_uiShatterTimer -= uiDiff; } - // Health check - if (!m_bCanShatterGolem && m_creature->GetHealthPercent() < float(100 - 20*m_uiHealthAmountModifier)) + // Summon Golems only when over 25% hp + if (m_creature->GetHealthPercent() > 25.0f) { - ++m_uiHealthAmountModifier; - - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(urand(0, 1) ? SAY_FORGE_1 : SAY_FORGE_2, m_creature); + if (m_uiTemperTimer < uiDiff) + { + DoScriptText(EMOTE_TO_ANVIL, m_creature); + DoScriptText(urand(0, 1) ? SAY_FORGE_1 : SAY_FORGE_2, m_creature); + SetCombatMovement(false); - m_bHasTemper = true; + if (m_pInstance) + { + if (Creature* pAnvil = m_pInstance->GetSingleCreatureFromStorage(NPC_VOLKHAN_ANVIL)) + { + float fX, fY, fZ; + pAnvil->GetContactPoint(m_creature, fX, fY, fZ, INTERACTION_DISTANCE); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + else + script_error_log("Npc %u couldn't be found or something really bad happened.", NPC_VOLKHAN_ANVIL); + } + m_uiTemperTimer = 30000; + } + else + m_uiTemperTimer -= uiDiff; + } - m_creature->CastSpell(m_creature, SPELL_TEMPER, false); + if (m_uiHeatTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HEAT : SPELL_HEAT_H) == CAST_OK) + m_uiHeatTimer = urand(10000, 15000); } + else + m_uiHeatTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -282,25 +269,18 @@ 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) return true; - for(uint8 i = 0; i < MAX_GOLEM; ++i) - { + for (uint8 i = 0; i < MAX_GOLEM; ++i) pCreatureTarget->CastSpell(pCaster, SPELL_SUMMON_MOLTEN_GOLEM, true); - //TODO: remove this line of hack when summon effect implemented - pCreatureTarget->SummonCreature(NPC_MOLTEN_GOLEM, - pCaster->GetPositionX(), pCaster->GetPositionY(), pCaster->GetPositionZ(), 0.0f, - TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - } - - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } @@ -311,30 +291,24 @@ 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) return true; - DoScriptText(EMOTE_TO_ANVIL, pCaster); - - float fX, fY, fZ; - pCreatureTarget->GetContactPoint(pCaster, fX, fY, fZ, INTERACTION_DISTANCE); - - pCaster->AttackStop(); - - if (pCaster->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - pCaster->GetMotionMaster()->MovementExpired(); - - ((Creature*)pCaster)->GetMap()->CreatureRelocation((Creature*)pCaster, fX, fY, fZ, pCreatureTarget->GetOrientation()); - ((Creature*)pCaster)->SendMonsterMove(fX, fY, fZ, SPLINETYPE_NORMAL, ((Creature*)pCaster)->GetSplineFlags(), 1); - pCreatureTarget->CastSpell(pCaster, SPELL_TEMPER_DUMMY, false); + // ToDo: research how the visual spell is used + + if (pCaster->getVictim()) + { + pCaster->GetMotionMaster()->Clear(); + 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; } @@ -347,7 +321,7 @@ bool EffectDummyCreature_npc_volkhan_anvil(Unit* pCaster, uint32 uiSpellId, Spel struct MANGOS_DLL_DECL 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(); @@ -357,94 +331,76 @@ struct MANGOS_DLL_DECL mob_molten_golemAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - bool m_bIsFrozen; - uint32 m_uiBlast_Timer; - uint32 m_uiDeathDelay_Timer; - uint32 m_uiImmolation_Timer; + uint32 m_uiBlastTimer; + uint32 m_uiImmolationTimer; - void Reset() + void Reset() override { - m_bIsFrozen = false; - - m_uiBlast_Timer = 20000; - m_uiDeathDelay_Timer = 0; - m_uiImmolation_Timer = 5000; + m_uiBlastTimer = 20000; + m_uiImmolationTimer = 5000; } - void AttackStart(Unit* pWho) + void EnterEvadeMode() override { - if (m_creature->Attack(pWho, true)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); + // Evade but keep the current location + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); - if (!m_bIsFrozen) - m_creature->GetMotionMaster()->MoveChase(pWho); - } + m_creature->SetLootRecipient(NULL); + + // Update creature to Brittle Golem + // Note: the npc has the proper flags in DB and won't engate in combat anymore + m_creature->UpdateEntry(NPC_BRITTLE_GOLEM); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (m_bIsFrozen) + // Transform intro Brittle when damaged to 0 HP + if (uiDamage >= m_creature->GetHealth()) { - //workaround for now, brittled should be immune to any kind of attacks uiDamage = 0; - return; - } - - if (uiDamage > m_creature->GetHealth()) - { - m_bIsFrozen = true; if (m_creature->IsNonMeleeSpellCasted(false)) m_creature->InterruptNonMeleeSpells(false); - m_creature->RemoveAllAuras(); - m_creature->AttackStop(); - - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MovementExpired(); - - uiDamage = m_creature->GetHealth()-1; - - m_creature->UpdateEntry(NPC_BRITTLE_GOLEM); - m_creature->SetHealth(1); + EnterEvadeMode(); } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - //this is the dummy effect of the spells - if (pSpell->Id == SPELL_SHATTER_N || pSpell->Id == SPELL_SHATTER_H) + // 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) { if (m_creature->GetEntry() == NPC_BRITTLE_GOLEM) - m_creature->ForcedDespawn(); + 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 { - //Return since we have no target or if we are frozen - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || m_bIsFrozen) + // Return since we have no target or if we are frozen + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiBlast_Timer < uiDiff) + if (m_uiBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE); - m_uiBlast_Timer = 20000; + if (DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE) == CAST_OK) + m_uiBlastTimer = 20000; } else - m_uiBlast_Timer -= uiDiff; + m_uiBlastTimer -= uiDiff; - if (m_uiImmolation_Timer < uiDiff) + if (m_uiImmolationTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_IMMOLATION_STRIKE_N : SPELL_IMMOLATION_STRIKE_H); - m_uiImmolation_Timer = 5000; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_IMMOLATION_STRIKE : SPELL_IMMOLATION_STRIKE_H) == CAST_OK) + m_uiImmolationTimer = 5000; } else - m_uiImmolation_Timer -= uiDiff; + m_uiImmolationTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -457,21 +413,21 @@ CreatureAI* GetAI_mob_molten_golem(Creature* pCreature) void AddSC_boss_volkhan() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_volkhan"; - newscript->GetAI = &GetAI_boss_volkhan; - newscript->pEffectDummyCreature = &EffectDummyCreature_boss_volkhan; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_volkhan_anvil"; - newscript->pEffectDummyCreature = &EffectDummyCreature_npc_volkhan_anvil; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_molten_golem"; - newscript->GetAI = &GetAI_mob_molten_golem; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_volkhan"; + pNewScript->GetAI = &GetAI_boss_volkhan; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_boss_volkhan; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_volkhan_anvil"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_volkhan_anvil; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_molten_golem"; + pNewScript->GetAI = &GetAI_mob_molten_golem; + pNewScript->RegisterSelf(); } 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 1311076102..d0cd8340fd 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -9,25 +9,52 @@ enum { MAX_ENCOUNTER = 4, - DATA_BJARNGRIM = 1, - DATA_IONAR = 2, - DATA_LOKEN = 3, - DATA_VOLKHAN = 4, - - TYPE_BJARNGRIM = 10, - TYPE_IONAR = 11, - TYPE_LOKEN = 12, - TYPE_VOLKHAN = 13, + TYPE_BJARNGRIM = 0, + TYPE_VOLKHAN = 1, + TYPE_IONAR = 2, + TYPE_LOKEN = 3, NPC_BJARNGRIM = 28586, NPC_VOLKHAN = 28587, NPC_IONAR = 28546, NPC_LOKEN = 28923, + NPC_VOLKHAN_ANVIL = 28823, GO_VOLKHAN_DOOR = 191325, //_doors07 GO_IONAR_DOOR = 191326, //_doors05 - GO_LOKEN_DOOR = 191324, //_doors02 - GO_LOKEN_THRONE = 192654 + // 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 +{ + public: + instance_halls_of_lightning(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + 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*/) 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; + + bool m_bLightningStruck; + bool m_bIsShatterResistant; }; #endif 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 3f2dc17626..94e4c70f8e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -31,185 +31,144 @@ EndScriptData */ 3 - Loken */ -struct MANGOS_DLL_DECL instance_halls_of_lightning : public ScriptedInstance +instance_halls_of_lightning::instance_halls_of_lightning(Map* pMap) : ScriptedInstance(pMap), + m_bLightningStruck(false), + m_bIsShatterResistant(false) { - instance_halls_of_lightning(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiGeneralBjarngrimGUID; - uint64 m_uiIonarGUID; - uint64 m_uiLokenGUID; - uint64 m_uiVolkhanGUID; + Initialize(); +} - uint64 m_uiVolkhanDoorGUID; - uint64 m_uiIonarDoorGUID; - uint64 m_uiLokenDoorGUID; - uint64 m_uiLokenGlobeGUID; +void instance_halls_of_lightning::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_halls_of_lightning::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiGeneralBjarngrimGUID = 0; - m_uiVolkhanGUID = 0; - m_uiIonarGUID = 0; - m_uiLokenGUID = 0; - - m_uiVolkhanDoorGUID = 0; - m_uiIonarDoorGUID = 0; - m_uiLokenDoorGUID = 0; - m_uiLokenGlobeGUID = 0; + case NPC_BJARNGRIM: + case NPC_IONAR: + case NPC_VOLKHAN_ANVIL: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_halls_of_lightning::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case NPC_BJARNGRIM: - m_uiGeneralBjarngrimGUID = pCreature->GetGUID(); - break; - case NPC_VOLKHAN: - m_uiVolkhanGUID = pCreature->GetGUID(); - break; - case NPC_IONAR: - m_uiIonarGUID = pCreature->GetGUID(); - break; - case NPC_LOKEN: - m_uiLokenGUID = pCreature->GetGUID(); - break; - } + case GO_VOLKHAN_DOOR: + if (m_auiEncounter[TYPE_VOLKHAN] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_IONAR_DOOR: + if (m_auiEncounter[TYPE_IONAR] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_LOKEN_THRONE: + break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) +void instance_halls_of_lightning::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(pGo->GetEntry()) - { - case GO_VOLKHAN_DOOR: - m_uiVolkhanDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_IONAR_DOOR: - m_uiIonarDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_LOKEN_DOOR: - m_uiLokenDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_LOKEN_THRONE: - m_uiLokenGlobeGUID = pGo->GetGUID(); - break; - } + 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); + else if (uiData == IN_PROGRESS) + m_bIsShatterResistant = true; + else if (uiData == SPECIAL) + m_bIsShatterResistant = false; + m_auiEncounter[uiType] = uiData; + break; + case TYPE_IONAR: + if (uiData == DONE) + DoUseDoorOrButton(GO_IONAR_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_LOKEN: + if (uiData == IN_PROGRESS) + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_LOKEN_ID); + else if (uiData == DONE) + { + if (GameObject* pGlobe = GetSingleGameObjectFromStorage(GO_LOKEN_THRONE)) + pGlobe->SendGameObjectCustomAnim(pGlobe->GetObjectGuid()); + } + m_auiEncounter[uiType] = uiData; + break; } - void SetData(uint32 uiType, uint32 uiData) + if (uiData == DONE) { - switch(uiType) - { - case TYPE_BJARNGRIM: - m_auiEncounter[0] = uiData; - break; - case TYPE_VOLKHAN: - if (uiData == DONE) - DoUseDoorOrButton(m_uiVolkhanDoorGUID); - m_auiEncounter[1] = uiData; - break; - case TYPE_IONAR: - if (uiData == DONE) - DoUseDoorOrButton(m_uiIonarDoorGUID); - m_auiEncounter[2] = uiData; - break; - case TYPE_LOKEN: - if (uiData == DONE) - { - DoUseDoorOrButton(m_uiLokenDoorGUID); - - //Appears to be type 5 GO with animation. Need to figure out how this work, code below only placeholder - if (GameObject* pGlobe = instance->GetGameObject(m_uiLokenGlobeGUID)) - pGlobe->SetGoState(GO_STATE_ACTIVE); - } - m_auiEncounter[3] = 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]; - - strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } + OUT_SAVE_INST_DATA; - const char* Save() - { - return strInstData.c_str(); - } + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_BJARNGRIM: - return m_auiEncounter[0]; - case TYPE_VOLKHAN: - return m_auiEncounter[1]; - case TYPE_IONAR: - return m_auiEncounter[2]; - case TYPE_LOKEN: - return m_auiEncounter[3]; - } - return 0; + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint64 GetData64(uint32 uiData) +uint32 instance_halls_of_lightning::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +bool instance_halls_of_lightning::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) { - switch(uiData) - { - case DATA_BJARNGRIM: - return m_uiGeneralBjarngrimGUID; - case DATA_VOLKHAN: - return m_uiVolkhanGUID; - case DATA_IONAR: - return m_uiIonarGUID; - case DATA_LOKEN: - return m_uiLokenGUID; - } - return 0; + case ACHIEV_CRIT_LIGHTNING: + return m_bLightningStruck; + case ACHIEV_CRIT_RESISTANT: + return m_bIsShatterResistant; } - void Load(const char* in) - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + return false; +} - OUT_LOAD_INST_DATA(in); +void instance_halls_of_lightning::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - std::istringstream loadStream(in); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; + OUT_LOAD_INST_DATA(chrIn); - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - OUT_LOAD_INST_DATA_COMPLETE; + 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_halls_of_lightning(Map* pMap) { @@ -218,9 +177,10 @@ InstanceData* GetInstanceData_instance_halls_of_lightning(Map* pMap) void AddSC_instance_halls_of_lightning() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_halls_of_lightning"; - newscript->GetInstanceData = &GetInstanceData_instance_halls_of_lightning; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_halls_of_lightning"; + pNewScript->GetInstanceData = &GetInstanceData_instance_halls_of_lightning; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp b/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp new file mode 100644 index 0000000000..a8cfa67e23 --- /dev/null +++ b/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp @@ -0,0 +1,175 @@ +/* Copyright (C) 2006 - 2013 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 Krystallus +SDAuthor: ckegg +SD%Complete: 0% +SDComment: +SDCategory: Halls of Stone +EndScriptData */ + +#include "precompiled.h" +#include "halls_of_stone.h" + +enum +{ + SAY_AGGRO = -1599000, + SAY_KILL = -1599001, + SAY_DEATH = -1599002, + SAY_SHATTER = -1599003, + + SPELL_BOULDER_TOSS = 50843, + SPELL_BOULDER_TOSS_H = 59742, + SPELL_GROUND_SPIKE = 59750, + SPELL_GROUND_SLAM = 50827, + SPELL_SHATTER = 50810, + SPELL_SHATTER_H = 61546, + SPELL_STOMP = 50868, + SPELL_STOMP_H = 59744, + +}; + +/*###### +## boss_krystallus +######*/ + +struct MANGOS_DLL_DECL boss_krystallusAI : public ScriptedAI +{ + boss_krystallusAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsRegularMode; + bool m_bIsSlam; + + uint32 m_uiToss_Timer; + uint32 m_uiSpike_Timer; + uint32 m_uiSlam_Timer; + uint32 m_uiShatter_Timer; + uint32 m_uiStomp_Timer; + + void Reset() + { + m_bIsSlam = false; + m_uiToss_Timer = 3000 + rand()%6000; + m_uiSpike_Timer = 9000 + rand()%5000; + m_uiSlam_Timer = 15000 + rand()%3000; + m_uiStomp_Timer = 20000 + rand()%9000; + m_uiShatter_Timer = 0; + + if(m_pInstance) + m_pInstance->SetData(TYPE_KRYSTALLUS, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) override + { + DoScriptText(SAY_AGGRO,m_creature); + + if(m_pInstance) + m_pInstance->SetData(TYPE_KRYSTALLUS, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(SAY_KILL, m_creature); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_KRYSTALLUS, DONE); + } + + void UpdateAI(const uint32 uiDiff) override + { + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiToss_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsRegularMode ? SPELL_BOULDER_TOSS_H : SPELL_BOULDER_TOSS); + m_uiToss_Timer = 9000 + rand()%6000; + } + else + m_uiToss_Timer -= uiDiff; + + if (m_uiSpike_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_GROUND_SPIKE); + m_uiSpike_Timer = 12000 + rand()%5000; + } + else + m_uiSpike_Timer -= uiDiff; + + if (m_uiStomp_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_STOMP_H : SPELL_STOMP); + m_uiStomp_Timer = 20000 + rand()%9000; + } + else + m_uiStomp_Timer -= uiDiff; + + if (m_uiSlam_Timer < uiDiff) + { + DoCast(m_creature, SPELL_GROUND_SLAM); + m_bIsSlam = true; + m_uiShatter_Timer = 10000; + m_uiSlam_Timer = 15000 + rand()%3000; + } + else + m_uiSlam_Timer -= uiDiff; + + if (m_bIsSlam) + { + if (m_uiShatter_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_SHATTER_H : SPELL_SHATTER); + m_bIsSlam = false; + m_uiShatter_Timer = 0; + } + else + m_uiShatter_Timer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_krystallus(Creature* pCreature) +{ + return new boss_krystallusAI (pCreature); +} + +void AddSC_boss_krystallus() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_krystallus"; + newscript->GetAI = &GetAI_boss_krystallus; + newscript->RegisterSelf(); +} 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 cff0b1ad49..2dcbf679b2 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -54,33 +54,44 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI { boss_maiden_of_griefAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_halls_of_stone*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_halls_of_stone* m_pInstance; bool m_bIsRegularMode; uint32 m_uiStormTimer; uint32 m_uiShockTimer; uint32 m_uiPillarTimer; + uint32 m_uiPartingSorrowTimer; - void Reset() + void Reset() override { m_uiStormTimer = 5000; m_uiShockTimer = 10000; m_uiPillarTimer = 15000; + m_uiPartingSorrowTimer = 12000; } - 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 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; @@ -89,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); @@ -97,11 +108,22 @@ 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; + if (m_uiPartingSorrowTimer < uiDiff) + { + 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; + } + } + 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) @@ -112,7 +134,7 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI if (m_uiPillarTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, m_bIsRegularMode ? SPELL_PILLAR_OF_WOE_H : SPELL_PILLAR_OF_WOE, SELECT_FLAG_PLAYER)) { if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_PILLAR_OF_WOE : SPELL_PILLAR_OF_WOE_H) == CAST_OK) m_uiPillarTimer = 10000; @@ -123,7 +145,7 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI if (m_uiShockTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHOCK_OF_SORROW : SPELL_SHOCK_OF_SORROW_H) == CAST_OK) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHOCK_OF_SORROW : SPELL_SHOCK_OF_SORROW_H) == CAST_OK) { DoScriptText(SAY_STUN, m_creature); m_uiShockTimer = 35000; @@ -143,10 +165,10 @@ CreatureAI* GetAI_boss_maiden_of_grief(Creature* pCreature) void AddSC_boss_maiden_of_grief() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_maiden_of_grief"; - newscript->GetAI = &GetAI_boss_maiden_of_grief; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_maiden_of_grief"; + pNewScript->GetAI = &GetAI_boss_maiden_of_grief; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp b/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp index 7c4b37ee09..5aa7ab76b1 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Sjonnir -SD%Complete: 20% -SDComment: +SD%Complete: 60% +SDComment: Brann Event missing, no proper source for timers SDCategory: Halls of Stone EndScriptData */ @@ -47,22 +47,30 @@ enum SPELL_LIGHTNING_RING = 50840, SPELL_LIGHTNING_RING_H = 59848, + // Cast on aggro SPELL_SUMMON_IRON_DWARF = 50789, // periodic dummy aura, tick each 30sec or each 20sec in heroic SPELL_SUMMON_IRON_DWARF_H = 59860, // left/right 50790,50791 + // Cast at 75% hp (also Brann has some yells at that point) SPELL_SUMMON_IRON_TROGG = 50792, // periodic dummy aura, tick each 10sec or each 7sec in heroic SPELL_SUMMON_IRON_TROGG_H = 59859, // left/right 50793,50794 + // Cast at 50% hp SPELL_SUMMON_MALFORMED_OOZE = 50801, // periodic dummy aura, tick each 5sec or each 3sec in heroic SPELL_SUMMON_MALFORMED_OOZE_H = 59858, // left/right 50802,50803 - SPELL_SUMMON_IRON_SLUDGE = 50747, // instakill TARGET_SCRIPT - SPELL_IRON_SLUDGE_SPAWN_VISUAL = 50777, + // Cast at 15% hp when Bran repairs the machine + SPELL_SUMMON_EARTHEN_DWARF = 50824, // left/right 50825, 50826 + + // 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, }; /*###### @@ -81,36 +89,94 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiChainLightningTimer; + uint32 m_uiLightningShieldTimer; + uint32 m_uiStaticChargeTimer; + uint32 m_uiLightningRingTimer; + uint32 m_uiFrenzyTimer; + + uint8 m_uiHpCheck; + + void Reset() override { - if (m_creature->isAlive()) - m_creature->CastSpell(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_SHIELD : SPELL_LIGHTNING_SHIELD_H, false); + 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_uiHpCheck = 75; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - m_creature->CastSpell(m_creature, m_bIsRegularMode ? SPELL_SUMMON_IRON_DWARF : SPELL_SUMMON_IRON_DWARF_H, true); - m_creature->CastSpell(m_creature, m_bIsRegularMode ? SPELL_SUMMON_IRON_TROGG : SPELL_SUMMON_IRON_TROGG_H, true); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_SHIELD : SPELL_LIGHTNING_SHIELD_H, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_IRON_DWARF : SPELL_SUMMON_IRON_DWARF_H, CAST_TRIGGERED); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SJONNIR, IN_PROGRESS); } + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SJONNIR, DONE); + } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override { - if (pSummoned->GetEntry() == NPC_IRON_TROGG || pSummoned->GetEntry() == NPC_IRON_DWARF || pSummoned->GetEntry() == NPC_MALFORMED_OOZE) + if (m_pInstance) + m_pInstance->SetData(TYPE_SJONNIR, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + 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->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + break; + } } } - void KilledUnit(Unit* pVictim) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + 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)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -118,16 +184,87 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + bool DoFrenzyIfCan() { - DoScriptText(SAY_DEATH, m_creature); + if (!m_uiFrenzyTimer) + return true; + + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_EARTHEN_DWARF, CAST_TRIGGERED); + m_uiFrenzyTimer = 0; + + return true; + } + + 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) + { + case 75: + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_IRON_TROGG : SPELL_SUMMON_IRON_TROGG_H, CAST_TRIGGERED) == CAST_OK) + m_uiHpCheck = 50; + break; + 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; + + break; + } + } + + 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_uiLightningShieldTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_SHIELD : SPELL_LIGHTNING_SHIELD_H) == CAST_OK) + m_uiLightningShieldTimer = urand(20000, 25000); + } + else + m_uiLightningShieldTimer -= uiDiff; + + if (m_uiStaticChargeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_STATIC_CHARGE : SPELL_STATIC_CHARGE_H) == CAST_OK) + m_uiStaticChargeTimer = urand(20000, 25000); + } + else + m_uiStaticChargeTimer -= uiDiff; + + if (m_uiLightningRingTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_RING : SPELL_LIGHTNING_RING_H) == CAST_OK) + m_uiLightningRingTimer = urand(30000, 35000); + } + else + m_uiLightningRingTimer -= uiDiff; + + if (m_uiFrenzyTimer <= uiDiff) + DoFrenzyIfCan(); + else + m_uiFrenzyTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -139,10 +276,10 @@ CreatureAI* GetAI_boss_sjonnir(Creature* pCreature) void AddSC_boss_sjonnir() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_sjonnir"; - newscript->GetAI = &GetAI_boss_sjonnir; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_sjonnir"; + pNewScript->GetAI = &GetAI_boss_sjonnir; + pNewScript->RegisterSelf(); } 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 085fe28649..871a872131 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Halls_of_Stone -SD%Complete: 20% -SDComment: +SD%Complete: 50% +SDComment: Just base mechanics in script, timers and stuff is very uncertain, event-spells are not working SDCategory: Halls of Stone EndScriptData */ @@ -25,6 +25,11 @@ EndScriptData */ #include "halls_of_stone.h" #include "escort_ai.h" +/* Notes + * The timers and handling of texts is not confirmed, but should also not be too far off + * The spells "of the statues" (handled in instance script), need quite much of core support + */ + enum { SAY_KILL_1 = -1599012, @@ -90,12 +95,26 @@ enum SAY_ENTRANCE_MEET = -1599064, + GOSSIP_ITEM_ID_START = -3599000, + GOSSIP_ITEM_ID_PROGRESS = -3599001, + TEXT_ID_START = 13100, - TEXT_ID_PROGRESS = 13101 -}; + TEXT_ID_PROGRESS = 13101, + + SPELL_SUMMON_PROTECTOR = 51780, // all spells are casted by stalker npcs 28130 + SPELL_SUMMON_STORMCALLER = 51050, + SPELL_SUMMON_CUSTODIAN = 51051, -#define GOSSIP_ITEM_START "Brann, it would be our honor!" -#define GOSSIP_ITEM_PROGRESS "Let's move Brann, enough of the history lessons!" + SPELL_STEALTH = 58506, + + SPELL_ACHIEVEMENT_CHECK = 59046, // Doesn't exist in client dbc + + NPC_DARK_RUNE_PROTECTOR = 27983, + NPC_DARK_RUNE_STORMCALLER = 27984, + NPC_IRON_GOLEM_CUSTODIAN = 27985, + + QUEST_HALLS_OF_STONE = 13207, +}; /*###### ## npc_brann_hos @@ -105,25 +124,39 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI { npc_brann_hosAI(Creature* pCreature) : npc_escortAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_halls_of_stone*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_halls_of_stone* m_pInstance; bool m_bIsRegularMode; - void Reset() - { - } + bool m_bHasContinued; + bool m_bIsBattle; + bool m_bIsLowHP; + + uint32 m_uiStep; + uint32 m_uiPhaseTimer; + + GuidList m_luiDwarfGUIDs; - void WaypointReached(uint32 uiPointId) + void Reset() override { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_bIsLowHP = false; + m_bIsBattle = false; + m_bHasContinued = false; + + m_uiStep = 0; + m_uiPhaseTimer = 0; + } } - void KilledUnit(Unit* pVictim) + 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; @@ -131,37 +164,487 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_TRIBUNAL, FAIL); + // Continue at right state after respawn + if (m_bHasContinued) + m_pInstance->SetData(TYPE_TRIBUNAL, IN_PROGRESS); + } + + for (GuidList::const_iterator itr = m_luiDwarfGUIDs.begin(); itr != m_luiDwarfGUIDs.end(); ++itr) + { + if (Creature* pDwarf = m_creature->GetMap()->GetCreature(*itr)) + pDwarf->ForcedDespawn(); + } + m_luiDwarfGUIDs.clear(); + } + + void AttackStart(Unit* pWho) override + { + if (!pWho) + return; + + if (!m_bIsBattle) + return; + + npc_escortAI::AttackStart(pWho); + } + + void ContinueEvent() + { + if (!m_pInstance || m_pInstance->GetData(TYPE_TRIBUNAL) != IN_PROGRESS) + return; + + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + SetRun(true); + SetEscortPaused(false); + m_bHasContinued = true; + } + + void JustStartedEscort() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_TRIBUNAL, IN_PROGRESS); + + DoScriptText(SAY_ESCORT_START, m_creature); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 13: // Before Tribunal Event, Continue with Gossip Interaction + DoScriptText(SAY_EVENT_INTRO_1, m_creature); + SetEscortPaused(true); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + case 17: // Reach Tribunal + SetEscortPaused(true); + m_uiPhaseTimer = 500; + break; + case 18: // Reach Floor Event + SetEscortPaused(true); + if (m_pInstance) + { + if (GameObject* pKonsole = m_pInstance->GetSingleGameObjectFromStorage(GO_TRIBUNAL_CONSOLE)) + m_creature->SetFacingToObject(pKonsole); + m_pInstance->DoUseDoorOrButton(GO_TRIBUNAL_FLOOR); + } + 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) + 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) + pStalker->CastSpell(pStalker, SPELL_SUMMON_STORMCALLER, true, NULL, NULL, m_creature->GetObjectGuid()); + break; + } + case NPC_IRON_GOLEM_CUSTODIAN: + { + 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) 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 + case 0: + // TODO, this is wrong, must be "using or similar" + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiPhaseTimer = 1500; + break; + case 1: + DoScriptText(SAY_EVENT_INTRO_2, m_creature); + m_uiPhaseTimer = 2500; + break; + case 2: + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_TRIBUNAL_CONSOLE); + m_uiPhaseTimer = 6500; + break; + case 3: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_INTRO_3_ABED); + m_uiPhaseTimer = 8500; + break; + + // Activate Kaddrak + case 4: + DoScriptText(SAY_EVENT_A_1, m_creature); + m_uiPhaseTimer = 6500; + break; + case 5: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_KADDRAK, SAY_EVENT_A_2_KADD); + m_uiPhaseTimer = 12500; + break; + case 6: + DoScriptText(SAY_EVENT_A_3, m_creature); + m_uiPhaseTimer = 6000; + break; + case 7: + if (m_pInstance) + m_pInstance->ActivateFace(FACE_KADDRAK, false); + m_uiPhaseTimer = 5000; + break; + case 8: + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 20000; + break; + + // Activate Marnak + case 9: + DoScriptText(SAY_EVENT_B_1, m_creature); + m_uiPhaseTimer = 6000; + break; + case 10: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_MARNAK, SAY_EVENT_B_2_MARN); + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 20000; + break; + case 11: + DoScriptText(SAY_EVENT_B_3, m_creature); + m_uiPhaseTimer = 5000; + break; + case 12: + if (m_pInstance) + m_pInstance->ActivateFace(FACE_MARNAK, false); + m_uiPhaseTimer = 10000; + break; + case 13: + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 10000; + break; + case 14: + SpawnDwarf(NPC_DARK_RUNE_STORMCALLER); + m_uiPhaseTimer = (20000); + break; + case 15: + DoScriptText(SAY_EVENT_C_1, m_creature); + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 10000; + break; + case 16: + SpawnDwarf(NPC_DARK_RUNE_STORMCALLER); + m_uiPhaseTimer = 20000; + break; + + // Activate Abedneum + case 17: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_C_2_ABED); + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 20000; + break; + case 18: + DoScriptText(SAY_EVENT_C_3, m_creature); + m_uiPhaseTimer = 5000; + break; + case 19: + if (m_pInstance) + m_pInstance->ActivateFace(FACE_ABEDNEUM, false); + m_uiPhaseTimer = 5000; + break; + case 20: + SpawnDwarf(NPC_DARK_RUNE_STORMCALLER); + m_uiPhaseTimer = 10000; + break; + case 21: + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 15000; + break; + + case 22: + DoScriptText(SAY_EVENT_D_1, m_creature); + SpawnDwarf(NPC_IRON_GOLEM_CUSTODIAN); + m_uiPhaseTimer = 20000; + break; + case 23: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_D_2_ABED); + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 5000; + break; + case 24: + SpawnDwarf(NPC_DARK_RUNE_STORMCALLER); + m_uiPhaseTimer = 15000; + break; + case 25: + DoScriptText(SAY_EVENT_D_3, m_creature); + SpawnDwarf(NPC_IRON_GOLEM_CUSTODIAN); + m_uiPhaseTimer = 5000; + break; + case 26: + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 5000; + break; + case 27: + SpawnDwarf(NPC_DARK_RUNE_STORMCALLER); + m_uiPhaseTimer = 10000; + break; + case 28: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_D_4_ABED); + SpawnDwarf(NPC_DARK_RUNE_PROTECTOR); + m_uiPhaseTimer = 10000; + break; + + // 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 + SetEscortPaused(false); + m_uiPhaseTimer = 3000; + // break; + // case 30: + if (m_pInstance) + m_pInstance->ActivateFace(FACE_ABEDNEUM, true); + m_uiPhaseTimer = 0; + break; + case 30: + DoScriptText(SAY_EVENT_END_02, m_creature); + m_uiPhaseTimer = 5500; + break; + case 31: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_END_03_ABED); + m_uiPhaseTimer = 8500; + break; + case 32: + DoScriptText(SAY_EVENT_END_04, m_creature); + m_uiPhaseTimer = 11500; + break; + case 33: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_END_05_ABED); + m_uiPhaseTimer = 11500; + break; + case 34: + DoScriptText(SAY_EVENT_END_06, m_creature); + m_uiPhaseTimer = 4500; + break; + case 35: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_END_07_ABED); + m_uiPhaseTimer = 22500; + break; + case 36: + DoScriptText(SAY_EVENT_END_08, m_creature); + m_uiPhaseTimer = 7500; + break; + case 37: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_KADDRAK, SAY_EVENT_END_09_KADD); + m_uiPhaseTimer = 18500; + break; + case 38: + DoScriptText(SAY_EVENT_END_10, m_creature); + m_uiPhaseTimer = 5500; + break; + case 39: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_KADDRAK, SAY_EVENT_END_11_KADD); + m_uiPhaseTimer = 20500; + break; + case 40: + DoScriptText(SAY_EVENT_END_12, m_creature); + m_uiPhaseTimer = 2500; + break; + case 41: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_KADDRAK, SAY_EVENT_END_13_KADD); + m_uiPhaseTimer = 19500; + break; + case 42: + DoScriptText(SAY_EVENT_END_14, m_creature); + m_uiPhaseTimer = 10500; + break; + case 43: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_MARNAK, SAY_EVENT_END_15_MARN); + m_uiPhaseTimer = 6500; + break; + case 44: + DoScriptText(SAY_EVENT_END_16, m_creature); + m_uiPhaseTimer = 6500; + break; + case 45: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_MARNAK, SAY_EVENT_END_17_MARN); + m_uiPhaseTimer = 25500; + break; + case 46: + DoScriptText(SAY_EVENT_END_18, m_creature); + m_uiPhaseTimer = 23500; + break; + case 47: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_MARNAK, SAY_EVENT_END_19_MARN); + m_uiPhaseTimer = 3500; + break; + case 48: + DoScriptText(SAY_EVENT_END_20, m_creature); + m_uiPhaseTimer = 8500; + break; + case 49: + if (m_pInstance) + m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_END_21_ABED); + m_uiPhaseTimer = 5500; + break; + case 50: + { + if (m_pInstance) + { + m_pInstance->DoUseDoorOrButton(GO_TRIBUNAL_FLOOR); + 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); + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + m_uiPhaseTimer = 180000; + break; + } + case 51: + SetEscortPaused(false); + break; + } + ++m_uiStep; + } + else if (m_uiPhaseTimer) + m_uiPhaseTimer -= uiDiff; + + if (!m_bIsLowHP && m_creature->GetHealthPercent() < 30) + { + DoScriptText(SAY_LOW_HEALTH, m_creature); + m_bIsLowHP = true; + } + else if (m_bIsLowHP && m_creature->GetHealthPercent() > 30) + m_bIsLowHP = false; + + // No Combat abilities needed here if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + } + + // Respawn Handling: Relocate and Set Escort to WP 13 + void JustRespawned() override + { + if (!m_pInstance) + return; + + Reset(); + + if (m_pInstance->GetData(TYPE_TRIBUNAL) == IN_PROGRESS) + { + SetEscortPaused(true); - DoMeleeAttackIfReady(); + m_uiStep = 0; + m_uiPhaseTimer = 0; + + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + // Relocate to position of WP 13 + m_creature->GetMap()->CreatureRelocation(m_creature, 941.101563f, 377.373413f, 207.421f, 3.85f); + + SetCurrentWaypoint(13); + } } }; bool GossipHello_npc_brann_hos(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_START, pCreature->GetGUID()); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (instance_halls_of_stone* pInstance = (instance_halls_of_stone*)(pCreature->GetInstanceData())) + { + if (pInstance->GetData(TYPE_TRIBUNAL) == NOT_STARTED || pInstance->GetData(TYPE_TRIBUNAL) == FAIL) + { + 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_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()); + } + } - //pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_PROGRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - //pPlayer->SEND_GOSSIP_MENU(TEXT_ID_PROGRESS, pCreature->GetGUID()); 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) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1 || uiAction == GOSSIP_ACTION_INFO_DEF+2) - pPlayer->CLOSE_GOSSIP_MENU(); + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF + 1: + 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())) + pBrannAi->ContinueEvent(); + break; + } + pPlayer->CLOSE_GOSSIP_MENU(); return true; } @@ -171,6 +654,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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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; @@ -181,4 +777,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 aca0a7b185..68f741bbb0 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -14,14 +14,22 @@ enum TYPE_KRYSTALLUS = 2, TYPE_SJONNIR = 3, - NPC_BRANN = 28070, + // NPC_BRANN = 28070, NPC_KADDRAK = 30898, NPC_ABEDNEUM = 30899, 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_SJONNIR = 191296, + GO_DOOR_MAIDEN = 191292, GO_DOOR_TRIBUNAL = 191294, // possibly closed during event? + GO_DOOR_TO_TRIBUNAL = 191295, + GO_DOOR_SJONNIR = 191296, GO_TRIBUNAL_CHEST = 190586, GO_TRIBUNAL_CHEST_H = 193996, @@ -33,7 +41,83 @@ enum GO_TRIBUNAL_CONSOLE = 193907, GO_TRIBUNAL_FLOOR = 191527, - GO_SJONNIR_CONSOLE = 193906 + 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 +{ + Face() : m_bIsActive(false), m_uiTimer(1000) {} + + ObjectGuid m_leftEyeGuid; + ObjectGuid m_rightEyeGuid; + ObjectGuid m_goFaceGuid; + ObjectGuid m_speakerGuid; + bool m_bIsActive; + uint32 m_uiTimer; +}; + +class MANGOS_DLL_DECL instance_halls_of_stone : public ScriptedInstance +{ + public: + instance_halls_of_stone(Map* pMap); + 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 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); + + ObjectGuid GetProtectorStalkerGuid() { return m_protectorStalkerGuid; } + ObjectGuid GeStormcallerStalkerGuid() { return m_stormcallerStalkerGuid; } + ObjectGuid GetCustodianStalkerGuid() { return m_custodianStalkerGuid; } + + private: + void SortFaces(); + void ProcessFace(uint8 uiFace); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + Face m_aFaces[MAX_FACES]; + std::string m_strInstData; + + 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 2274a29e10..a3339a8f46 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,7 +16,7 @@ /* ScriptData SDName: Instance_Halls_of_Stone -SD%Complete: 10% +SD%Complete: 50% SDComment: SDCategory: Halls of Stone EndScriptData */ @@ -24,173 +24,391 @@ EndScriptData */ #include "precompiled.h" #include "halls_of_stone.h" -struct MANGOS_DLL_DECL instance_halls_of_stone : public ScriptedInstance +enum { - instance_halls_of_stone(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + // KADDRAK + SPELL_GLARE_OF_THE_TRIBUNAL = 50988, + SPELL_GLARE_OF_THE_TRIBUNAL_H = 59870, - uint32 m_auiEncounter[MAX_ENCOUNTER]; + // MARNAK + // Spells are handled in individual script - uint64 m_uiBrannGUID; - uint64 m_uiKaddrakGUID; - uint64 m_uiAbedneumGUID; - uint64 m_uiMarnakGUID; + // ABEDNEUM + SPELL_SUMMON_SEARING_GAZE_TARGET = 51146, // The other spells are handled in individual script - uint64 m_uiSjonnirDoorGUID; - uint64 m_uiTribunalDoorGUID; - uint64 m_uiTribunalChestGUID; - uint64 m_uiTribunalHeadRightGUID; - uint64 m_uiTribunalHeadCenterGUID; - uint64 m_uiTribunalHeadLeftGUID; - uint64 m_uiTribunalConsoleGUID; - uint64 m_uiTribunalFloorGUID; - uint64 m_uiSjonnirConsoleGUID; + SPELL_KILL_TRIBUNAL_ADD = 51288, // Cleanup event on finish +}; + +instance_halls_of_stone::instance_halls_of_stone(Map* pMap) : ScriptedInstance(pMap), + m_uiIronSludgeKilled(0), + m_bIsBrannSpankin(false) +{ + Initialize(); +} + +void instance_halls_of_stone::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_halls_of_stone::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiBrannGUID = 0; - m_uiKaddrakGUID = 0; - m_uiAbedneumGUID = 0; - m_uiMarnakGUID = 0; - - m_uiSjonnirDoorGUID = 0; - m_uiTribunalDoorGUID = 0; - m_uiTribunalChestGUID = 0; - m_uiTribunalHeadRightGUID = 0; - m_uiTribunalHeadCenterGUID = 0; - m_uiTribunalHeadLeftGUID = 0; - m_uiTribunalConsoleGUID = 0; - m_uiTribunalFloorGUID = 0; - m_uiSjonnirConsoleGUID = 0; + 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[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_halls_of_stone::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case NPC_BRANN: - m_uiBrannGUID = pCreature->GetGUID(); - break; - case NPC_KADDRAK: - m_uiKaddrakGUID = pCreature->GetGUID(); - break; - case NPC_ABEDNEUM: - m_uiAbedneumGUID = pCreature->GetGUID(); - break; - case NPC_MARNAK: - m_uiMarnakGUID = pCreature->GetGUID(); - break; - } + case GO_TRIBUNAL_CHEST: + case GO_TRIBUNAL_CHEST_H: + if (m_auiEncounter[TYPE_TRIBUNAL] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; + case GO_TRIBUNAL_HEAD_RIGHT: + m_aFaces[FACE_MARNAK].m_goFaceGuid = pGo->GetObjectGuid(); + return; + case GO_TRIBUNAL_HEAD_CENTER: + m_aFaces[FACE_ABEDNEUM].m_goFaceGuid = pGo->GetObjectGuid(); + return; + case GO_TRIBUNAL_HEAD_LEFT: + m_aFaces[FACE_KADDRAK].m_goFaceGuid = pGo->GetObjectGuid(); + return; + case GO_DOOR_TO_TRIBUNAL: + case GO_DOOR_MAIDEN: + case GO_DOOR_SJONNIR: + case GO_DOOR_TRIBUNAL: + case GO_TRIBUNAL_CONSOLE: + case GO_TRIBUNAL_FLOOR: + case GO_SJONNIR_CONSOLE: + break; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_halls_of_stone::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_TRIBUNAL: + m_auiEncounter[uiType] = uiData; + switch (uiData) + { + case IN_PROGRESS: + SortFaces(); + // Uncomment when this achievement is implemented + // m_bIsBrannSpankin = true; + break; + case DONE: + 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); + break; + case FAIL: + for (uint8 i = 0; i < MAX_FACES; ++i) + { + // Shut down the faces + if (m_aFaces[i].m_bIsActive) + DoUseDoorOrButton(m_aFaces[i].m_goFaceGuid); + m_aFaces[i].m_bIsActive = false; + m_aFaces[i].m_uiTimer = 1000; + } + break; + case SPECIAL: + for (uint8 i = 0; i < MAX_FACES; ++i) + { + m_aFaces[i].m_bIsActive = false; + m_aFaces[i].m_uiTimer = 1000; + // 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; + } + break; + case TYPE_MAIDEN: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_MAIDEN_ID); + break; + case TYPE_KRYSTALLUS: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_SJONNIR: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_DOOR_SJONNIR); + if (uiData == IN_PROGRESS) + m_uiIronSludgeKilled = 0; + 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_halls_of_stone::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[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) {} + bool operator()(WorldObject* pLeft, WorldObject* pRight) + { + return m_pRef->GetDistanceOrder(pLeft, pRight); + } + WorldObject const* m_pRef; +}; + +// Small Helper-function +static void GetValidNPCsOfList(Map* pMap, GuidList& lGUIDs, std::list& lNPCs) +{ + lNPCs.clear(); + for (GuidList::const_iterator itr = lGUIDs.begin(); itr != lGUIDs.end(); ++itr) + { + if (Creature* pMob = pMap->GetCreature(*itr)) + lNPCs.push_back(pMob); } +} + +void instance_halls_of_stone::SortFaces() +{ + std::list lPossibleEyes; + GameObject* pFace = NULL; - void OnObjectCreate(GameObject* pGo) + // FACE_MARNAK + if (pFace = instance->GetGameObject(m_aFaces[FACE_MARNAK].m_goFaceGuid)) { - switch(pGo->GetEntry()) + // Find Marnak NPCs + GetValidNPCsOfList(instance, m_lMarnakGUIDs, lPossibleEyes); + if (lPossibleEyes.size() > 1) { - case GO_DOOR_SJONNIR: - m_uiSjonnirDoorGUID = pGo->GetGUID(); - break; - case GO_DOOR_TRIBUNAL: - m_uiTribunalDoorGUID = pGo->GetGUID(); - break; - case GO_TRIBUNAL_CHEST: - case GO_TRIBUNAL_CHEST_H: - m_uiTribunalChestGUID = pGo->GetGUID(); - break; - case GO_TRIBUNAL_HEAD_RIGHT: - m_uiTribunalHeadRightGUID = pGo->GetGUID(); - break; - case GO_TRIBUNAL_HEAD_CENTER: - m_uiTribunalHeadCenterGUID = pGo->GetGUID(); - break; - case GO_TRIBUNAL_HEAD_LEFT: - m_uiTribunalHeadLeftGUID = pGo->GetGUID(); - break; - case GO_TRIBUNAL_CONSOLE: - m_uiTribunalConsoleGUID = pGo->GetGUID(); - break; - case GO_TRIBUNAL_FLOOR: - m_uiTribunalFloorGUID = pGo->GetGUID(); - break; - case GO_SJONNIR_CONSOLE: - m_uiSjonnirConsoleGUID = pGo->GetGUID(); - break; + lPossibleEyes.sort(SortHelper(pFace)); + std::list::const_iterator itr = lPossibleEyes.begin(); + m_aFaces[FACE_MARNAK].m_leftEyeGuid = (*itr)->GetObjectGuid(); + ++itr; + m_aFaces[FACE_MARNAK].m_speakerGuid = (*itr)->GetObjectGuid(); + } + // Find Worldtrigger NPC + GetValidNPCsOfList(instance, m_lWorldtriggerGUIDs, lPossibleEyes); + if (!lPossibleEyes.empty()) + { + lPossibleEyes.sort(SortHelper(pFace)); + m_aFaces[FACE_MARNAK].m_rightEyeGuid = (*lPossibleEyes.begin())->GetObjectGuid(); } } - void SetData(uint32 uiType, uint32 uiData) + // FACE_ABEDNEUM + if (pFace = instance->GetGameObject(m_aFaces[FACE_ABEDNEUM].m_goFaceGuid)) { - switch(uiType) + // Find Abedneum NPCs + GetValidNPCsOfList(instance, m_lAbedneumGUIDs, lPossibleEyes); + if (lPossibleEyes.size() > 1) + { + lPossibleEyes.sort(SortHelper(pFace)); + std::list::const_iterator itr = lPossibleEyes.begin(); + m_aFaces[FACE_ABEDNEUM].m_leftEyeGuid = (*itr)->GetObjectGuid(); + ++itr; + m_aFaces[FACE_ABEDNEUM].m_speakerGuid = (*itr)->GetObjectGuid(); + } + // Find Worldtrigger NPC + GetValidNPCsOfList(instance, m_lWorldtriggerGUIDs, lPossibleEyes); + if (!lPossibleEyes.empty()) { - case TYPE_TRIBUNAL: - m_auiEncounter[0] = uiData; - if (uiData == DONE) - DoRespawnGameObject(m_uiTribunalChestGUID); - break; - case TYPE_MAIDEN: - m_auiEncounter[1] = uiData; - break; - case TYPE_KRYSTALLUS: - m_auiEncounter[2] = uiData; - break; - case TYPE_SJONNIR: - m_auiEncounter[3] = uiData; - break; + lPossibleEyes.sort(SortHelper(pFace)); + m_aFaces[FACE_ABEDNEUM].m_rightEyeGuid = (*lPossibleEyes.begin())->GetObjectGuid(); } } - uint32 GetData(uint32 uiType) + // FACE_KADDRAK + if (pFace = instance->GetGameObject(m_aFaces[FACE_KADDRAK].m_goFaceGuid)) { - switch(uiType) + // Find Marnak NPCs + GetValidNPCsOfList(instance, m_lKaddrakGUIDs, lPossibleEyes); + if (lPossibleEyes.size() > 1) + { + lPossibleEyes.sort(SortHelper(pFace)); + std::list::const_iterator itr = lPossibleEyes.begin(); + m_aFaces[FACE_KADDRAK].m_leftEyeGuid = (*itr)->GetObjectGuid(); + ++itr; + m_aFaces[FACE_KADDRAK].m_speakerGuid = (*itr)->GetObjectGuid(); + } + // Find Tribunal NPC + GetValidNPCsOfList(instance, m_lTribunalGUIDs, lPossibleEyes); + if (!lPossibleEyes.empty()) { - case TYPE_TRIBUNAL: - return m_auiEncounter[0]; - case TYPE_MAIDEN: - return m_auiEncounter[1]; - case TYPE_KRYSTALLUS: - return m_auiEncounter[2]; - case TYPE_SJONNIR: - return m_auiEncounter[3]; + lPossibleEyes.sort(SortHelper(pFace)); + m_aFaces[FACE_KADDRAK].m_rightEyeGuid = (*lPossibleEyes.begin())->GetObjectGuid(); } - return 0; } - uint64 GetData64(uint32 uiData) + // Clear GUIDs + m_lKaddrakGUIDs.clear(); + m_lAbedneumGUIDs.clear(); + m_lMarnakGUIDs.clear(); + m_lTribunalGUIDs.clear(); + m_lWorldtriggerGUIDs.clear(); +} + +void instance_halls_of_stone::ActivateFace(uint8 uiFace, bool bAfterEvent) +{ + if (uiFace >= MAX_FACES) + return; + + if (bAfterEvent) + DoUseDoorOrButton(m_aFaces[uiFace].m_goFaceGuid); + else { - switch(uiData) + // TODO: How to get them red? + DoUseDoorOrButton(m_aFaces[uiFace].m_goFaceGuid); + m_aFaces[uiFace].m_bIsActive = true; + } +} + +void instance_halls_of_stone::DoFaceSpeak(uint8 uiFace, int32 iTextId) +{ + if (uiFace >= MAX_FACES) + return; + + if (Creature* pSpeaker = instance->GetCreature(m_aFaces[uiFace].m_speakerGuid)) + 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) + { + for (uint8 i = 0; i < MAX_FACES; ++i) { - case NPC_BRANN: - return m_uiBrannGUID; - case NPC_KADDRAK: - return m_uiKaddrakGUID; - case NPC_ABEDNEUM: - return m_uiAbedneumGUID; - case NPC_MARNAK: - return m_uiMarnakGUID; - case GO_DOOR_SJONNIR: - return m_uiSjonnirDoorGUID; - case GO_DOOR_TRIBUNAL: - return m_uiTribunalDoorGUID; - case GO_TRIBUNAL_CHEST: - case GO_TRIBUNAL_CHEST_H: - return m_uiTribunalChestGUID; - case GO_TRIBUNAL_HEAD_RIGHT: - return m_uiTribunalHeadRightGUID; - case GO_TRIBUNAL_HEAD_CENTER: - return m_uiTribunalHeadCenterGUID; - case GO_TRIBUNAL_HEAD_LEFT: - return m_uiTribunalHeadLeftGUID; - case GO_TRIBUNAL_CONSOLE: - return m_uiTribunalConsoleGUID; - case GO_TRIBUNAL_FLOOR: - return m_uiTribunalFloorGUID; - case GO_SJONNIR_CONSOLE: - return m_uiSjonnirConsoleGUID; + if (!m_aFaces[i].m_bIsActive) + continue; + + if (m_aFaces[i].m_uiTimer < uiDiff) + ProcessFace(i); + else + m_aFaces[i].m_uiTimer -= uiDiff; } - return 0; } -}; +} + +void instance_halls_of_stone::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; +} + +void instance_halls_of_stone::ProcessFace(uint8 uiFace) +{ + // Cast dmg spell from face eyes, and reset timer for face + switch (uiFace) + { + case FACE_KADDRAK: + if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_leftEyeGuid)) + 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 = urand(1000, 2000); + break; + case FACE_MARNAK: + 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)) + // pEye->CastSpell(pEye, SPELL_SUMMON_DARK_MATTER_TARGET, true); + 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)) + // pEye->CastSpell(pEye, SPELL_SUMMON_SEARING_GAZE_TARGET, true); + m_aFaces[uiFace].m_uiTimer = urand(15000, 20000); + break; + default: + return; + } +} InstanceData* GetInstanceData_instance_halls_of_stone(Map* pMap) { @@ -199,9 +417,10 @@ InstanceData* GetInstanceData_instance_halls_of_stone(Map* pMap) void AddSC_instance_halls_of_stone() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_halls_of_stone"; - newscript->GetInstanceData = &GetInstanceData_instance_halls_of_stone; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_halls_of_stone"; + pNewScript->GetInstanceData = &GetInstanceData_instance_halls_of_stone; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp b/scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp index 9185c8152c..abe413c3b2 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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: assembly_of_iron -SD%Complete: 0% -SDComment: +SD%Complete: 90% +SDComment: Lightning Tendrils target following could use some love from the core side SDCategory: Ulduar EndScriptData */ @@ -51,9 +51,728 @@ enum SAY_STEEL_SLAY_2 = -1603076, SAY_STEEL_OVERWHELM = -1603077, SAY_STEEL_BERSERK = -1603078, + + // Common spells + SPELL_BERSERK = 62535, // triggers 47008 after 15 min + 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 + + // Steelbreaker + SPELL_HIGH_VOLTAGE = 61890, // phase 1 spells + SPELL_HIGH_VOLTAGE_H = 63498, // probably related to 61892 - couldn't find any info regarding this one + SPELL_FUSION_PUNCH = 61903, + SPELL_FUSION_PUNCH_H = 63493, + SPELL_STATIC_DISRUPTION = 61911, // phase 2 spells + SPELL_STATIC_DISRUPTION_H = 63495, // should be triggered by 64641 + SPELL_OVERWHELMING_POWER = 61888, // phase 3 spells + SPELL_OVERWHELMING_POWER_H = 64637, + SPELL_ELECTRICAL_CHARGE = 61900, // triggers 61901 when target dies + + // Runemaster Molgeim + SPELL_SHIELD = 62274, // phase 1 spells + SPELL_SHIELD_H = 63489, + SPELL_RUNE_OF_POWER = 61973, + SPELL_RUNE_OF_DEATH = 62269, // phase 2 spells + SPELL_RUNE_OF_DEATH_H = 63490, + SPELL_RUNE_OF_SUMMONING = 62273, // phase 3 spells + + // Stormcaller Brundir + SPELL_CHAIN_LIGHTNING = 61879, // phase 1 spells + SPELL_CHAIN_LIGHTNING_H = 63479, + SPELL_OVERLOAD = 61869, + SPELL_LIGHTNING_WHIRL = 61915, // phase 2 spells + SPELL_LIGHTNING_WHIRL_H = 63483, + SPELL_LIGHTNING_WHIRL_DAMAGE = 61916, // used to check achiev criterias + SPELL_LIGHTNING_WHIRL_DAMAGE_H = 63482, + SPELL_STORMSHIELD = 64187, // phase 3 spells + SPELL_LIGHTNING_TENDRILS = 61887, + SPELL_LIGHTNING_TENDRILS_H = 63486, + SPELL_TENDRILS_VISUAL = 61883, + + // Summoned spells + SPELL_OVERLOAD_AURA = 61877, + SPELL_RUNE_OF_POWER_AURA = 61974, + SPELL_RUNE_OF_SUMMONING_AURA = 62019, // triggers 62020 which summons 32958 + SPELL_LIGHTNING_ELEMENTAL_PASSIVE = 62052, + SPELL_LIGHTNING_ELEMENTAL_PASSIVE_H = 63492, + + // summoned npcs + NPC_OVERLOAD_VISUAL = 32866, + NPC_RUNE_OF_POWER = 33705, + NPC_RUNE_OF_SUMMONING = 33051, + NPC_LIGHTNING_ELEMENTAL = 32958, + + PHASE_NO_CHARGE = 0, + PHASE_CHARGE_ONE = 1, + PHASE_CHARGE_TWO = 2, + + POINT_ID_LIFT_OFF = 1, + POINT_ID_LAND = 2, +}; + +struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI +{ + boss_brundirAI(Creature* pCreature) : ScriptedAI(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_uiVisualTimer; + uint32 m_uiChainLightningTimer; + uint32 m_uiOverloadTimer; + uint32 m_uiWhirlTimer; + uint32 m_uiTendrilsTimer; + uint32 m_uiTendrilsTargetTimer; + uint32 m_uiTendrilsEndTimer; + uint32 m_uiTendrilsFollowTimer; + + ObjectGuid m_followTargetGuid; + + void Reset() override + { + m_uiPhase = PHASE_NO_CHARGE; + m_uiVisualTimer = 5000; + m_uiChainLightningTimer = 0; + m_uiOverloadTimer = 35000; + m_uiWhirlTimer = 10000; + m_uiTendrilsTimer = 60000; + m_uiTendrilsEndTimer = 0; + m_uiTendrilsTargetTimer = 0; + m_uiTendrilsFollowTimer = 500; + + m_creature->SetLevitate(false); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + // If we are not on the last phase then cast Supercharge and set as unlootable + if (m_uiPhase != PHASE_CHARGE_TWO) + { + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + DoCastSpellIfCan(m_creature, SPELL_SUPERCHARGE, CAST_TRIGGERED); + 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*/) override + { + DoScriptText(SAY_BRUNDIR_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS); + + m_creature->InterruptNonMeleeSpells(false); + DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_BRUNDIR_SLAY_1 : SAY_BRUNDIR_SLAY_2, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_OVERLOAD_VISUAL) + { + pSummoned->CastSpell(pSummoned, SPELL_OVERLOAD_AURA, true); + // Visual npc- shouldn't move and should despawn in 6 sec + pSummoned->GetMotionMaster()->MoveIdle(); + pSummoned->ForcedDespawn(6000); + } + } + + 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) + { + // Not sure if there is a spell for this, so we are doing it here + m_creature->SetHealth(m_creature->GetMaxHealth()); + ++m_uiPhase; + } + + if (m_uiPhase == PHASE_CHARGE_TWO) + { + // Cast stormshield in the last phase + DoCastSpellIfCan(m_creature, SPELL_STORMSHIELD, CAST_TRIGGERED); + + // set the instace data to special in order to mark the last phase - this is used to check the achiev criteria + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, SPECIAL); + } + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + if (pTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (!m_pInstance) + return; + + // Check achiev criterias + switch (pSpell->Id) + { + case SPELL_CHAIN_LIGHTNING: + case SPELL_CHAIN_LIGHTNING_H: + case SPELL_LIGHTNING_WHIRL_DAMAGE: + case SPELL_LIGHTNING_WHIRL_DAMAGE_H: + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_STUNNED, false); + break; + } + } + + 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 + 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 + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER | SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + DoMoveToTarget(pTarget); + m_followTargetGuid = pTarget->GetObjectGuid(); + } + m_uiTendrilsTargetTimer = 5000; + m_uiTendrilsFollowTimer = 500; + break; + // After reached the land remove all the auras and resume basic combat + case POINT_ID_LAND: + m_creature->SetLevitate(false); + SetCombatMovement(true); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + m_creature->RemoveAurasDueToSpell(SPELL_TENDRILS_VISUAL); + m_creature->RemoveAurasDueToSpell(m_bIsRegularMode ? SPELL_LIGHTNING_TENDRILS : SPELL_LIGHTNING_TENDRILS_H); + break; + } + } + + // Wrapper for target movement + void DoMoveToTarget(Unit* pTarget) + { + if (pTarget) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, pTarget->GetPositionX(), pTarget->GetPositionY(), m_creature->GetPositionZ()); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Pre fight visual spell + if (m_uiVisualTimer) + { + if (m_uiVisualTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_CHANNEL_PREFIGHT) == CAST_OK) + m_uiVisualTimer = 0; + } + else + m_uiVisualTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_CHARGE_TWO: + + if (m_uiTendrilsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_TENDRILS : SPELL_LIGHTNING_TENDRILS_H) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_TENDRILS_VISUAL, CAST_TRIGGERED); + DoScriptText(SAY_BRUNDIR_FLY, m_creature); + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_LIFT_OFF, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 15.0f); + m_uiTendrilsTimer = 90000; + m_uiTendrilsEndTimer = 25000; + } + } + else + m_uiTendrilsTimer -= uiDiff; + + if (m_uiTendrilsEndTimer) + { + if (m_uiTendrilsEndTimer <= uiDiff) + { + // Get proper Z position and land + float fZ = m_creature->GetTerrain()->GetWaterOrGroundLevel(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_creature->GetPositionX(), m_creature->GetPositionY(), fZ); + m_uiOverloadTimer = 40000; + m_uiWhirlTimer = 15000; + m_uiChainLightningTimer = 3000; + m_uiTendrilsEndTimer = 0; + m_uiTendrilsTargetTimer = 0; + } + else + m_uiTendrilsEndTimer -= uiDiff; + + // Change follow target every 5 seconds + if (m_uiTendrilsTargetTimer) + { + if (m_uiTendrilsTargetTimer <= uiDiff) + { + // TODO: the boss should follow without changing his Z position - missing core feature + // Current implementation with move point is wrong + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER | SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + DoMoveToTarget(pTarget); + m_followTargetGuid = pTarget->GetObjectGuid(); + } + m_uiTendrilsTargetTimer = 5000; + m_uiTendrilsFollowTimer = 500; + } + else + m_uiTendrilsTargetTimer -= uiDiff; + + // Workaround to follow the target + if (m_uiTendrilsFollowTimer < uiDiff) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_followTargetGuid)) + DoMoveToTarget(pTarget); + m_uiTendrilsFollowTimer = 500; + } + else + m_uiTendrilsFollowTimer -= uiDiff; + } + + // no other spells during tendrils + return; + } + + // no break here; he uses the other spells as well + case PHASE_CHARGE_ONE: + + if (m_uiWhirlTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_WHIRL : SPELL_LIGHTNING_WHIRL_H) == CAST_OK) + { + DoScriptText(SAY_BRUNDIR_WHIRL, m_creature); + m_uiWhirlTimer = 30000; + } + } + else + m_uiWhirlTimer -= uiDiff; + + // no break here; he uses the other spells as well + case PHASE_NO_CHARGE: + + 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 = 2000; + } + } + else + m_uiChainLightningTimer -= uiDiff; + + if (m_uiOverloadTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_OVERLOAD) == CAST_OK) + m_uiOverloadTimer = 80000; + } + else + m_uiOverloadTimer -= uiDiff; + + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_brundir(Creature* pCreature) +{ + return new boss_brundirAI(pCreature); +} + +struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI +{ + boss_molgeimAI(Creature* pCreature) : ScriptedAI(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_uiVisualTimer; + uint32 m_uiShieldTimer; + uint32 m_uiRunePowerTimer; + uint32 m_uiRuneDeathTimer; + uint32 m_uiRuneSummonTimer; + + void Reset() override + { + m_uiPhase = PHASE_NO_CHARGE; + m_uiVisualTimer = 5000; + m_uiShieldTimer = 25000; + m_uiRunePowerTimer = 15000; + m_uiRuneSummonTimer = 10000; + m_uiRuneDeathTimer = 30000; + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + // If we are not on the last phase then cast Supercharge and set as unlootable + if (m_uiPhase != PHASE_CHARGE_TWO) + { + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + DoCastSpellIfCan(m_creature, SPELL_SUPERCHARGE, CAST_TRIGGERED); + 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*/) override + { + DoScriptText(SAY_MOLGEIM_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS); + + m_creature->InterruptNonMeleeSpells(false); + DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_MOLGEIM_SLAY_1 : SAY_MOLGEIM_SLAY_2, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, FAIL); + } + + 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()); + else if (pSummoned->GetEntry() == NPC_RUNE_OF_POWER) + pSummoned->CastSpell(pSummoned, SPELL_RUNE_OF_POWER_AURA, true); + else if (pSummoned->GetEntry() == NPC_LIGHTNING_ELEMENTAL) + { + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_LIGHTNING_ELEMENTAL_PASSIVE : SPELL_LIGHTNING_ELEMENTAL_PASSIVE_H, true); + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + 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) + { + // Not sure if there is a spell for this, so we are doing it here + m_creature->SetHealth(m_creature->GetMaxHealth()); + ++m_uiPhase; + } + + if (m_uiPhase == PHASE_CHARGE_TWO) + { + // set the instace data to special in order to mark the last phase - this is used to check the achiev criteria + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, SPECIAL); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Pre fight visual spell + if (m_uiVisualTimer) + { + if (m_uiVisualTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RUNE_OF_POWER_PREFIGHT) == CAST_OK) + m_uiVisualTimer = 0; + } + else + m_uiVisualTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_CHARGE_TWO: + + if (m_uiRuneSummonTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RUNE_OF_SUMMONING) == CAST_OK) + { + DoScriptText(SAY_MOLGEIM_SURGE, m_creature); + m_uiRuneSummonTimer = 30000; + } + } + else + m_uiRuneSummonTimer -= uiDiff; + + // no break here; he uses the other spells as well + case PHASE_CHARGE_ONE: + + if (m_uiRuneDeathTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_RUNE_OF_DEATH : SPELL_RUNE_OF_DEATH_H) == CAST_OK) + { + DoScriptText(SAY_MOLGEIM_DEATH_RUNE, m_creature); + m_uiRuneDeathTimer = 30000; + } + } + } + else + m_uiRuneDeathTimer -= uiDiff; + + // no break here; he uses the other spells as well + case PHASE_NO_CHARGE: + + if (m_uiShieldTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHIELD : SPELL_SHIELD_H) == CAST_OK) + m_uiShieldTimer = 40000; + } + else + m_uiShieldTimer -= uiDiff; + + if (m_uiRunePowerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RUNE_OF_POWER) == CAST_OK) + m_uiRunePowerTimer = 45000; + } + else + m_uiRunePowerTimer -= uiDiff; + + break; + } + + DoMeleeAttackIfReady(); + } }; +CreatureAI* GetAI_boss_molgeim(Creature* pCreature) +{ + return new boss_molgeimAI(pCreature); +} + +struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI +{ + boss_steelbreakerAI(Creature* pCreature) : ScriptedAI(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_uiFusionPunchTimer; + uint32 m_uiDisruptionTimer; + uint32 m_uiPowerTimer; + + void Reset() override + { + m_uiPhase = PHASE_NO_CHARGE; + m_uiFusionPunchTimer = 15000; + m_uiDisruptionTimer = 15000; + m_uiPowerTimer = 10000; + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + // If we are not on the last phase then cast Supercharge and set as unlootable + if (m_uiPhase != PHASE_CHARGE_TWO) + { + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + DoCastSpellIfCan(m_creature, SPELL_SUPERCHARGE, CAST_TRIGGERED); + 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*/) override + { + DoScriptText(SAY_STEEL_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS); + + DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HIGH_VOLTAGE : SPELL_HIGH_VOLTAGE_H, CAST_TRIGGERED); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_STEEL_SLAY_1 : SAY_STEEL_SLAY_2, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, FAIL); + } + + 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) + { + // Not sure if there is a spell for this, so we are doing it here + m_creature->SetHealth(m_creature->GetMaxHealth()); + ++m_uiPhase; + } + + if (m_uiPhase == PHASE_CHARGE_TWO) + { + // Cast electrical charge aura on all players - this will proc when player dies + DoCastSpellIfCan(m_creature, SPELL_ELECTRICAL_CHARGE, CAST_TRIGGERED); + + // set the instace data to special in order to mark the last phase - this is used to check the achiev criteria + if (m_pInstance) + m_pInstance->SetData(TYPE_ASSEMBLY, SPECIAL); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_CHARGE_TWO: + + if (m_uiPowerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_OVERWHELMING_POWER : SPELL_OVERWHELMING_POWER_H) == CAST_OK) + { + DoScriptText(SAY_STEEL_OVERWHELM, m_creature); + m_uiPowerTimer = m_bIsRegularMode ? 60000 : 35000; + } + } + else + m_uiPowerTimer -= uiDiff; + + // no break here; he uses the other spells as well + case PHASE_CHARGE_ONE: + + if (m_uiDisruptionTimer < uiDiff) + { + // NOTE: This spell is not cast right: Normally it should be triggered by 64641 in core + // Because of the poor target selection in core we'll implement it here with select flag targeting + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_NOT_IN_MELEE_RANGE); + + if (!pTarget) + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_STATIC_DISRUPTION : SPELL_STATIC_DISRUPTION_H) == CAST_OK) + m_uiDisruptionTimer = urand(10000, 15000); + } + else + m_uiDisruptionTimer -= uiDiff; + + // no break here; he uses the other spells as well + case PHASE_NO_CHARGE: + + if (m_uiFusionPunchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FUSION_PUNCH : SPELL_FUSION_PUNCH_H) == CAST_OK) + m_uiFusionPunchTimer = 15000; + } + else + m_uiFusionPunchTimer -= uiDiff; + + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_steelbreaker(Creature* pCreature) +{ + return new boss_steelbreakerAI(pCreature); +} + void AddSC_boss_assembly_of_iron() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_brundir"; + pNewScript->GetAI = GetAI_boss_brundir; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_molgeim"; + pNewScript->GetAI = GetAI_boss_molgeim; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_steelbreaker"; + pNewScript->GetAI = GetAI_boss_steelbreaker; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_algalon.cpp b/scripts/northrend/ulduar/ulduar/boss_algalon.cpp index fa2c76e817..cd7747ac4e 100644 --- a/scripts/northrend/ulduar/ulduar/boss_algalon.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_algalon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,763 @@ 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 + SPELL_TELEPORT = 62940, + + // 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, 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, 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 MANGOS_DLL_DECL 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_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 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); + } + else + m_pInstance->SetData(TYPE_ALGALON, FAIL); + + // 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 SAY_ENGAGE: + // summon Living Constellations at this point + DoSpawnConstellations(); + break; + case SPELL_BERSERK: + EnterEvadeMode(); + break; + case SPELL_TELEPORT: + // despawn when time has run out + 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, CAST_TRIGGERED); + 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, 1, 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) + 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 MANGOS_DLL_DECL 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); + } + + 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 b1038e19a5..4e92eae068 100644 --- a/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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_auriaya -SD%Complete: 0% +SD%Complete: 100% SDComment: SDCategory: Ulduar EndScriptData */ @@ -33,9 +33,361 @@ enum SAY_DEATH = -1603083, EMOTE_SCREECH = -1603084, EMOTE_DEFENDER = -1603085, + + // Auriaya + SPELL_BERSERK = 47008, + SPELL_GUARDIAN_SWARM = 64396, // triggers 64397 + SPELL_SENTINEL_BLAST = 64389, // triggers 64392 + SPELL_SENTINEL_BLAST_H = 64678, // triggers 64679 + SPELL_SONIC_SCREECH = 64422, + SPELL_SONIC_SCREECH_H = 64688, + SPELL_TERRIFYING_SCREECH = 64386, + SPELL_ACTIVATE_FERAL_DEFENDER = 64449, // triggers 64447 + SPELL_ACTIVATE_FERAL_DEFENDER_TRIGG = 64448, + + // Feral Defender spells + SPELL_FERAL_ESSENCE = 64455, + SPELL_FERAL_ESSENCE_REMOVAL = 64456, // remove 1 stack of 64455 + SPELL_FERAL_POUNCE = 64478, + SPELL_FERAL_POUNCE_H = 64669, + SPELL_FERAL_RUSH = 64489, // triggers 64496 + SPELL_FERAL_RUSH_H = 64673, // triggers 64674 + SPELL_SEEPING_FERAL_ESSENCE_SUMMON = 64457, + 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_FERAL_DEFENDER_STALKER = 34096, +}; + +/*###### +## boss_auriaya +######*/ + +struct MANGOS_DLL_DECL boss_auriayaAI : public ScriptedAI +{ + boss_auriayaAI(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_uiSwarmTimer; + uint32 m_uiSonicScreechTimer; + uint32 m_uiSentinelBlastTimer; + uint32 m_uiTerrifyingScreechTimer; + uint32 m_uiDefenderTimer; + + void Reset() override + { + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiSwarmTimer = 50000; + m_uiSonicScreechTimer = 58000; + m_uiSentinelBlastTimer = 40000; + m_uiTerrifyingScreechTimer = 38000; + m_uiDefenderTimer = 1 * MINUTE * IN_MILLISECONDS; + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_AURIAYA, DONE); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + } + + 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_AURIAYA, FAIL); + } + + 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) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiTerrifyingScreechTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TERRIFYING_SCREECH) == CAST_OK) + { + DoScriptText(EMOTE_SCREECH, m_creature); + m_uiTerrifyingScreechTimer = 35000; + m_uiSentinelBlastTimer = 2000; + } + } + else + m_uiTerrifyingScreechTimer -= uiDiff; + + if (m_uiSentinelBlastTimer < uiDiff) + { + // Cast Sentinel blast right after terrifying screech + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SENTINEL_BLAST : SPELL_SENTINEL_BLAST_H) == CAST_OK) + m_uiSentinelBlastTimer = 35000; + } + else + m_uiSentinelBlastTimer -= uiDiff; + + if (m_uiDefenderTimer) + { + if (m_uiDefenderTimer <= uiDiff) + { + // Summon the feral defender trigger + if (DoCastSpellIfCan(m_creature, SPELL_ACTIVATE_FERAL_DEFENDER_TRIGG) == CAST_OK) + m_uiDefenderTimer = 0; + } + else + m_uiDefenderTimer -= uiDiff; + } + + if (m_uiSonicScreechTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SONIC_SCREECH : SPELL_SONIC_SCREECH_H) == CAST_OK) + m_uiSonicScreechTimer = 27000; + } + else + m_uiSonicScreechTimer -= uiDiff; + + if (m_uiSwarmTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_GUARDIAN_SWARM) == CAST_OK) + m_uiSwarmTimer = 37000; + } + } + else + m_uiSwarmTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiEnrageTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } }; +CreatureAI* GetAI_boss_auriaya(Creature* pCreature) +{ + return new boss_auriayaAI(pCreature); +} + +/*###### +## boss_feral_defender +######*/ + +struct MANGOS_DLL_DECL 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() override + { + m_uiFeralRushCount = 0; + m_uiReviveDelayTimer = 0; + 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*/) override + { + // Set achiev criteria to true + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_NINE_LIVES, true); + } + + 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 + return; + + if (m_uiReviveDelayTimer) // Already faking + { + uiDamage = 0; + return; + } + + if (uiDamage > m_creature->GetHealth()) + { + uiDamage = 0; + + // 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->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); + + m_uiReviveDelayTimer = 30000; + ++m_uiKilledCount; + } + } + + void JustSummoned(Creature* pSummoned) override + { + // Cast seeping feral essence on the summoned + 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) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiReviveDelayTimer) + { + if (m_uiReviveDelayTimer <= uiDiff) + { + // 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; + + // No Further action while faking + return; + } + + 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_uiAttackDelayTimer -= uiDiff; + + // No Further action while faking + return; + } + + if (m_uiPounceTimer < uiDiff) + { + 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 = urand(13000, 16000); + } + } + else + m_uiPounceTimer -= uiDiff; + + if (m_uiFeralRushTimer < uiDiff) + { + 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; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_feral_defender(Creature* pCreature) +{ + return new boss_feral_defenderAI(pCreature); +} + void AddSC_boss_auriaya() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_auriaya"; + pNewScript->GetAI = GetAI_boss_auriaya; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_feral_defender"; + pNewScript->GetAI = &GetAI_boss_feral_defender; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp b/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp index fcbc44d2b3..53fc9b2a9e 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 0e49ee7431..ce0a7d93e3 100644 --- a/scripts/northrend/ulduar/ulduar/boss_freya.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_freya.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,1004 @@ 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_TELEPORT = 62940, // despawn on event end + 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 MANGOS_DLL_DECL 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 (SpellAuraHolderPtr 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 42ada85915..f9adc28756 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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_general_vezax -SD%Complete: 0% -SDComment: +SD%Complete: 90% +SDComment: Some details may need some small adjustments SDCategory: Ulduar EndScriptData */ @@ -37,9 +37,290 @@ enum EMOTE_VAPOR = -1603103, EMOTE_SURGE = -1603104, EMOTE_ANIMUS = -1603105, + + SPELL_AURA_OF_DESPAIR = 62692, + SPELL_SHADOW_CRASH = 62660, + SPELL_MARK_OF_FACELESS = 63276, // triggers 63278 + SPELL_SEARING_FLAMES = 62661, + SPELL_SURGE_OF_DARKNESS = 62662, + SPELL_BERSERK = 26662, + 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_SARONITE_VAPORS = 63323, // cast by vapor on death + SPELL_CORRUPTED_RAGE = 68415, // Unused + SPELL_CORRUPTED_WISDOM = 64646, + + MAX_HARD_MODE_VAPORS = 6, + + NPC_SARONITE_VAPOR = 33488, }; +/*###### +## boss_general_vezax +######*/ + +struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI +{ + boss_general_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + uint32 m_uiEnrageTimer; + uint32 m_uiCrashTimer; + uint32 m_uiMarkTimer; + uint32 m_uiFlamesTimer; + uint32 m_uiSurgeTimer; + uint32 m_uiSaroniteVaporTimer; + uint32 m_uiSaroniteBarrierTimer; + + uint8 m_uiVaporsGathered; + + GuidList m_lVaporsGuids; + + void Reset() override + { + 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_uiVaporsGathered = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_VEZAX, IN_PROGRESS); + m_pInstance->SetData(TYPE_VEZAX_HARD, NOT_STARTED); + } + + DoCastSpellIfCan(m_creature, SPELL_AURA_OF_DESPAIR); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VEZAX, FAIL); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VEZAX, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SARONITE_VAPOR) + { + m_lVaporsGuids.push_back(pSummoned->GetObjectGuid()); + + // if vapors have reached the max number for hard mode then summon animus + if (m_lVaporsGuids.size() == MAX_HARD_MODE_VAPORS) + DoPrepareAnimusIfCan(); + } + else if (pSummoned->GetEntry() == NPC_SARONITE_ANIMUS) + pSummoned->SetInCombatWithZone(); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // decrease the number of vapors when they die + if (pSummoned->GetEntry() == NPC_SARONITE_VAPOR) + { + pSummoned->CastSpell(pSummoned, SPELL_SARONITE_VAPORS, true); + m_lVaporsGuids.remove(pSummoned->GetObjectGuid()); + } + // remove saronite barrier when animus dies + else if (pSummoned->GetEntry() == NPC_SARONITE_ANIMUS) + { + 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) override + { + if (uiMoveType != POINT_MOTION_TYPE || uiPointId != 0 || pSummoned->GetEntry() != NPC_SARONITE_VAPOR) + 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; + } + } + + // 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) + { + // 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()); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSaroniteBarrierTimer) + { + if (m_uiSaroniteBarrierTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SARONITE_BARRIER) == CAST_OK) + m_uiSaroniteBarrierTimer = 0; + } + else + m_uiSaroniteBarrierTimer -= uiDiff; + } + + // summon saronite vapors before the hard mode + if (m_pInstance && m_pInstance->GetData(TYPE_VEZAX_HARD) == NOT_STARTED) + { + if (m_uiSaroniteVaporTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_VAPORS) == CAST_OK) + { + DoScriptText(EMOTE_VAPOR, m_creature); + m_uiSaroniteVaporTimer = 30000; + } + } + else + m_uiSaroniteVaporTimer -= uiDiff; + } + + // Searing flames only while animus is not around + if (m_pInstance && m_pInstance->GetData(TYPE_VEZAX_HARD) != IN_PROGRESS) + { + if (m_uiFlamesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SEARING_FLAMES) == CAST_OK) + m_uiFlamesTimer = urand(9000, 16000); + } + else + m_uiFlamesTimer -= uiDiff; + } + + if (m_uiSurgeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SURGE_OF_DARKNESS) == CAST_OK) + { + DoScriptText(SAY_SURGE, m_creature); + DoScriptText(EMOTE_SURGE, m_creature); + m_uiSurgeTimer = 62000; + } + } + else + m_uiSurgeTimer -= uiDiff; + + if (m_uiMarkTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MARK_OF_FACELESS) == CAST_OK) + m_uiMarkTimer = urand(25000, 30000); + } + } + else + m_uiMarkTimer -= uiDiff; + + if (m_uiCrashTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_CRASH) == CAST_OK) + m_uiCrashTimer = 15000; + } + } + else + m_uiCrashTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiEnrageTimer = 30000; + } + } + else + m_uiEnrageTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +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*/) +{ + if (pSource->GetTypeId() == TYPEID_UNIT && ((Creature*)pSource)->GetEntry() == NPC_VEZAX) + { + if (instance_ulduar* pInstance = (instance_ulduar*)((Creature*)pSource)->GetInstanceData()) + { + // 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; + } + } + return false; +} + void AddSC_boss_general_vezax() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_general_vezax"; + pNewScript->GetAI = &GetAI_boss_general_vezax; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "event_spell_saronite_barrier"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_saronite_barrier; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_hodir.cpp b/scripts/northrend/ulduar/ulduar/boss_hodir.cpp index 49c4ca168c..bb1ea4733e 100644 --- a/scripts/northrend/ulduar/ulduar/boss_hodir.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_hodir.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,426 @@ 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 + SPELL_TELEPORT = 62940, // despawn on event end + + // 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 MANGOS_DLL_DECL 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 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->setFaction(FACTION_ID_FRIENDLY); + 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_creature->CastSpell(m_creature, SPELL_HODIR_CREDIT, true); + 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 MANGOS_DLL_DECL 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)) + { + 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)) + pHodir->SetInCombatWithZone(); + } + + return true; + } + + return false; +} + +/*###### +## npc_icicle_target +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct MANGOS_DLL_DECL 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 59024c98a4..688355965e 100644 --- a/scripts/northrend/ulduar/ulduar/boss_ignis.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_ignis.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 (SpellAuraHolderPtr 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 MANGOS_DLL_DECL 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 feb6725816..33606e3018 100644 --- a/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 fa7ea5733c..2b8112f513 100644 --- a/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 332e6b54f8..096fbcf9af 100644 --- a/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + } + + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + + 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 27bc538841..cd3f8507fc 100644 --- a/scripts/northrend/ulduar/ulduar/boss_thorim.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_thorim.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,1028 @@ 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 + SPELL_TELEPORT = 62940, + + // 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 MANGOS_DLL_DECL 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->setFaction(FACTION_ID_FRIENDLY); + 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 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 8935bb14c1..d64a75dedc 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 1cf0af23b8..26c0900892 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 MANGOS_DLL_DECL 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; + 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 (SpellAuraHolderPtr 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 44fb693aa4..954aa5b0d1 100644 --- a/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp +++ b/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,112 +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 sSpawnLocation m_aKeepersSpawnLocs[] = +static UlduarKeeperSpawns m_aKeepersSpawnLocs[] = { - {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 + {1945.682f, 33.34201f, 411.4408f, 5.270f, NPC_KEEPER_FREYA, TYPE_FREYA}, + {2028.766f, 17.42014f, 411.4446f, 3.857f, NPC_KEEPER_MIMIRON, TYPE_MIMIRON}, + {1945.761f, -81.52171f, 411.4407f, 1.029f, NPC_KEEPER_HODIR, TYPE_HODIR}, + {2028.822f, -65.73573f, 411.4426f, 2.460f, NPC_KEEPER_THORIM, TYPE_THORIM}, }; -instance_ulduar::instance_ulduar(Map* pMap) : ScriptedInstance(pMap), - // Creatures - m_uiLeviathanGUID(0), - m_uiIgnisGUID(0), - m_uiRazorscaleGUID(0), - m_uiCommanderGUID(0), - m_uiXT002GUID(0), - m_uiBrundirGUID(0), - m_uiMolgeimGUID(0), - m_uiSteelbreakerGUID(0), - m_uiKologarnGUID(0), - m_uiAuriayaGUID(0), - m_uiMimironGUID(0), - m_uiHodirGUID(0), - m_uiThorimGUID(0), - m_uiFreyaGUID(0), - m_uiVezaxGUID(0), - m_uiYoggSaronGUID(0), - m_uiAlgalonGUID(0), - m_uiRightArmGUID(0), - m_uiLeftArmGUID(0), - m_uiFeralDefenderGUID(0), - m_uiElderBrightleafGUID(0), - m_uiElderStonebarkGUID(0), - m_uiElderIronbrachGUID(0), - m_uiSaroniteAnimusGUID(0), - m_uiRunicColossusGUID(0), - m_uiRuneGiantGUID(0), - m_uiJormungarGUID(0), - m_uiLeviathanMkGUID(0), - m_uiSaraGUID(0), - m_uiYoggBrainGUID(0), - - // Chests - m_uiKologarnLootGUID(0), - m_uiHodirLootGUID(0), - m_uiHodirRareLootGUID(0), - m_uiThorimLootGUID(0), - m_uiThorimRareLootGUID(0), - m_uiMimironLootGUID(0), - m_uiMimironHardLootGUID(0), - m_uiAlagonLootGUID(0), - - // Doors - // The siege - m_uiShieldWallGUID(0), - m_uiLeviathanGateGUID(0), - m_uiXT002GateGUID(0), - m_uiBrokenHarpoonGUID(0), - // Archivum - m_uiIronCouncilDoorGUID(0), - m_uiArchivumDoorGUID(0), - m_uiArchivumConsoleGUID(0), - m_uiUniverseFloorArchivumGUID(0), - // Celestial planetarium - m_uiCelestialDoorGUID(0), - m_uiCelestialConsoleGUID(0), - m_uiUniverseFloorCelestialGUID(0), - m_uiAzerothGlobeGUID(0), - // Kologarn - m_uiShatteredHallsDoorGUID(0), - m_uiKologarnBridgeGUID(0), - // Hodir - m_uiHodirEnterDoorGUID(0), - m_uiHodirWallGUID(0), - m_uiHodirExitDoorGUID(0), - // Mimiron - m_uiMimironButtonGUID(0), - m_uiMimironDoor1GUID(0), - m_uiMimironDoor2GUID(0), - m_uiMimironDoor3GUID(0), - m_uiMimironElevatorGUID(0), - // Thorim - m_uiArenaEnterDoorGUID(0), - m_uiArenaExitDoorGUID(0), - m_uiHallwayDoorGUID(0), - m_uiThorimEnterDoorGUID(0), - m_uiThorimLeverGUID(0), - // Prison - m_uiAncientGateGUID(0), - m_uiVezaxGateGUID(0), - m_uiYoggGateGUID(0), - m_uiBrainDoor1GUID(0), - m_uiBrainDoor2GUID(0), - m_uiBrainDoor3GUID(0) +static UlduarKeeperSpawns m_aKeeperHelperLocs[] = +{ + {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), 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(); } @@ -131,13 +88,75 @@ 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_auiUlduarTeleporters, 0, sizeof(m_auiUlduarTeleporters)); - memset(&m_auiMimironTelGUID, 0, sizeof(m_auiMimironTelGUID)); + 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); + } + + 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; @@ -150,627 +169,862 @@ void instance_ulduar::OnCreatureCreate(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_LEVIATHAN: - m_uiLeviathanGUID = pCreature->GetGUID(); - break; - case NPC_IGNIS: - m_uiIgnisGUID = pCreature->GetGUID(); - break; + case NPC_EXPLORER_DELLORAH: + case NPC_BRANN_BRONZEBEARD: + case NPC_ORBITAL_SUPPORT: case NPC_RAZORSCALE: - m_uiRazorscaleGUID = pCreature->GetGUID(); - break; - case NPC_COMMANDER: - m_uiCommanderGUID = pCreature->GetGUID(); - break; + case NPC_EXPEDITION_COMMANDER: case NPC_XT002: - m_uiXT002GUID = pCreature->GetGUID(); - break; + case NPC_HEART_DECONSTRUCTOR: + case NPC_STEELBREAKER: - m_uiSteelbreakerGUID = pCreature->GetGUID(); - break; case NPC_MOLGEIM: - m_uiMolgeimGUID = pCreature->GetGUID(); - break; case NPC_BRUNDIR: - m_uiBrundirGUID = pCreature->GetGUID(); - break; case NPC_KOLOGARN: - m_uiKologarnGUID = pCreature->GetGUID(); - break; case NPC_RIGHT_ARM: - m_uiRightArmGUID = pCreature->GetGUID(); - break; case NPC_LEFT_ARM: - m_uiLeftArmGUID = pCreature->GetGUID(); - break; case NPC_AURIAYA: - m_uiAuriayaGUID = pCreature->GetGUID(); - break; case NPC_FERAL_DEFENDER: - m_uiFeralDefenderGUID = pCreature->GetGUID(); - break; - case NPC_MIMIRON: - m_uiMimironGUID = pCreature->GetGUID(); - if(m_auiEncounter[7] == DONE) - SpawnFriendlyKeeper(NPC_MIMIRON_IMAGE); - break; + case NPC_BRANN_ARCHIVUM: + case NPC_BRANN_ALGALON: + case NPC_LEVIATHAN_MK: - m_uiLeviathanMkGUID = pCreature->GetGUID(); - break; - case NPC_HODIR: - m_uiHodirGUID = pCreature->GetGUID(); - if(m_auiEncounter[8] == DONE) - SpawnFriendlyKeeper(NPC_HODIR_IMAGE); - break; - case NPC_THORIM: - m_uiThorimGUID = pCreature->GetGUID(); - if(m_auiEncounter[9] == DONE) - SpawnFriendlyKeeper(NPC_THORIM_IMAGE); - break; + case NPC_LEVIATHAN_MK_TURRET: + case NPC_COMPUTER: + case NPC_VX001: + case NPC_AERIAL_UNIT: + case NPC_WORLD_TRIGGER_FLAMES: case NPC_RUNIC_COLOSSUS: - m_uiRunicColossusGUID = pCreature->GetGUID(); - break; case NPC_RUNE_GIANT: - m_uiRuneGiantGUID = pCreature->GetGUID(); - break; + case NPC_SIF: case NPC_JORMUNGAR_BEHEMOTH: - m_uiJormungarGUID = pCreature->GetGUID(); - break; - case NPC_FREYA: - m_uiFreyaGUID = pCreature->GetGUID(); - if(m_auiEncounter[10] == DONE) - SpawnFriendlyKeeper(NPC_FREYA_IMAGE); - break; + case NPC_THORIM_COMBAT_TRIGGER: case NPC_ELDER_BRIGHTLEAF: - m_uiElderBrightleafGUID = pCreature->GetGUID(); - break; case NPC_ELDER_IRONBRACH: - m_uiElderIronbrachGUID = pCreature->GetGUID(); - break; case NPC_ELDER_STONEBARK: - m_uiElderStonebarkGUID = pCreature->GetGUID(); - break; case NPC_VEZAX: - m_uiVezaxGUID = pCreature->GetGUID(); - break; case NPC_SARONITE_ANIMUS: - m_uiSaroniteAnimusGUID = pCreature->GetGUID(); - break; case NPC_YOGGSARON: - m_uiYoggSaronGUID = pCreature->GetGUID(); - break; case NPC_SARA: - m_uiSaraGUID = pCreature->GetGUID(); - break; case NPC_YOGG_BRAIN: - m_uiYoggBrainGUID = pCreature->GetGUID(); - break; + case NPC_VOICE_OF_YOGG: case NPC_ALGALON: - m_uiAlgalonGUID = pCreature->GetGUID(); + + case NPC_MIMIRON: + case NPC_HODIR: + case NPC_THORIM: + case NPC_FREYA: + 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; + + default: + return; + } + 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: - m_uiShieldWallGUID = pGo->GetGUID(); + 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: - m_uiLeviathanGateGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) + if (m_auiEncounter[TYPE_LEVIATHAN] != NOT_STARTED) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_XT002_GATE: pGo->SetGoState(GO_STATE_READY); - if (m_auiEncounter[3] == DONE) + if (m_auiEncounter[TYPE_XT002] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); - if (m_auiEncounter[1] == DONE && m_auiEncounter[2] == DONE) + if (m_auiEncounter[TYPE_LEVIATHAN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); - m_uiXT002GateGUID = pGo->GetGUID(); break; - case GO_BROKEN_HARPOON: - m_uiBrokenHarpoonGUID = pGo->GetGUID(); - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); + 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: - m_uiIronCouncilDoorGUID = pGo->GetGUID(); break; case GO_ARCHIVUM_DOOR: - m_uiArchivumDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[4]) + if (m_auiEncounter[TYPE_ASSEMBLY]) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_ARCHIVUM_CONSOLE: - m_uiArchivumConsoleGUID = pGo->GetGUID(); - break; - case GO_UNIVERSE_FLOOR_ARCHIVUM: - m_uiUniverseFloorArchivumGUID = pGo->GetGUID(); - break; - // Celestial Planetarium + // Celestial Planetarium case GO_CELESTIAL_ACCES: - m_uiCelestialConsoleGUID = pGo->GetGUID(); + 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: - m_uiCelestialDoorGUID = pGo->GetGUID(); - break; - case GO_UNIVERSE_FLOOR_CELESTIAL: - m_uiUniverseFloorCelestialGUID = pGo->GetGUID(); + 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: - m_uiAzerothGlobeGUID = pGo->GetGUID(); break; - // Shattered Hallway + // Shattered Hallway case GO_KOLOGARN_BRIDGE: - m_uiKologarnBridgeGUID = pGo->GetGUID(); - pGo->SetGoState(GO_STATE_ACTIVE); - if (m_auiEncounter[5] == DONE) + if (m_auiEncounter[TYPE_KOLOGARN] == DONE) pGo->SetGoState(GO_STATE_READY); break; - case GO_SHATTERED_DOOR: - m_uiShatteredHallsDoorGUID = pGo->GetGUID(); - break; - // ----------------- The Keepers ----------------- - // Hodir + // ----------------- The Keepers ----------------- + // Hodir case GO_HODIR_EXIT: - m_uiHodirExitDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[8]) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_HODIR_ICE_WALL: - m_uiHodirWallGUID = pGo->GetGUID(); - if (m_auiEncounter[8]) + if (m_auiEncounter[TYPE_HODIR] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_HODIR_ENTER: - m_uiHodirEnterDoorGUID = pGo->GetGUID(); break; - // Mimiron + // Mimiron case G0_MIMIRON_BUTTON: - m_uiMimironButtonGUID = pGo->GetGUID(); - if (m_auiEncounter[7] == NOT_STARTED) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; case GO_MIMIRON_DOOR_1: - m_uiMimironDoor1GUID = pGo->GetGUID(); - break; case GO_MIMIRON_DOOR_2: - m_uiMimironDoor2GUID = pGo->GetGUID(); - break; case GO_MIMIRON_DOOR_3: - m_uiMimironDoor3GUID = pGo->GetGUID(); - break; case GO_MIMIRON_ELEVATOR: - m_uiMimironElevatorGUID = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL1: - m_auiMimironTelGUID[0] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL2: - m_auiMimironTelGUID[1] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL3: - m_auiMimironTelGUID[2] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL4: - m_auiMimironTelGUID[3] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL5: - m_auiMimironTelGUID[4] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL6: - m_auiMimironTelGUID[5] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL7: - m_auiMimironTelGUID[6] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL8: - m_auiMimironTelGUID[7] = pGo->GetGUID(); - break; - case GO_MIMIRON_TEL9: - m_auiMimironTelGUID[8] = pGo->GetGUID(); - break; - // Thorim + // Thorim case GO_DARK_IRON_PORTCULIS: - m_uiArenaExitDoorGUID = pGo->GetGUID(); - break; case GO_RUNED_STONE_DOOR: - m_uiHallwayDoorGUID = pGo->GetGUID(); - break; case GO_THORIM_STONE_DOOR: - m_uiThorimEnterDoorGUID = pGo->GetGUID(); - break; case GO_LIGHTNING_FIELD: - m_uiArenaEnterDoorGUID = pGo->GetGUID(); - break; case GO_DOOR_LEVER: - m_uiThorimLeverGUID = pGo->GetGUID(); - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); break; - // Prison + // Prison case GO_ANCIENT_GATE: - m_uiAncientGateGUID = pGo->GetGUID(); - 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: - m_uiVezaxGateGUID = pGo->GetGUID(); pGo->SetGoState(GO_STATE_READY); - if (m_auiEncounter[11]) + if (m_auiEncounter[TYPE_VEZAX]) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_YOGG_GATE: - m_uiYoggGateGUID = pGo->GetGUID(); - break; - case GO_BRAIN_DOOR1: - m_uiBrainDoor1GUID = pGo->GetGUID(); - break; - case GO_BRAIN_DOOR2: - m_uiBrainDoor2GUID = pGo->GetGUID(); - break; - case GO_BRAIN_DOOR3: - m_uiBrainDoor3GUID = pGo->GetGUID(); + case GO_BRAIN_DOOR_CHAMBER: + case GO_BRAIN_DOOR_ICECROWN: + case GO_BRAIN_DOOR_STORMWIND: break; - // ----------------- Chests ----------------- - // Kologarn - case GO_CACHE_OF_LIVING_STONE: - case GO_CACHE_OF_LIVING_STONE_H: - m_uiKologarnLootGUID = pGo->GetGUID(); - break; + // ----------------- Chests ----------------- + // Kologarn + case GO_CACHE_OF_LIVING_STONE_10: + case GO_CACHE_OF_LIVING_STONE_25: - // Hodir - case GO_CACHE_OF_WINTER: - case GO_CACHE_OF_WINTER_H: - m_uiHodirLootGUID = pGo->GetGUID(); - break; - case GO_CACHE_OF_RARE_WINTER: - case GO_CACHE_OF_RARE_WINTER_H: - m_uiHodirRareLootGUID = pGo->GetGUID(); - break; + // 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 - case GO_CACHE_OF_STORMS: - case GO_CACHE_OF_STORMS_H: - m_uiThorimLootGUID = pGo->GetGUID(); - break; - case GO_CACHE_OF_RARE_STORMS: - case GO_CACHE_OF_RARE_STORMS_H: - m_uiThorimRareLootGUID = pGo->GetGUID(); - break; + // 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 - case GO_CACHE_OF_INOV: - case GO_CACHE_OF_INOV_H: - m_uiMimironLootGUID = pGo->GetGUID(); - break; - case GO_CACHE_OF_INOV_HARD: - case GO_CACHE_OF_INOV_HARD_H: - m_uiMimironHardLootGUID = pGo->GetGUID(); - break; + // 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 - case GO_GIFT_OF_OBSERVER: - case GO_GIFT_OF_OBSERVER_H: - m_uiAlagonLootGUID = pGo->GetGUID(); + // Alagon + case GO_GIFT_OF_OBSERVER_10: + case GO_GIFT_OF_OBSERVER_25: break; - } -} -Player* instance_ulduar::GetPlayerInMap() -{ - Map::PlayerList const& players = instance->GetPlayers(); + 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; - if (!players.isEmpty()) - { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* plr = itr->getSource()) - return plr; - } + default: + return; } - return NULL; + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } // Used in order to unlock the door to Vezax 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 = instance->GetGameObject(m_uiAncientGateGUID)) - 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[0] = uiData; - DoUseDoorOrButton(m_uiShieldWallGUID); - if (uiData == DONE) + m_auiEncounter[uiType] = uiData; + 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(m_uiXT002GateGUID); - DoUseDoorOrButton(m_uiLeviathanGateGUID); + DoUseDoorOrButton(GO_XT002_GATE); + DoUseDoorOrButton(GO_LIGHTNING_DOOR); } + else if (uiData == FAIL) + DoCallLeviathanHelp(); break; case TYPE_IGNIS: - m_auiEncounter[1] = uiData; + 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: - m_auiEncounter[2] = uiData; + 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[3] = uiData; - DoUseDoorOrButton(m_uiXT002GateGUID); + 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: - m_auiEncounter[4] = uiData; - DoUseDoorOrButton(m_uiIronCouncilDoorGUID); + // Don't set the same encounter data twice + if (uiData == m_auiEncounter[uiType]) + return; + m_auiEncounter[uiType] = uiData; + // don't continue for encounter = special + if (uiData == SPECIAL) + return; + DoUseDoorOrButton(GO_IRON_ENTRANCE_DOOR); if (uiData == DONE) - DoUseDoorOrButton(m_uiArchivumDoorGUID); + { + 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); + SetSpecialAchievementCriteria(TYPE_ACHIEV_MOLGEIM, true); + SetSpecialAchievementCriteria(TYPE_ACHIEV_STEELBREAKER, true); + SetSpecialAchievementCriteria(TYPE_ACHIEV_STUNNED, true); + } break; case TYPE_KOLOGARN: - m_auiEncounter[5] = uiData; - DoUseDoorOrButton(m_uiShatteredHallsDoorGUID); + m_auiEncounter[uiType] = uiData; if (uiData == DONE) { - DoRespawnGameObject(m_uiKologarnLootGUID, 30*MINUTE); - if(GameObject* pBridge = instance->GetGameObject(m_uiKologarnBridgeGUID)) - 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: - m_auiEncounter[6] = uiData; + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + { + SetSpecialAchievementCriteria(TYPE_ACHIEV_CAT_LADY, true); + SetSpecialAchievementCriteria(TYPE_ACHIEV_NINE_LIVES, false); + } break; - // Keepers + + // Keepers of Ulduar case TYPE_MIMIRON: - m_auiEncounter[7] = uiData; - DoUseDoorOrButton(m_uiMimironDoor1GUID); - DoUseDoorOrButton(m_uiMimironDoor2GUID); - DoUseDoorOrButton(m_uiMimironDoor3GUID); + // 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 (m_auiHardBoss[3] != DONE) - DoRespawnGameObject(m_uiMimironLootGUID, 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(G0_MIMIRON_BUTTON, GO_FLAG_NO_INTERACT, true); + else if (uiData == FAIL) + { + // reset objects + DoToggleGameObjectFlags(G0_MIMIRON_BUTTON, GO_FLAG_NO_INTERACT, false); + + if (GameObject* pButton = GetSingleGameObjectFromStorage(G0_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: - m_auiEncounter[8] = uiData; - DoUseDoorOrButton(m_uiHodirEnterDoorGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_HODIR_ENTER); if (uiData == DONE) { - DoUseDoorOrButton(m_uiHodirWallGUID); - DoUseDoorOrButton(m_uiHodirExitDoorGUID); - DoRespawnGameObject(m_uiHodirLootGUID, 30*MINUTE); - SpawnFriendlyKeeper(NPC_HODIR_IMAGE); + DoUseDoorOrButton(GO_HODIR_ICE_WALL); + DoUseDoorOrButton(GO_HODIR_EXIT); + + 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[9] = uiData; - DoUseDoorOrButton(m_uiArenaEnterDoorGUID); + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_LIGHTNING_FIELD); if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiArenaExitDoorGUID); - if (uiData == DONE) { - if (m_auiHardBoss[5] != DONE) - DoRespawnGameObject(m_uiThorimLootGUID, 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[10] = uiData; + 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[11] = uiData; + m_auiEncounter[uiType] = uiData; if (uiData == DONE) - DoUseDoorOrButton(m_uiVezaxGateGUID); + DoUseDoorOrButton(GO_VEZAX_GATE); break; case TYPE_YOGGSARON: - m_auiEncounter[12] = uiData; - DoUseDoorOrButton(m_uiYoggGateGUID); + // 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)) + { + pHelper->AI()->EnterEvadeMode(); + pHelper->CastSpell(pHelper, SPELL_KEEPER_ACTIVE, true); + } + } + } + + // 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[13] = uiData; - //TODO: need to find the proper way to use these - DoUseDoorOrButton(m_uiCelestialDoorGUID); - DoUseDoorOrButton(m_uiUniverseFloorCelestialGUID); + m_auiEncounter[uiType] = uiData; + 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(m_uiAlagonLootGUID, 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; + return; + case TYPE_THORIM_HARD: + m_auiHardBoss[3] = uiData; + return; + case TYPE_MIMIRON_HARD: m_auiHardBoss[4] = uiData; - if (uiData == DONE) - DoRespawnGameObject(m_uiHodirRareLootGUID, 30*MINUTE); - break; - case TYPE_ASSEMBLY_HARD: - m_auiHardBoss[2] = uiData; // TODO: add extra loot - break; + return; case TYPE_FREYA_HARD: - m_auiHardBoss[6] = uiData; // Hard mode loot in in script - break; - case TYPE_THORIM_HARD: m_auiHardBoss[5] = uiData; - if (uiData == DONE) - DoRespawnGameObject(m_uiThorimRareLootGUID, 30*MINUTE); - break; - case TYPE_MIMIRON_HARD: - m_auiHardBoss[3] = uiData; - if (uiData == DONE) - DoRespawnGameObject(m_uiMimironHardLootGUID, 30*MINUTE); - break; + return; case TYPE_VEZAX_HARD: - m_auiHardBoss[7] = uiData; // TODO: add extra loot - break; + m_auiHardBoss[6] = uiData; + return; case TYPE_YOGGSARON_HARD: - m_auiHardBoss[8] = 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; - // Teleporters - case TYPE_LEVIATHAN_TP: - m_auiUlduarTeleporters[0] = uiData; - break; - case TYPE_XT002_TP: - m_auiUlduarTeleporters[1] = uiData; + // 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; - case TYPE_MIMIRON_TP: - m_auiUlduarTeleporters[2] = uiData; - break; - } - DoOpenMadnessDoorIfCan(); + // 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_auiHardBoss[7] << " " << m_auiHardBoss[8] << " " << 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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); SaveToDB(); OUT_SAVE_INST_DATA_COMPLETE; } } -uint64 instance_ulduar::GetData64(uint32 uiData) +bool instance_ulduar::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const { - switch (uiData) + switch (uiInstanceConditionId) { - // Siege - case NPC_LEVIATHAN: - return m_uiLeviathanGUID; - case NPC_IGNIS: - return m_uiIgnisGUID; - case NPC_RAZORSCALE: - return m_uiRazorscaleGUID; - case NPC_COMMANDER: - return m_uiCommanderGUID; - case NPC_XT002: - return m_uiXT002GUID; - // Antechamber - case NPC_STEELBREAKER: - return m_uiSteelbreakerGUID; - case NPC_MOLGEIM: - return m_uiMolgeimGUID; - case NPC_BRUNDIR: - return m_uiBrundirGUID; - case NPC_KOLOGARN: - return m_uiKologarnGUID; - case NPC_LEFT_ARM: - return m_uiLeftArmGUID; - case NPC_RIGHT_ARM: - return m_uiRightArmGUID; - case NPC_AURIAYA: - return m_uiAuriayaGUID; - // Keepers - case NPC_MIMIRON: - return m_uiMimironGUID; - case NPC_LEVIATHAN_MK: - return m_uiLeviathanMkGUID; - case NPC_HODIR: - return m_uiMimironGUID; - case NPC_THORIM: - return m_uiThorimGUID; - case NPC_RUNE_GIANT: - return m_uiRuneGiantGUID; - case NPC_RUNIC_COLOSSUS: - return m_uiRunicColossusGUID; - case NPC_JORMUNGAR_BEHEMOTH: - return m_uiJormungarGUID; - case NPC_FREYA: - return m_uiFreyaGUID; - case NPC_ELDER_BRIGHTLEAF: - return m_uiElderBrightleafGUID; - case NPC_ELDER_IRONBRACH: - return m_uiElderIronbrachGUID; - case NPC_ELDER_STONEBARK: - return m_uiElderStonebarkGUID; - case NPC_VEZAX: - return m_uiVezaxGUID; - case NPC_YOGGSARON: - return m_uiYoggSaronGUID; - case NPC_SARA: - return m_uiSaraGUID; - case NPC_YOGG_BRAIN: - return m_uiYoggBrainGUID; - case NPC_ALGALON: - return m_uiAlgalonGUID; + 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; - // Mimiron hard mode button - case G0_MIMIRON_BUTTON: - return m_uiMimironButtonGUID; - // Celestial door - case GO_CELESTIAL_DOOR: - return m_uiCelestialDoorGUID; - } + 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 0; -} + return uiCondId == uiInstanceConditionId; + } + case INSTANCE_CONDITION_ID_ULDUAR: + { + if (!pConditionSource) + break; -// TODO: implement all hard mode loot here! -bool instance_ulduar::CheckConditionCriteriaMeet(Player const* pSource, uint32 uiMapId, uint32 uiInstanceConditionId) -{ - if (uiMapId != instance->GetId()) - return false; + // 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; + } + } - switch (uiInstanceConditionId) - { - case TYPE_XT002_HARD: - break; - } + 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: @@ -799,28 +1053,30 @@ 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: return m_auiHardBoss[1]; - case TYPE_ASSEMBLY_HARD: + case TYPE_HODIR_HARD: return m_auiHardBoss[2]; - case TYPE_MIMIRON_HARD: + case TYPE_THORIM_HARD: return m_auiHardBoss[3]; - case TYPE_HODIR_HARD: + case TYPE_MIMIRON_HARD: return m_auiHardBoss[4]; - case TYPE_THORIM_HARD: - return m_auiHardBoss[5]; case TYPE_FREYA_HARD: - return m_auiHardBoss[6]; + return m_auiHardBoss[5]; case TYPE_VEZAX_HARD: - return m_auiHardBoss[7]; + return m_auiHardBoss[6]; case TYPE_YOGGSARON_HARD: - return m_auiHardBoss[8]; + return m_auiHardBoss[7]; - // Ulduar Keepers + // Ulduar Keepers case TYPE_KEEPER_HODIR: return m_auiUlduarKeepers[0]; case TYPE_KEEPER_THORIM: @@ -830,14 +1086,19 @@ uint32 instance_ulduar::GetData(uint32 uiType) case TYPE_KEEPER_MIMIRON: return m_auiUlduarKeepers[3]; - // Teleporters - case TYPE_LEVIATHAN_TP: - return m_auiUlduarTeleporters[0]; - case TYPE_XT002_TP: - return m_auiUlduarTeleporters[1]; - case TYPE_MIMIRON_TP: - return m_auiUlduarTeleporters[2]; - } + // 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; } @@ -849,12 +1110,129 @@ void instance_ulduar::SpawnFriendlyKeeper(uint32 uiWho) if (!pPlayer) return; - switch(uiWho) + switch (uiWho) + { + 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()) { - 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_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; } } @@ -870,14 +1248,13 @@ 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_auiHardBoss[7] >> m_auiHardBoss[8] >> m_auiUlduarKeepers[0] - >> m_auiUlduarKeepers[1] >> m_auiUlduarKeepers[2] >> m_auiUlduarKeepers[3]; - - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + >> 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) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -886,11 +1263,370 @@ void instance_ulduar::Load(const char* strIn) OUT_LOAD_INST_DATA_COMPLETE; } +void instance_ulduar::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < MAX_SPECIAL_ACHIEV_CRITS) + m_abAchievCriteria[uiType] = bIsMet; +} + +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_CAT_LADY_N: + case ACHIEV_CRIT_CAT_LADY_H: + return m_abAchievCriteria[TYPE_ACHIEV_CAT_LADY]; + case ACHIEV_CRIT_NINE_LIVES_N: + case ACHIEV_CRIT_NINE_LIVES_H: + return m_abAchievCriteria[TYPE_ACHIEV_NINE_LIVES]; + case ACHIEV_CRIT_BRUNDIR_N: + case ACHIEV_CRIT_BRUNDIR_H: + if (GetData(TYPE_ASSEMBLY) == SPECIAL) + return m_abAchievCriteria[TYPE_ACHIEV_BRUNDIR]; + case ACHIEV_CRIT_MOLGEIM_N: + case ACHIEV_CRIT_MOLGEIM_H: + if (GetData(TYPE_ASSEMBLY) == SPECIAL) + return m_abAchievCriteria[TYPE_ACHIEV_MOLGEIM]; + case ACHIEV_CRIT_STEELBREAKER_N: + case ACHIEV_CRIT_STEELBREAKER_H: + if (GetData(TYPE_ASSEMBLY) == SPECIAL) + return m_abAchievCriteria[TYPE_ACHIEV_STEELBREAKER]; + case ACHIEV_CRIT_STUNNED_BRUND_N: + case ACHIEV_CRIT_STUNNED_STEEL_N: + case ACHIEV_CRIT_STUNNED_MOLG_N: + case ACHIEV_CRIT_STUNNED_BRUND_H: + case ACHIEV_CRIT_STUNNED_STEEL_H: + 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].uiAllyEntry, 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].uiAllyEntry, 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; @@ -899,4 +1635,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 ff84d97981..a04ad251d3 100644 --- a/scripts/northrend/ulduar/ulduar/ulduar.cpp +++ b/scripts/northrend/ulduar/ulduar/ulduar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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, @@ -53,3 +73,564 @@ enum TeleporterGossipItems GOSSIP_ITEM_TELE_SPARK_IMAGINATION = -3603007, 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 c1eb6fa001..7cfb146469 100644 --- a/scripts/northrend/ulduar/ulduar/ulduar.h +++ b/scripts/northrend/ulduar/ulduar/ulduar.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 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,10 +7,9 @@ enum { - MAX_ENCOUNTER = 14, - HARD_MODE_ENCOUNTER = 9, + MAX_ENCOUNTER = 16, + HARD_MODE_ENCOUNTER = 8, KEEPER_ENCOUNTER = 4, - TELEPORTER_ENCOUNTER = 3, // Main boss types TYPE_LEVIATHAN = 0, @@ -27,38 +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_ASSEMBLY_HARD = 16, - TYPE_MIMIRON_HARD = 17, - TYPE_HODIR_HARD = 18, - TYPE_THORIM_HARD = 19, - TYPE_FREYA_HARD = 20, - 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, - // Teleporter types - // Some teleporters aren't depending directly on a boss, so we use a distinct type for them (maybe use areatrigger?) - TYPE_LEVIATHAN_TP = 27, - TYPE_XT002_TP = 28, - TYPE_MIMIRON_TP = 29, + // 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, @@ -67,24 +97,74 @@ 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, @@ -92,73 +172,117 @@ enum 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 = 19, + + TYPE_ACHIEV_CAT_LADY = 0, + TYPE_ACHIEV_NINE_LIVES = 1, + TYPE_ACHIEV_STEELBREAKER = 2, + 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, + // Loot chests // Kologarn - GO_CACHE_OF_LIVING_STONE = 195046, - GO_CACHE_OF_LIVING_STONE_H = 195047, + GO_CACHE_OF_LIVING_STONE_10 = 195046, + GO_CACHE_OF_LIVING_STONE_25 = 195047, // Hodir - GO_CACHE_OF_WINTER = 194307, - GO_CACHE_OF_WINTER_H = 194308, - GO_CACHE_OF_RARE_WINTER = 194200, - GO_CACHE_OF_RARE_WINTER_H = 194201, + GO_CACHE_OF_WINTER_10 = 194307, + GO_CACHE_OF_WINTER_25 = 194308, + GO_CACHE_OF_RARE_WINTER_10 = 194200, + GO_CACHE_OF_RARE_WINTER_25 = 194201, // Mimiron - GO_CACHE_OF_INOV = 194789, - GO_CACHE_OF_INOV_H = 194956, - GO_CACHE_OF_INOV_HARD = 194957, - GO_CACHE_OF_INOV_HARD_H = 194958, + GO_CACHE_OF_INOV_10 = 194789, + GO_CACHE_OF_INOV_25 = 194956, + GO_CACHE_OF_INOV_10_H = 194957, + GO_CACHE_OF_INOV_25_H = 194958, // Thorim - GO_CACHE_OF_STORMS = 194312, - GO_CACHE_OF_STORMS_H = 194314, - GO_CACHE_OF_RARE_STORMS = 194313, - GO_CACHE_OF_RARE_STORMS_H = 194315, + GO_CACHE_OF_STORMS_10 = 194312, + GO_CACHE_OF_STORMS_25 = 194315, + GO_CACHE_OF_STORMS_10_H = 194313, + GO_CACHE_OF_STORMS_25_H = 194314, // Alagon - GO_GIFT_OF_OBSERVER_H = 194821, - GO_GIFT_OF_OBSERVER = 194822, - GO_GIFT_OF_OBSERVER_HH = 194823, // Purpose Unknown + GO_GIFT_OF_OBSERVER_10 = 194821, + GO_GIFT_OF_OBSERVER_25 = 194822, // Doors and other Objects // The siege GO_SHIELD_WALL = 194416, // Gate before Leviathan - GO_LEVIATHAN_GATE = 194630, // Gate after Leviathan -> this should be used before the boss enter the arena - // There should be another gate after the Leviathan here which should be used during the Leviathan encounter + 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 @@ -185,141 +309,311 @@ 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, // For the platform animation + 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, + + // 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_CAT_LADY_N = 10400, // Auriaya, achievs 3006, 3007 + ACHIEV_CRIT_CAT_LADY_H = 10184, + ACHIEV_CRIT_NINE_LIVES_N = 10399, // Auriaya, achievs 3076, 3077 + ACHIEV_CRIT_NINE_LIVES_H = 10243, + ACHIEV_CRIT_STEELBREAKER_N = 10084, // Iron council, achievs 2941, 2944 + ACHIEV_CRIT_STEELBREAKER_H = 10087, + ACHIEV_CRIT_MOLGEIM_N = 10082, // Iron council, achievs 2939, 2942 + ACHIEV_CRIT_MOLGEIM_H = 10085, + ACHIEV_CRIT_BRUNDIR_N = 10083, // Iron council, achievs 2940, 2943 + ACHIEV_CRIT_BRUNDIR_H = 10086, + ACHIEV_CRIT_STUNNED_BRUND_N = 10090, // Iron council, achiev 2947 + ACHIEV_CRIT_STUNNED_STEEL_N = 10422, + ACHIEV_CRIT_STUNNED_MOLG_N = 10423, + 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, +}; + +struct UlduarSpawns +{ + 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 UlduarSpawns 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}, }; -class MANGOS_DLL_DECL instance_ulduar : public ScriptedInstance +static const UlduarSpawns 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 UlduarSpawns 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 UlduarSpawns 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 UlduarSpawns 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 MANGOS_DLL_DECL 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 OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnPlayerDeath(Player* pPlayer) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiData); + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - // Dummy, leave till correct solution for hardmode found - bool CheckConditionCriteriaMeet(Player const* pSource, uint32 uiMapId, uint32 uiInstanceConditionId); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void DoOpenMadnessDoorIfCan(); - Player* GetPlayerInMap(); - void SpawnFriendlyKeeper(uint32 uiWho); + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + 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 DoSpawnThorimNpcs(Player* pSummoner); + void DoProcessShatteredEvent(); + + ObjectGuid GetKoloRubbleStalker(bool bRightSide) { return bRightSide ? m_rightKoloStalkerGuid : m_leftKoloStalkerGuid; } + + 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: - std::string strInstData; + 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_auiUlduarTeleporters[TELEPORTER_ENCOUNTER]; - - // Creatures - uint64 m_uiLeviathanGUID; - uint64 m_uiIgnisGUID; - uint64 m_uiRazorscaleGUID; - uint64 m_uiCommanderGUID; - uint64 m_uiXT002GUID; - uint64 m_uiBrundirGUID; - uint64 m_uiMolgeimGUID; - uint64 m_uiSteelbreakerGUID; - uint64 m_uiKologarnGUID; - uint64 m_uiAuriayaGUID; - uint64 m_uiMimironGUID; - uint64 m_uiHodirGUID; - uint64 m_uiThorimGUID; - uint64 m_uiFreyaGUID; - uint64 m_uiVezaxGUID; - uint64 m_uiYoggSaronGUID; - uint64 m_uiAlgalonGUID; - uint64 m_uiRightArmGUID; - uint64 m_uiLeftArmGUID; - uint64 m_uiFeralDefenderGUID; - uint64 m_uiElderBrightleafGUID; - uint64 m_uiElderStonebarkGUID; - uint64 m_uiElderIronbrachGUID; - uint64 m_uiSaroniteAnimusGUID; - uint64 m_uiRunicColossusGUID; - uint64 m_uiRuneGiantGUID; - uint64 m_uiJormungarGUID; - uint64 m_uiLeviathanMkGUID; - uint64 m_uiSaraGUID; - uint64 m_uiYoggBrainGUID; - - // Doors & Objects - // The siege - uint64 m_uiShieldWallGUID; - uint64 m_uiLeviathanGateGUID; - uint64 m_uiXT002GateGUID; - uint64 m_uiBrokenHarpoonGUID; - // Archivum - uint64 m_uiIronCouncilDoorGUID; - uint64 m_uiArchivumDoorGUID; - uint64 m_uiArchivumConsoleGUID; - uint64 m_uiUniverseFloorArchivumGUID; - // Celestial planetarium - uint64 m_uiCelestialDoorGUID; - uint64 m_uiCelestialConsoleGUID; - uint64 m_uiUniverseFloorCelestialGUID; - uint64 m_uiAzerothGlobeGUID; - // Kologarn - uint64 m_uiShatteredHallsDoorGUID; - uint64 m_uiKologarnBridgeGUID; - // Hodir - uint64 m_uiHodirEnterDoorGUID; - uint64 m_uiHodirWallGUID; - uint64 m_uiHodirExitDoorGUID; - // Mimiron - uint64 m_uiMimironButtonGUID; - uint64 m_uiMimironDoor1GUID; - uint64 m_uiMimironDoor2GUID; - uint64 m_uiMimironDoor3GUID; - uint64 m_uiMimironElevatorGUID; - uint64 m_auiMimironTelGUID[9]; - // Thorim - uint64 m_uiArenaEnterDoorGUID; - uint64 m_uiArenaExitDoorGUID; - uint64 m_uiHallwayDoorGUID; - uint64 m_uiThorimEnterDoorGUID; - uint64 m_uiThorimLeverGUID; - // Prison - uint64 m_uiAncientGateGUID; - uint64 m_uiVezaxGateGUID; - uint64 m_uiYoggGateGUID; - uint64 m_uiBrainDoor1GUID; - uint64 m_uiBrainDoor2GUID; - uint64 m_uiBrainDoor3GUID; - - // Chests - uint64 m_uiKologarnLootGUID; - uint64 m_uiHodirLootGUID; - uint64 m_uiHodirRareLootGUID; - uint64 m_uiThorimLootGUID; - uint64 m_uiThorimRareLootGUID; - uint64 m_uiMimironLootGUID; - uint64 m_uiMimironHardLootGUID; - uint64 m_uiAlagonLootGUID; + 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; + + 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 b9c7b24ae1..93128e18ba 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Ingvar -SD%Complete: 35% -SDComment: TODO: correct timers. Create ressurection sequenze and phase 2. +SD%Complete: 70% +SDComment: TODO: correct timers, spell 42912 requires proper position fix in core SDCategory: Utgarde Keep EndScriptData */ @@ -36,10 +36,11 @@ enum SAY_ANNHYLDE_REZ = -1574023, NPC_ANNHYLDE = 24068, - NPC_THROW_TARGET = 23996, //the target, casting spell and target of moving dummy - NPC_THROW_DUMMY = 23997, //the axe, moving to target + NPC_THROW_TARGET = 23996, // the target, casting spell and target of moving dummy + 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, @@ -51,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, @@ -61,16 +62,20 @@ enum SPELL_WOE_STRIKE_H = 59735, SPELL_SHADOW_AXE = 42748, - SPELL_SHADOW_AXE_PROC = 42751, - SPELL_SHADOW_AXE_PROC_H = 59720, + 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, SPELL_TRANSFORM = 42796, - SPELL_SCOURGE_RES_SUMMON = 42863, //summones a dummy target - SPELL_SCOURGE_RES_HEAL = 42704, //heals max HP - SPELL_SCOURGE_RES_BUBBLE = 42862, //black bubble - SPELL_SCOURGE_RES_CHANNEL = 42857 //the whirl from annhylde + SPELL_SCOURGE_RES_SUMMON = 42863, // summones a dummy target + SPELL_SCOURGE_RES_HEAL = 42704, // heals max HP + SPELL_SCOURGE_RES_BUBBLE = 42862, // black bubble + SPELL_SCOURGE_RES_CHANNEL = 42857, // the whirl from annhylde + + POINT_ID_ANNHYLDE = 1 }; /*###### @@ -90,15 +95,17 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI bool m_bIsRegularMode; bool m_bIsResurrected; + bool m_bIsFakingDeath; uint32 m_uiCleaveTimer; uint32 m_uiSmashTimer; uint32 m_uiStaggeringRoarTimer; uint32 m_uiEnrageTimer; - void Reset() + void Reset() override { m_bIsResurrected = false; + m_bIsFakingDeath = false; m_uiCleaveTimer = urand(5000, 7000); m_uiSmashTimer = urand(8000, 15000); @@ -106,77 +113,177 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI m_uiEnrageTimer = 30000; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { - DoScriptText(m_bIsResurrected ? SAY_AGGRO_SECOND : SAY_AGGRO_FIRST, m_creature); + // don't yell for her + if (pWho->GetEntry() == NPC_ANNHYLDE) + return; + + // 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); } - //this need to be done when spell works - /*void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { if (m_bIsResurrected) return; - if (uiDamage >= m_creature->GetHealth()) + if (m_bIsFakingDeath) { - uiDamage = m_creature->GetHealth() -1; + uiDamage = 0; + return; + } - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; DoScriptText(SAY_DEATH_FIRST, m_creature); - m_creature->CastSpell(m_creature, SPELL_FEIGN_DEATH, true); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_BANSHEE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH, CAST_TRIGGERED); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_bIsFakingDeath = true; + } + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_TRANSFORM) + { + DoScriptText(SAY_AGGRO_SECOND, m_creature); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->UpdateEntry(pSpell->GetEffectMiscValue(EFFECT_INDEX_0)); + m_bIsResurrected = true; + m_bIsFakingDeath = false; } - }*/ + } - void JustDied(Unit* pKiller) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_THROW_DUMMY: + // ToDo: should this move to the target? + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_SHADOW_AXE_PROC : SPELL_SHADOW_AXE_PROC_H, true); + break; + + case NPC_ANNHYLDE: + // This is not blizzlike - npc should be summoned above the boss and should move slower + pSummoned->CastSpell(pSummoned, SPELL_ASTRAL_TELEPORT, false); + pSummoned->SetLevitate(true); + pSummoned->GetMotionMaster()->MovePoint(POINT_ID_ANNHYLDE, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ() + 15.0f); + break; + + case NPC_GROUND_VISUAL: + pSummoned->CastSpell(pSummoned, SPELL_SCOURGE_RES_BUBBLE, false); + // npc doesn't despawn on time + pSummoned->ForcedDespawn(8000); + break; + } + } + + 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()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || m_bIsFakingDeath) return; - if (!m_bIsResurrected) + if (!m_bIsResurrected) // First phase { if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = urand(2500, 7000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(2500, 7000); } else m_uiCleaveTimer -= uiDiff; if (m_uiSmashTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SMASH : SPELL_SMASH_H); - m_uiSmashTimer = urand(8000, 15000); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SMASH : SPELL_SMASH_H) == CAST_OK) + m_uiSmashTimer = urand(8000, 15000); } else m_uiSmashTimer -= uiDiff; if (m_uiStaggeringRoarTimer < uiDiff) { - DoScriptText(EMOTE_ROAR, m_creature); - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STAGGERING_ROAR : SPELL_STAGGERING_ROAR_H); - m_uiStaggeringRoarTimer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STAGGERING_ROAR : SPELL_STAGGERING_ROAR_H) == CAST_OK) + { + DoScriptText(EMOTE_ROAR, m_creature); + m_uiStaggeringRoarTimer = urand(15000, 30000); + } } else m_uiStaggeringRoarTimer -= uiDiff; if (m_uiEnrageTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H); - m_uiEnrageTimer = urand(10000, 20000); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H) == CAST_OK) + m_uiEnrageTimer = urand(10000, 20000); + } + else + m_uiEnrageTimer -= uiDiff; + } + else // Second phase + { + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_WOE_STRIKE : SPELL_WOE_STRIKE_H) == CAST_OK) + m_uiCleaveTimer = urand(2500, 7000); + } + else + m_uiCleaveTimer -= uiDiff; + + if (m_uiSmashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_SMASH_H) == CAST_OK) + m_uiSmashTimer = urand(8000, 15000); + } + else + m_uiSmashTimer -= uiDiff; + + if (m_uiStaggeringRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DREADFUL_ROAR : SPELL_DREADFUL_ROAR_H) == CAST_OK) + { + DoScriptText(EMOTE_ROAR, m_creature); + m_uiStaggeringRoarTimer = urand(15000, 30000); + } + } + else + m_uiStaggeringRoarTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_AXE) == CAST_OK) + m_uiEnrageTimer = urand(10000, 20000); } else m_uiEnrageTimer -= uiDiff; @@ -200,19 +307,82 @@ struct MANGOS_DLL_DECL npc_annhyldeAI : public ScriptedAI npc_annhyldeAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; - void Reset() + uint32 m_uiResurrectTimer; + uint8 m_uiResurrectPhase; + + void Reset() override + { + m_uiResurrectTimer = 0; + m_uiResurrectPhase = 0; + } + + // No attacking + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { + if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_ID_ANNHYLDE) + return; + + DoScriptText(SAY_ANNHYLDE_REZ, m_creature); + m_uiResurrectTimer = 3000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (m_uiResurrectTimer) + { + if (m_uiResurrectTimer <= uiDiff) + { + if (!m_pInstance) + return; + + switch (m_uiResurrectPhase) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_SCOURGE_RES_CHANNEL); + if (Creature* pIngvar = m_pInstance->GetSingleCreatureFromStorage(NPC_INGVAR)) + { + if (pIngvar->HasAura(SPELL_SUMMON_BANSHEE)) + pIngvar->RemoveAurasDueToSpell(SPELL_SUMMON_BANSHEE); + } + m_uiResurrectTimer = 3000; + break; + case 1: + if (Creature* pIngvar = m_pInstance->GetSingleCreatureFromStorage(NPC_INGVAR)) + { + pIngvar->CastSpell(pIngvar, SPELL_SCOURGE_RES_SUMMON, true); + // Workaround - set Feign death again because it's removed by the previous casted spell + pIngvar->CastSpell(pIngvar, SPELL_FEIGN_DEATH, true); + } + m_uiResurrectTimer = 5000; + break; + case 2: + if (Creature* pIngvar = m_pInstance->GetSingleCreatureFromStorage(NPC_INGVAR)) + pIngvar->CastSpell(pIngvar, SPELL_SCOURGE_RES_HEAL, false); + m_uiResurrectTimer = 3000; + break; + case 3: + if (Creature* pIngvar = m_pInstance->GetSingleCreatureFromStorage(NPC_INGVAR)) + pIngvar->CastSpell(pIngvar, SPELL_TRANSFORM, false); + // despawn the creature + m_creature->GetMotionMaster()->MovePoint(2, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 50); + m_creature->ForcedDespawn(5000); + m_uiResurrectTimer = 0; + break; + } + + ++m_uiResurrectPhase; + } + else + m_uiResurrectTimer -= uiDiff; + } } }; @@ -223,15 +393,15 @@ CreatureAI* GetAI_npc_annhylde(Creature* pCreature) void AddSC_boss_ingvar() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_ingvar"; - newscript->GetAI = &GetAI_boss_ingvar; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_ingvar"; + pNewScript->GetAI = &GetAI_boss_ingvar; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "npc_annhylde"; - newscript->GetAI = &GetAI_npc_annhylde; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_annhylde"; + pNewScript->GetAI = &GetAI_npc_annhylde; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp index d3cad4f638..0007b54598 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -45,7 +45,6 @@ enum SPELL_DECREPIFY_H = 59397, SPELL_BONE_ARMOR = 59386, // casted on boss, heroic only - NPC_FROST_TOMB = 23965, NPC_VRYKUL_SKELETON = 23970 }; @@ -59,7 +58,7 @@ static float fAddPosition[4] = {163.5727f, 252.1900f, 42.8684f, 5.57052f}; struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI { - mob_vrykul_skeletonAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_vrykul_skeletonAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = m_creature->GetMap()->IsRegularDifficulty(); @@ -69,22 +68,16 @@ struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - Creature* m_pKeleseth; uint32 m_uiCastTimer; uint32 m_uiReviveTimer; - void Reset() + void Reset() override { m_uiReviveTimer = 0; m_uiCastTimer = urand(5000, 10000); // taken out of thin air - - if (!m_pInstance) - return; - - m_pKeleseth = m_pInstance->instance->GetCreature(m_pInstance->GetData64(NPC_KELESETH)); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!pWho || m_uiReviveTimer) return; @@ -92,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; @@ -113,14 +106,8 @@ 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_pKeleseth || !m_pKeleseth->isAlive()) - { - uiDamage = m_creature->GetHealth(); - return; - } - if (m_uiReviveTimer) { uiDamage = 0; @@ -133,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; @@ -164,8 +151,11 @@ struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI { if (urand(0, 3)) DoCastSpellIfCan(m_creature->getVictim(), SPELL_DECREPIFY_H); - else if (m_pKeleseth && m_pKeleseth->isAlive()) - DoCastSpellIfCan(m_pKeleseth, SPELL_BONE_ARMOR); + else if (m_pInstance && m_pInstance->GetData(TYPE_KELESETH) == IN_PROGRESS) + { + if (Creature* pKeleseth = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + DoCastSpellIfCan(pKeleseth, SPELL_BONE_ARMOR); + } } m_uiCastTimer = urand(5000, 15000); @@ -198,21 +188,23 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 m_uiFrostTombTimer; + uint32 m_uiFrostTombTimer; uint32 m_uiSummonTimer; uint32 m_uiShadowboltTimer; - void Reset() + GuidList m_lSummonedAddGuids; + + void Reset() override { // timers need confirmation m_uiFrostTombTimer = 20000; m_uiSummonTimer = 5000 ; m_uiShadowboltTimer = 0; - DespawnAdds(); + DespawnOrKillAdds(true); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, true)) { @@ -224,47 +216,73 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_KELESETH, IN_PROGRESS); } 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_TIMED_DESPAWN_OUT_OF_COMBAT, MINUTE*IN_MILLISECONDS); + 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 DespawnAdds() + void DespawnOrKillAdds(bool bDespawn) { - std::list lAddsList; - GetCreatureListWithEntryInGrid(lAddsList, m_creature, NPC_VRYKUL_SKELETON, 100.0f); + for (GuidList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); ++itr) + { + if (Creature* pAdd = m_creature->GetMap()->GetCreature(*itr)) + { + if (bDespawn) + pAdd->ForcedDespawn(); + else + { + pAdd->SetDeathState(JUST_DIED); + pAdd->SetHealth(0); + } + } + } - if (!lAddsList.empty()) - for(std::list::iterator itr = lAddsList.begin(); itr != lAddsList.end(); ++itr) - (*itr)->ForcedDespawn(); + m_lSummonedAddGuids.clear(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_VRYKUL_SKELETON) + { pSummoned->AI()->AttackStart(m_creature->getVictim()); + m_lSummonedAddGuids.push_back(pSummoned->GetObjectGuid()); + } if (pSummoned->GetEntry() == NPC_FROST_TOMB) pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, true); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_KELESETH, DONE); + + DespawnOrKillAdds(false); + } + + 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; @@ -292,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); @@ -322,15 +340,15 @@ CreatureAI* GetAI_boss_keleseth(Creature* pCreature) void AddSC_boss_keleseth() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_keleseth"; - newscript->GetAI = &GetAI_boss_keleseth; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_keleseth"; + pNewScript->GetAI = &GetAI_boss_keleseth; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_vrykul_skeleton"; - newscript->GetAI = &GetAI_mob_vrykul_skeleton; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_vrykul_skeleton"; + pNewScript->GetAI = &GetAI_mob_vrykul_skeleton; + pNewScript->RegisterSelf(); } 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 095e52f989..94c7de1ce2 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, @@ -80,25 +80,24 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - m_uiGhostGUID = 0; Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint64 m_uiGhostGUID; + ObjectGuid m_ghostGuid; Creature* GetBuddy() { if (!m_pInstance) return NULL; - return m_pInstance->instance->GetCreature(m_pInstance->GetData64(m_creature->GetEntry() == NPC_DALRONN ? NPC_SKARVALD : NPC_DALRONN)); + 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()) { @@ -106,14 +105,14 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI pBuddy->Respawn(); } - if (Creature* pGhost = m_creature->GetMap()->GetCreature(m_uiGhostGUID)) + if (Creature* pGhost = m_creature->GetMap()->GetCreature(m_ghostGuid)) { if (pGhost->isAlive()) pGhost->ForcedDespawn(); } } - void EnterCombat(Unit* pWho) + void EnterCombat(Unit* pWho) override { if (!pWho) return; @@ -127,19 +126,21 @@ 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_uiGhostGUID = pSummoned->GetGUID(); + 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()); + + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (Creature* pBuddy = GetBuddy()) { @@ -154,7 +155,7 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI } else { - if (Creature* pGhost = m_creature->GetMap()->GetCreature(m_uiGhostGUID)) + if (Creature* pGhost = m_creature->GetMap()->GetCreature(m_ghostGuid)) pGhost->ForcedDespawn(); pBuddy->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); @@ -176,7 +177,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); @@ -184,18 +185,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; @@ -260,19 +261,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; @@ -321,15 +322,15 @@ CreatureAI* GetAI_boss_dalronn(Creature* pCreature) void AddSC_boss_skarvald_and_dalronn() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_skarvald"; - newscript->GetAI = &GetAI_boss_skarvald; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_skarvald"; + pNewScript->GetAI = &GetAI_boss_skarvald; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_dalronn"; - newscript->GetAI = &GetAI_boss_dalronn; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_dalronn"; + pNewScript->GetAI = &GetAI_boss_dalronn; + pNewScript->RegisterSelf(); } 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 0f9f9ee5f6..ccab4d375f 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,169 +24,164 @@ EndScriptData */ #include "precompiled.h" #include "utgarde_keep.h" -struct MANGOS_DLL_DECL instance_utgarde_keep : public ScriptedInstance +instance_utgarde_keep::instance_utgarde_keep(Map* pMap) : ScriptedInstance(pMap), + m_bKelesethAchievFailed(false) { - instance_utgarde_keep(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiKelesethGUID; - uint64 m_uiSkarvaldGUID; - uint64 m_uiDalronnGUID; + Initialize(); +} - uint64 m_uiBellow1GUID; - uint64 m_uiBellow2GUID; - uint64 m_uiBellow3GUID; - uint64 m_uiForgeFire1GUID; - uint64 m_uiForgeFire2GUID; - uint64 m_uiForgeFire3GUID; +void instance_utgarde_keep::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_utgarde_keep::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiKelesethGUID = 0; - m_uiSkarvaldGUID = 0; - m_uiDalronnGUID = 0; - - m_uiBellow1GUID = 0; - m_uiBellow2GUID = 0; - m_uiBellow3GUID = 0; - m_uiForgeFire1GUID = 0; - m_uiForgeFire2GUID = 0; - m_uiForgeFire3GUID = 0; + case NPC_KELESETH: + case NPC_SKARVALD: + case NPC_DALRONN: + case NPC_INGVAR: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_utgarde_keep::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case NPC_KELESETH: m_uiKelesethGUID = pCreature->GetGUID(); break; - case NPC_SKARVALD: m_uiSkarvaldGUID = pCreature->GetGUID(); break; - case NPC_DALRONN: m_uiDalronnGUID = pCreature->GetGUID(); break; - } + case GO_BELLOW_1: + if (m_auiEncounter[TYPE_BELLOW_1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_BELLOW_2: + if (m_auiEncounter[TYPE_BELLOW_2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_BELLOW_3: + if (m_auiEncounter[TYPE_BELLOW_3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FORGEFIRE_1: + if (m_auiEncounter[TYPE_BELLOW_1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FORGEFIRE_2: + if (m_auiEncounter[TYPE_BELLOW_2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FORGEFIRE_3: + 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; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) - { - switch(pGo->GetEntry()) - { - case GO_BELLOW_1: - m_uiBellow1GUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_BELLOW_2: - m_uiBellow2GUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_BELLOW_3: - m_uiBellow3GUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_FORGEFIRE_1: - m_uiForgeFire1GUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_FORGEFIRE_2: - m_uiForgeFire2GUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_FORGEFIRE_3: - m_uiForgeFire3GUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - } - } +void instance_utgarde_keep::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_FROST_TOMB) + m_bKelesethAchievFailed = true; +} - void SetData(uint32 uiType, uint32 uiData) +void instance_utgarde_keep::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(uiType) - { - case GO_BELLOW_1: - m_auiEncounter[0] = uiData; - break; - case GO_BELLOW_2: - m_auiEncounter[1] = uiData; - break; - case GO_BELLOW_3: - m_auiEncounter[2] = uiData; - break; - } - - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; - - strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + case TYPE_KELESETH: + if (uiData == IN_PROGRESS) + m_bKelesethAchievFailed = false; + 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: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_BELLOW_2: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_BELLOW_3: + m_auiEncounter[uiType] = uiData; + break; } - const char* Save() + if (uiData == DONE) { - return strInstData.c_str(); + 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint64 GetData64(uint32 uiData) +uint32 instance_utgarde_keep::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_utgarde_keep::Load(const char* chrIn) +{ + if (!chrIn) { - switch(uiData) - { - case NPC_KELESETH: - return m_uiKelesethGUID; - case NPC_SKARVALD: - return m_uiSkarvaldGUID; - case NPC_DALRONN: - return m_uiDalronnGUID; - case GO_BELLOW_1: - return m_uiBellow1GUID; - case GO_BELLOW_2: - return m_uiBellow2GUID; - case GO_BELLOW_3: - return m_uiBellow3GUID; - case GO_FORGEFIRE_1: - return m_uiForgeFire1GUID; - case GO_FORGEFIRE_2: - return m_uiForgeFire2GUID; - case GO_FORGEFIRE_3: - return m_uiForgeFire3GUID; - } - return 0; + OUT_LOAD_INST_DATA_FAIL; + return; } - void Load(const char* in) - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + OUT_LOAD_INST_DATA(chrIn); - OUT_LOAD_INST_DATA(in); + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - std::istringstream loadStream(in); - 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; + } - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + OUT_LOAD_INST_DATA_COMPLETE; +} - OUT_LOAD_INST_DATA_COMPLETE; - } -}; +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; + + return false; +} InstanceData* GetInstanceData_instance_utgarde_keep(Map* pMap) { @@ -195,9 +190,10 @@ InstanceData* GetInstanceData_instance_utgarde_keep(Map* pMap) void AddSC_instance_utgarde_keep() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_utgarde_keep"; - newscript->GetInstanceData = GetInstanceData_instance_utgarde_keep; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_utgarde_keep"; + pNewScript->GetInstanceData = GetInstanceData_instance_utgarde_keep; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp index d827506d0c..d0fc507fa3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -57,34 +57,34 @@ 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) + 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; case 2: uiGOBellow = GO_BELLOW_3; break; } - if (GameObject* pGOTemp = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(uiGOBellow))) + if (GameObject* pGOTemp = m_pInstance->GetSingleGameObjectFromStorage(uiGOBellow)) lGOList.push_back(pGOTemp); } 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,42 +93,40 @@ 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; break; - case GO_BELLOW_2: uiGOFire = GO_FORGEFIRE_2; break; - case GO_BELLOW_3: uiGOFire = GO_FORGEFIRE_3; break; + 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; + case GO_BELLOW_3: uiGOFire = GO_FORGEFIRE_3; m_uiForgeEncounterId = TYPE_BELLOW_3; break; } - if (GameObject* pGOTemp = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(uiGOFire))) + if (GameObject* pGOTemp = m_pInstance->GetSingleGameObjectFromStorage(uiGOFire)) { if (pGOTemp->getLootState() == GO_READY) pGOTemp->UseDoorOrButton(DAY); else if (pGOTemp->getLootState() == GO_ACTIVATED) pGOTemp->ResetDoorOrButton(); } - - m_uiForgeEncounterId = lGOList.front()->GetEntry(); } } - 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; @@ -151,10 +149,10 @@ CreatureAI* GetAI_mob_dragonflayer_forge_master(Creature* pCreature) void AddSC_utgarde_keep() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "mob_dragonflayer_forge_master"; - newscript->GetAI = &GetAI_mob_dragonflayer_forge_master; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_dragonflayer_forge_master"; + pNewScript->GetAI = &GetAI_mob_dragonflayer_forge_master; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h b/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h index fb91b7e4be..74b56fcad5 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,19 +7,61 @@ enum { - MAX_ENCOUNTER = 3, + MAX_ENCOUNTER = 6, + + TYPE_KELESETH = 0, + TYPE_SKARVALD_DALRONN = 1, + TYPE_INGVAR = 2, + TYPE_BELLOW_1 = 3, + TYPE_BELLOW_2 = 4, + TYPE_BELLOW_3 = 5, - //also using these as identifier for Set/GetData(), unlike normal naming NPC_KELESETH = 23953, NPC_SKARVALD = 24200, NPC_DALRONN = 24201, + NPC_INGVAR = 23954, + + NPC_FROST_TOMB = 23965, GO_BELLOW_1 = 186688, GO_BELLOW_2 = 186689, GO_BELLOW_3 = 186690, GO_FORGEFIRE_1 = 186692, GO_FORGEFIRE_2 = 186693, - GO_FORGEFIRE_3 = 186691 + 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 +{ + public: + instance_utgarde_keep(Map* pMap); + ~instance_utgarde_keep() {} + + 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; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + + protected: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + bool m_bKelesethAchievFailed; }; #endif diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp index 178782a3b1..970768402c 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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 */ @@ -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,12 +137,80 @@ CreatureAI* GetAI_boss_gortok(Creature* pCreature) return new boss_gortokAI(pCreature); } -void AddSC_boss_gortok() +bool EffectDummyCreature_spell_awaken_gortok(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - Script *newscript; + // 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; + } - newscript = new Script; - newscript->Name = "boss_gortok"; - newscript->GetAI = &GetAI_boss_gortok; - newscript->RegisterSelf(); + 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; + + 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 1d084c55dd..b3fff5bb83 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,24 +38,53 @@ 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) + + // 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}, }; /*###### @@ -66,32 +95,66 @@ struct MANGOS_DLL_DECL 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 +162,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 +170,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 +301,196 @@ CreatureAI* GetAI_boss_skadi(Creature* pCreature) return new boss_skadiAI(pCreature); } -bool AreaTrigger_at_skadi(Player* pPlayer, AreaTriggerEntry const* pAt) +/*###### +## npc_grauf +######*/ + +struct MANGOS_DLL_DECL 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->GetMotionMaster()->MoveWaypoint(); + m_uiFlightDelayTimer = 0; + } + else + m_uiFlightDelayTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_grauf(Creature* pCreature) +{ + return new npc_graufAI(pCreature); +} + +/*###### +## 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; @@ -134,15 +498,20 @@ bool AreaTrigger_at_skadi(Player* pPlayer, AreaTriggerEntry const* pAt) void AddSC_boss_skadi() { - Script *newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_skadi"; + pNewScript->GetAI = &GetAI_boss_skadi; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_skadi"; - newscript->GetAI = &GetAI_boss_skadi; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_grauf"; + pNewScript->GetAI = &GetAI_npc_grauf; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "at_skadi"; - newscript->pAreaTrigger = &AreaTrigger_at_skadi; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "at_skadi"; + pNewScript->pAreaTrigger = &AreaTrigger_at_skadi; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp index 6354f732c1..18ff1c7477 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,18 +45,29 @@ 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, }; /*###### @@ -67,13 +78,13 @@ struct MANGOS_DLL_DECL 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,15 +152,13 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (m_creature->HasSplineFlag(SPLINEFLAG_FLYING)) - m_creature->RemoveSplineFlag(SPLINEFLAG_FLYING); - + m_creature->SetLevitate(false); DoScriptText(SAY_AGGRO, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_ARTHAS_IMAGE) { @@ -142,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; @@ -171,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); @@ -184,13 +221,11 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI float fX, fZ, fY; m_creature->GetRespawnCoord(fX, fY, fZ); - m_creature->AddSplineFlag(SPLINEFLAG_FLYING); - - m_creature->SendMonsterMoveWithSpeed(fX, fY, fZ + 5.0f, m_uiIntroTimer); - m_creature->GetMap()->CreatureRelocation(m_creature, fX, fY, fZ + 5.0f, m_creature->GetOrientation()); + m_creature->SetLevitate(true); + 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()) { @@ -203,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); @@ -212,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: @@ -225,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; @@ -239,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(); } }; @@ -248,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) @@ -261,15 +357,15 @@ bool AreaTrigger_at_svala_intro(Player* pPlayer, AreaTriggerEntry const* pAt) void AddSC_boss_svala() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_svala"; - newscript->GetAI = &GetAI_boss_svala; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_svala"; + pNewScript->GetAI = &GetAI_boss_svala; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "at_svala_intro"; - newscript->pAreaTrigger = &AreaTrigger_at_svala_intro; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "at_svala_intro"; + pNewScript->pAreaTrigger = &AreaTrigger_at_svala_intro; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp index 30613e2b9f..a4751d8b74 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,7 +35,67 @@ 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} }; /*###### @@ -47,24 +108,71 @@ struct MANGOS_DLL_DECL boss_ymironAI : public ScriptedAI { 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,12 +406,30 @@ 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 *newscript; + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ymiron"; + pNewScript->GetAI = &GetAI_boss_ymiron; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_ymiron"; - newscript->GetAI = &GetAI_boss_ymiron; - newscript->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 937d472d1d..aa7c6dd8d0 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 - 2010 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software; you can redistribute it and/or modify * 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,121 +24,311 @@ EndScriptData */ #include "precompiled.h" #include "utgarde_pinnacle.h" -struct MANGOS_DLL_DECL instance_pinnacle : public ScriptedInstance +instance_pinnacle::instance_pinnacle(Map* pMap) : ScriptedInstance(pMap), + m_uiGortokOrbTimer(0), + m_uiGortokOrbPhase(0) { - instance_pinnacle(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; +void instance_pinnacle::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - uint64 m_uiSkadiDoorGUID; + for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS; ++i) + m_abAchievCriteria[i] = false; +} - void Initialize() +void instance_pinnacle::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + 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; + } +} - m_uiSkadiDoorGUID = 0; +void instance_pinnacle::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_DOOR_SKADI: + if (m_auiEncounter[TYPE_SKADI] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + 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 OnObjectCreate(GameObject* pGo) +void instance_pinnacle::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(pGo->GetEntry()) - { - case GO_DOOR_SKADI: - m_uiSkadiDoorGUID = pGo->GetGUID(); + 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]); - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); + m_uiGortokOrbTimer = 2000; + } + } + else if (uiData == FAIL) + { + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + { + if (!pOrb->isAlive()) + pOrb->Respawn(); + else + pOrb->RemoveAllAuras(); - break; - } + // 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: + // 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: + script_error_log("Instance Pinnacle: SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; } - void SetData(uint32 uiType, uint32 uiData) + // Saving also SPECIAL for this instance + if (uiData == DONE || uiData == SPECIAL) { - debug_log("SD2: Instance Pinnacle: SetData received for type %u with data %u", uiType, uiData); + OUT_SAVE_INST_DATA; - switch(uiType) - { - case TYPE_SVALA: - m_auiEncounter[0] = uiData; - break; - case TYPE_GORTOK: - m_auiEncounter[1] = uiData; - break; - case TYPE_SKADI: - if (uiData == DONE) - DoUseDoorOrButton(m_uiSkadiDoorGUID); - - m_auiEncounter[2] = uiData; - break; - case TYPE_YMIRON: - m_auiEncounter[3] = uiData; - break; - default: - error_log("SD2: Instance Pinnacle: SetData = %u for type %u does not exist/not implemented.", uiType, uiData); - break; - } + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; - //saving also SPECIAL for this instance - if (uiData == DONE || uiData == SPECIAL) - { - OUT_SAVE_INST_DATA; + m_strInstData = saveStream.str(); - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} - strInstData = saveStream.str(); +uint32 instance_pinnacle::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + return 0; +} + +void instance_pinnacle::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; } - uint32 GetData(uint32 uiType) + 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) { - switch(uiType) - { - case TYPE_SVALA: - return m_auiEncounter[0]; - case TYPE_GORTOK: - return m_auiEncounter[1]; - case TYPE_SKADI: - return m_auiEncounter[2]; - case TYPE_YMIRON: - return m_auiEncounter[3]; - } + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + 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]; - return 0; + default: + return false; } +} - const char* Save() +void instance_pinnacle::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - return strInstData.c_str(); + 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 Load(const char* chrIn) +void instance_pinnacle::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - if (!chrIn) + 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) { - OUT_LOAD_INST_DATA_FAIL; - return; - } + if (!m_uiGortokOrbPhase) + { + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + pOrb->GetMotionMaster()->MovePoint(0, aOrbPositions[1][0], aOrbPositions[1][1], aOrbPositions[1][2]); - OUT_LOAD_INST_DATA(chrIn); + 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; - std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + { + pOrb->CastSpell(pOrb, uiSpellId, false); - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - } + if (m_uiGortokOrbPhase == uiMaxOrbPhase) + pOrb->ForcedDespawn(10000); + } - OUT_LOAD_INST_DATA_COMPLETE; + m_uiGortokOrbTimer = 0; + } + ++m_uiGortokOrbPhase; + } + else + m_uiGortokOrbTimer -= uiDiff; } -}; +} InstanceData* GetInstanceData_instance_pinnacle(Map* pMap) { @@ -147,10 +337,10 @@ InstanceData* GetInstanceData_instance_pinnacle(Map* pMap) void AddSC_instance_pinnacle() { - Script* newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "instance_pinnacle"; - newscript->GetInstanceData = &GetInstanceData_instance_pinnacle; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "instance_pinnacle"; + pNewScript->GetInstanceData = &GetInstanceData_instance_pinnacle; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h b/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h index 5ab6aa4108..1d6f7112c6 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h @@ -1,26 +1,115 @@ -/* Copyright (C) 2006 - 2010 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_NEXUS_H -#define DEF_NEXUS_H +#ifndef DEF_UTG_PINNACLE_H +#define DEF_UTG_PINNACLE_H 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 +}; + +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 MANGOS_DLL_DECL instance_pinnacle : public ScriptedInstance +{ + public: + instance_pinnacle(Map* pMap); + + 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 SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + + void SetGortokEventStarter(ObjectGuid playerGuid) { m_gortokEventStarterGuid = playerGuid; } + ObjectGuid GetGortokEventStarter() { return m_gortokEventStarterGuid; } + ObjectGuid GetSkadiMobsTrigger() { return m_skadiMobsTriggerGuid; } + + 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 new file mode 100644 index 0000000000..3033d20f28 --- /dev/null +++ b/scripts/northrend/vault_of_archavon/boss_archavon.cpp @@ -0,0 +1,278 @@ +/* Copyright (C) 2006 - 2013 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_Archavon_The_Stone_Watcher +SD%Complete: 0% +SDComment: +SDCategory: Vault of Archavon +EndScriptData */ + +#include "precompiled.h" +#include "vault_of_archavon.h" + +enum +{ + SPELL_ROCK_SHARDS_LEFT_N = 58695, + SPELL_ROCK_SHARDS_LEFT_H = 60883, + SPELL_ROCK_SHARDS_RIGHT_N = 58696, + SPELL_ROCK_SHARDS_RIGHT_H = 60884, + SPELL_CRUSHING_LEAP_N = 58963, + SPELL_CRUSHING_LEAP_H = 60895, + SPELL_STOMP_N = 58663, + SPELL_STOMP_H = 60880, + SPELL_IMPALE_DMG_N = 58666, + SPELL_IMPALE_DMG_H = 60882, + SPELL_IMPALE_STUN = 50839, + SPELL_BERSERK = 47008 +}; + +struct MANGOS_DLL_DECL boss_archavonAI : public ScriptedAI +{ + boss_archavonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_fDefaultMoveSpeed = pCreature->GetSpeedRate(MOVE_RUN); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + float m_fDefaultMoveSpeed; + uint32 m_uiEvadeCheckCooldown; + + uint32 m_uiBerserkTimer; + uint32 m_uiRockShardsTimer; + bool m_bRockShardsInProgress; + uint32 m_uiRockShardsProgressTimer; + uint32 m_uiRockShardTimer; + bool m_bRLRockShard; + ObjectGuid m_pRockShardsTargetGuid; + uint32 m_uiCrushingLeapTimer; + Unit* m_pCrushingLeapTarget; + bool m_bCrushingLeapInProgress; + uint32 m_uiCrushingLeapSecureTimer; + uint32 m_uiStompTimer; + uint32 m_uiImpaleAfterStompTimer; + bool m_bImpaleInProgress; + + void Reset() + { + m_uiEvadeCheckCooldown = 2000; + m_creature->SetSpeedRate(MOVE_RUN, m_fDefaultMoveSpeed); + m_uiBerserkTimer = 300000; + m_uiRockShardsTimer = 15000; + m_bRockShardsInProgress = false; + m_uiRockShardsProgressTimer = 3000; + m_uiRockShardTimer = 0; + m_bRLRockShard = true; + m_pRockShardsTargetGuid.Clear(); + m_uiCrushingLeapTimer = 30000; + m_pCrushingLeapTarget = NULL; + m_bCrushingLeapInProgress = false; + m_uiCrushingLeapSecureTimer = 2000; + m_uiStompTimer = 45000; + m_uiImpaleAfterStompTimer = 1000; + m_bImpaleInProgress = false; + + if(m_pInstance) + m_pInstance->SetData(TYPE_ARCHAVON, NOT_STARTED); + } + + void Aggro(Unit *pWho) + { + if(m_pInstance) + m_pInstance->SetData(TYPE_ARCHAVON, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if(m_pInstance) + m_pInstance->SetData(TYPE_ARCHAVON, DONE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEvadeCheckCooldown < uiDiff) + { + if (m_creature->GetDistance2d(140.34f, -102.34f) > 80.0f) + EnterEvadeMode(); + m_uiEvadeCheckCooldown = 2000; + } + else + m_uiEvadeCheckCooldown -= uiDiff; + + if (m_bImpaleInProgress) + { + if (m_uiImpaleAfterStompTimer < uiDiff) + { + if (Unit* pTarget = m_creature->getVictim()) + { + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_IMPALE_DMG_N : SPELL_IMPALE_DMG_H); + pTarget->CastSpell(pTarget, SPELL_IMPALE_STUN, true); + } + m_bImpaleInProgress = false; + } + else + { + m_uiImpaleAfterStompTimer -= uiDiff; + return; + } + } + + if (m_bCrushingLeapInProgress) + { + if (m_pCrushingLeapTarget) + { + if (m_pCrushingLeapTarget->isDead() || !m_pCrushingLeapTarget->IsInWorld() && !m_pCrushingLeapTarget->IsInMap(m_creature)) + { + m_bCrushingLeapInProgress = false; + return; + } + } + else + { + m_bCrushingLeapInProgress = false; + return; + } + if ((m_uiCrushingLeapSecureTimer < uiDiff) || (m_pCrushingLeapTarget && m_creature->IsWithinDist(m_pCrushingLeapTarget, 5.0f))) + { + m_creature->getThreatManager().addThreat(m_pCrushingLeapTarget, -100000000.0f); + m_creature->SetSpeedRate(MOVE_RUN, m_fDefaultMoveSpeed); + DoCastSpellIfCan(m_pCrushingLeapTarget, m_bIsRegularMode ? SPELL_CRUSHING_LEAP_N : SPELL_CRUSHING_LEAP_H, true); + m_bCrushingLeapInProgress = false; + } + else + m_uiCrushingLeapSecureTimer -= uiDiff; + + return; + } + + if (m_bRockShardsInProgress) + { + if (m_uiRockShardsProgressTimer < uiDiff) + { + m_bRockShardsInProgress = false; + if (!m_pRockShardsTargetGuid.IsEmpty()) + if (Unit* m_pRockShardsTarget = m_creature->GetMap()->GetUnit(m_pRockShardsTargetGuid)) + m_creature->getThreatManager().addThreat(m_pRockShardsTarget, -100000000.0f); + return; + } + else + m_uiRockShardsProgressTimer -= uiDiff; + + if (m_uiRockShardTimer < uiDiff) + { + if (Unit* m_pRockShardsTarget = m_creature->GetMap()->GetUnit(m_pRockShardsTargetGuid)) + if (m_pRockShardsTarget->isAlive()) + { + DoCast(m_pRockShardsTarget, m_bIsRegularMode ? (m_bRLRockShard ? SPELL_ROCK_SHARDS_LEFT_N : SPELL_ROCK_SHARDS_RIGHT_N) : (m_bRLRockShard ? SPELL_ROCK_SHARDS_LEFT_H : SPELL_ROCK_SHARDS_RIGHT_H)); + m_bRLRockShard = !m_bRLRockShard; + } + m_uiRockShardTimer = 100; + } + else + m_uiRockShardsTimer -= uiDiff; + + return; + } + + if (m_uiRockShardsTimer < uiDiff) + { + m_bRockShardsInProgress = true; + m_uiRockShardsProgressTimer = 3000; + m_bRLRockShard = true; + if (Unit* m_pRockShardsTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + m_pRockShardsTargetGuid = m_pRockShardsTarget->GetObjectGuid(); + m_creature->getThreatManager().addThreat(m_pRockShardsTarget, 100000000.0f); + } + m_uiRockShardsTimer = 15000+rand()%15000; + return; + } + else + m_uiRockShardsTimer -= uiDiff; + + if (m_uiCrushingLeapTimer < uiDiff) + { + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + std::list lTargets; + for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + { + Unit *pTemp = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); + if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER && !m_creature->IsWithinDist(pTemp, 10.0f) && m_creature->IsWithinDist(pTemp, 80.0f)) + lTargets.push_back(pTemp); + } + m_pCrushingLeapTarget = NULL; + if (!lTargets.empty()) + { + std::list::iterator pTarget = lTargets.begin(); + advance(pTarget, (rand() % lTargets.size())); + m_pCrushingLeapTarget = *pTarget; + if (m_pCrushingLeapTarget) + { + m_creature->MonsterSay(m_pCrushingLeapTarget->GetName(), LANG_UNIVERSAL); + m_creature->getThreatManager().addThreat(m_pCrushingLeapTarget, 100000000.0f); + m_creature->SetSpeedRate(MOVE_RUN, m_fDefaultMoveSpeed*10.0f); + m_bCrushingLeapInProgress = true; + m_uiCrushingLeapSecureTimer = 2000; + } + } + m_uiCrushingLeapTimer = 30000+rand()%15000; + return; + } + else + m_uiCrushingLeapTimer -= uiDiff; + + if (m_uiStompTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STOMP_N : SPELL_STOMP_H); + m_uiImpaleAfterStompTimer = 1000; + m_bImpaleInProgress = true; + m_uiStompTimer = 45000+rand()%15000; + } + else + m_uiStompTimer -= uiDiff; + + if (m_uiBerserkTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_BERSERK); + m_uiBerserkTimer = 60000; + } + else + m_uiBerserkTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_archavon(Creature *pCreature) +{ + return new boss_archavonAI (pCreature); +}; + +void AddSC_boss_archavon() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_archavon"; + newscript->GetAI = &GetAI_boss_archavon; + newscript->RegisterSelf(); +}; diff --git a/scripts/northrend/vault_of_archavon/boss_emalon.cpp b/scripts/northrend/vault_of_archavon/boss_emalon.cpp new file mode 100644 index 0000000000..4075280cd9 --- /dev/null +++ b/scripts/northrend/vault_of_archavon/boss_emalon.cpp @@ -0,0 +1,444 @@ +/* Copyright (C) 2006 - 2013 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_Emalon_The_Storm_Watcher +SD%Complete: 0% +SDComment: +SDCategory: Vault of Archavon +EndScriptData */ + +#include "precompiled.h" +#include "vault_of_archavon.h" + +enum +{ + // Emalon spells + SPELL_CHAIN_LIGHTNING_N = 64213, + SPELL_CHAIN_LIGHTNING_H = 64215, + SPELL_LIGHTNING_NOVA_N = 64216, + SPELL_LIGHTNING_NOVA_H = 65279, + SPELL_OVERCHARGE = 64379, //This spell is used by Time Warder, and temporary by Emalon, because 64218 is bugged + SPELL_BERSERK = 26662, + + // Tempest Minion spells + SPELL_SHOCK = 64363, + SPELL_OVERCHARGED_BLAST = 64219, + SPELL_OVERCHARGED = 64217 +}; + +/*###### +## npc_tempest_minion +######*/ + +struct MANGOS_DLL_DECL npc_tempest_minionAI : public ScriptedAI +{ + npc_tempest_minionAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_fDefaultX = m_creature->GetPositionX(); + m_fDefaultY = m_creature->GetPositionY(); + m_fDefaultZ = m_creature->GetPositionZ(); + m_fDefaultO = m_creature->GetOrientation(); + Reset(); + } + + ScriptedInstance* m_pInstance; + uint32 m_uiEvadeCheckCooldown; + + uint32 m_uiShockTimer; + uint32 m_uiRespawnTimer; + uint32 m_uiOverchargedStacksCheckTimer; + bool m_bDead; + bool m_bTimeToDie; + float m_fDefaultX; + float m_fDefaultY; + float m_fDefaultZ; + float m_fDefaultO; + + void Init() + { + m_uiEvadeCheckCooldown = 2000; + m_uiShockTimer = 8000+rand()%4000; + m_bDead = false; + m_bTimeToDie = false; + m_uiRespawnTimer = 4000; + m_uiOverchargedStacksCheckTimer = 2000; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetVisibility(VISIBILITY_ON); + } + + void Reset() + { + Init(); + } + + void Aggro(Unit* pWho) + { + m_creature->CallForHelp(80.0f); + } + + void FakeDeath() + { + m_bDead = true; + m_bTimeToDie = false; + m_uiRespawnTimer = 4000; + 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->SetUInt64Value(UNIT_FIELD_TARGET,0); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + m_creature->GetMap()->CreatureRelocation(m_creature, m_fDefaultX, m_fDefaultY, m_fDefaultZ, m_fDefaultO); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage < m_creature->GetHealth()) + return; + + if (m_pInstance && (m_pInstance->GetData(TYPE_EMALON) != DONE)) + { + uiDamage = 0; + FakeDeath(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEvadeCheckCooldown < uiDiff) + { + Creature* pEmalon = m_pInstance->GetSingleCreatureFromStorage(NPC_EMALON); + if ((pEmalon && pEmalon->IsInEvadeMode()) || (m_creature->GetDistance2d(-219.119f, -289.037f) > 80.0f)) + { + EnterEvadeMode(); + return; + } + m_uiEvadeCheckCooldown = 2000; + } + else + m_uiEvadeCheckCooldown -= uiDiff; + + if (m_bTimeToDie) + { + FakeDeath(); + return; + } + + if (m_bDead) + { + if (m_uiRespawnTimer < uiDiff) + { + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->SetVisibility(VISIBILITY_OFF); + Init(); + m_creature->MonsterTextEmote("%s appears to defend Emalon!", NULL, true); + m_creature->SetInCombatWithZone(); + DoResetThreat(); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->GetMotionMaster()->MoveChase(pTarget); + } + else + m_uiRespawnTimer -= uiDiff; + + return; + } + + if (m_uiOverchargedStacksCheckTimer < uiDiff) + { + m_uiOverchargedStacksCheckTimer = 2000; + Aura* pAuraOvercharged = m_creature->GetAura(SPELL_OVERCHARGED, EFFECT_INDEX_0); + if(pAuraOvercharged && pAuraOvercharged->GetStackAmount() >= 10) + { + DoCastSpellIfCan(m_creature, SPELL_OVERCHARGED_BLAST); + m_bTimeToDie = true; + return; + } + } + else + m_uiOverchargedStacksCheckTimer -= uiDiff; + + if (m_uiShockTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCK); + m_uiShockTimer = 8000+rand()%4000; + } + else + m_uiShockTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## boss_emalon +######*/ + +struct MANGOS_DLL_DECL boss_emalonAI : public ScriptedAI +{ + boss_emalonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + uint32 m_uiEvadeCheckCooldown; + + Creature* m_auiTempestMinion[4]; + uint32 m_uiChainLightningTimer; + uint32 m_uiChainLightningCount; + uint32 m_uiLightningNovaTimer; + uint32 m_uiOverchargeTimer; + uint32 m_uiEnrageTimer; + + void Reset() + { + m_uiEvadeCheckCooldown = 2000; + m_uiChainLightningTimer = 15000; + m_uiChainLightningCount = 0; + m_uiLightningNovaTimer = 20000; + m_uiOverchargeTimer = 45000; + m_uiEnrageTimer = 360000; + + if (m_pInstance) + { + m_auiTempestMinion[0] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_1); + m_auiTempestMinion[1] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_2); + m_auiTempestMinion[2] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_3); + m_auiTempestMinion[3] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_4); + } + + for (uint8 i=0; i<4; ++i) + { + Creature* pMinion = m_auiTempestMinion[i]; + if (pMinion && pMinion->isDead()) + pMinion->Respawn(); + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_EMALON, NOT_STARTED); + } + + void Aggro(Unit* pWho) + { + if (m_pInstance) + { + m_auiTempestMinion[0] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_1); + m_auiTempestMinion[1] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_2); + m_auiTempestMinion[2] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_3); + m_auiTempestMinion[3] = m_pInstance->GetSingleCreatureFromStorage(DATA_TEMPEST_MINION_4); + } + + m_creature->CallForHelp(80.0f); + + if (m_pInstance) + m_pInstance->SetData(TYPE_EMALON, IN_PROGRESS); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_EMALON, DONE); + for (uint8 i=0; i<4; ++i) + { + Creature* pMinion = m_auiTempestMinion[i]; + if (pMinion) + pMinion->DealDamage(pMinion, pMinion->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_uiEvadeCheckCooldown < uiDiff) + { + if (m_creature->GetDistance2d(-219.119f, -289.037f) > 80.0f) + EnterEvadeMode(); + m_creature->CallForHelp(80.0f); + m_uiEvadeCheckCooldown = 2000; + } + else + m_uiEvadeCheckCooldown -= uiDiff; + + if (m_uiOverchargeTimer < uiDiff) + { + Creature* pMinion = m_auiTempestMinion[rand()%4]; + if(pMinion && pMinion->isAlive()) + { + m_creature->MonsterTextEmote("%s overcharges Tempest Minion!",NULL, true); + pMinion->SetHealth(pMinion->GetMaxHealth()); + pMinion->CastSpell(pMinion, SPELL_OVERCHARGE, false); + } + m_uiOverchargeTimer = 45000; + } + else + m_uiOverchargeTimer -= uiDiff; + + if (m_uiChainLightningTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING_N : SPELL_CHAIN_LIGHTNING_H); + m_uiChainLightningTimer = 10000 + rand()%15000; + } + else + m_uiChainLightningTimer -= uiDiff; + + if (m_uiLightningNovaTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_NOVA_N : SPELL_LIGHTNING_NOVA_H); + m_uiLightningNovaTimer = 45000; + } + else + m_uiLightningNovaTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_BERSERK); + m_uiEnrageTimer = 30000; + } + else + m_uiEnrageTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_tempest_warder +######*/ + +struct MANGOS_DLL_DECL npc_tempest_warderAI : public ScriptedAI +{ + npc_tempest_warderAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiShockTimer; + bool m_bOvercharged; + uint32 m_uiOverchargedStacksCheckTimer; + bool m_bTimeToDie; + + void Reset() + { + m_uiShockTimer = 8000+rand()%4000; + m_bOvercharged = false; + uint32 m_uiOverchargedStacksCheckTimer = 2000; + m_bTimeToDie = false; + } + + void Aggro(Unit* pWho) {} + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bTimeToDie) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + return; + } + + if (!m_bOvercharged && ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 37)) + { + DoCastSpellIfCan(m_creature, SPELL_OVERCHARGE); + m_bOvercharged = true; + } + + if (m_bOvercharged) + { + if (m_uiOverchargedStacksCheckTimer < uiDiff) + { + m_uiOverchargedStacksCheckTimer = 2000; + Aura* pAuraOvercharged = m_creature->GetAura(SPELL_OVERCHARGED, EFFECT_INDEX_0); + if(pAuraOvercharged && pAuraOvercharged->GetStackAmount() >= 10) + { + DoCastSpellIfCan(m_creature, SPELL_OVERCHARGED_BLAST); + m_bTimeToDie = true; + return; + } + } + else + m_uiOverchargedStacksCheckTimer -= uiDiff; + } + + if (m_uiShockTimer < uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCK); + m_uiShockTimer = 8000+rand()%4000; + } + else + m_uiShockTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_emalonAI(Creature* pCreature) +{ + return new boss_emalonAI(pCreature); +} + +CreatureAI* GetAI_npc_tempest_minionAI(Creature* pCreature) +{ + return new npc_tempest_minionAI(pCreature); +} + +CreatureAI* GetAI_npc_tempest_warderAI(Creature* pCreature) +{ + return new npc_tempest_warderAI(pCreature); +} + +void AddSC_boss_emalon() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_emalon"; + newscript->GetAI = &GetAI_boss_emalonAI; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_tempest_minion"; + newscript->GetAI = &GetAI_npc_tempest_minionAI; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_tempest_warder"; + newscript->GetAI = &GetAI_npc_tempest_warderAI; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/vault_of_archavon/boss_koralon.cpp b/scripts/northrend/vault_of_archavon/boss_koralon.cpp new file mode 100644 index 0000000000..3441297bd8 --- /dev/null +++ b/scripts/northrend/vault_of_archavon/boss_koralon.cpp @@ -0,0 +1,140 @@ +/* Copyright (C) 2006 - 2013 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_koralon +SD%Complete: 50% +SDComment: +SDCategory: Vault of Archavon +EndScriptData */ + +#include "precompiled.h" +#include "vault_of_archavon.h" + +#define SP_BURNING_FURY_AURA 66895 +#define SP_BURNING_FURY_AURA2 68168 +#define SP_BURNING_FURY_EFFECT 66721 + +#define SP_BURNING_BREATH 66665 +#define H_SP_BURNING_BREATH 67328 //DBM +#define SP_BB_EFFECT 66670 +#define H_SP_BB_EFFECT 67329 + +#define SP_METEOR_FISTS 66725 //DBM +#define H_SP_METEOR_FISTS 68161 +#define SP_METEOR_FISTS_EFF 66765 +#define H_SP_METEOR_FISTS_EFF 67333 + +#define SP_CINDER 66684 +#define H_SP_CINDER 67332 + +struct MANGOS_DLL_DECL boss_koralonAI : public ScriptedAI +{ + boss_koralonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Regular = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* pInstance; + bool Regular; + uint32 BurningBreathTimer; + uint32 MeteorFistsTimer; + uint32 FlamesTimer; + + uint32 BBTickTimer; + uint32 BBTicks; + bool BB; + + void Reset() + { + BurningBreathTimer = 25000; + MeteorFistsTimer = 47000; + FlamesTimer = 15000; + + BB = false; + + if(pInstance) pInstance->SetData(TYPE_KORALON, NOT_STARTED); + } + + void Aggro(Unit *who) + { + DoCastSpellIfCan(m_creature, SP_BURNING_FURY_AURA); + + if(pInstance) pInstance->SetData(TYPE_KORALON, IN_PROGRESS); + }; + + void JustDied(Unit *killer) + { + if(pInstance) pInstance->SetData(TYPE_KORALON, DONE); + }; + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(BurningBreathTimer < diff) + { + DoCastSpellIfCan(m_creature, Regular ? SP_BURNING_BREATH : H_SP_BURNING_BREATH); + BurningBreathTimer = 45000; + + BB = true; + BBTickTimer = 1000; + BBTicks = 0; + } + else BurningBreathTimer -= diff; + + + if(FlamesTimer < diff) + { + int flames = Regular ? 3 : 5; + int i; + for(i=0; i< flames; ++i) + { + Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + if(target) DoCastSpellIfCan(target, Regular ? SP_CINDER : H_SP_CINDER); + } + FlamesTimer = 20000; + } + else FlamesTimer -= diff; + + if(MeteorFistsTimer < diff) + { + DoCastSpellIfCan(m_creature->getVictim(), SP_METEOR_FISTS_EFF); + MeteorFistsTimer = 45000; + } + else MeteorFistsTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_koralonAI(Creature* pCreature) +{ + return new boss_koralonAI(pCreature); +} + +void AddSC_boss_koralon() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_koralon"; + newscript->GetAI = &GetAI_boss_koralonAI; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/vault_of_archavon/boss_toravon.cpp b/scripts/northrend/vault_of_archavon/boss_toravon.cpp new file mode 100644 index 0000000000..8b52cf9846 --- /dev/null +++ b/scripts/northrend/vault_of_archavon/boss_toravon.cpp @@ -0,0 +1,138 @@ +/* Copyright (C) 2006 - 2013 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: Toravon the Ice Watcher +SDAuthor: Lutik +SD%Complete: 0% +SDComment: +SDCategory: Vault of Archavon +EndScriptData */ + +#include "precompiled.h" +#include "vault_of_archavon.h" + +enum +{ + SP_WHITEOUT = 72034, + H_SP_WHITEOUT = 72096, + SP_FREEZING_GROUND = 72090, + H_SP_FREEZING_GROUND = 72104, + SP_FROZEN_MALLET = 71993, + FROZEN_ORB_AURA = 72081, + + CR_FROZEN_ORB = 38456 +}; + + +struct MANGOS_DLL_DECL boss_toravonAI : public ScriptedAI +{ + boss_toravonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + orbsNum = m_bIsRegularMode ? 1 : 3; + pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + bool m_bIsRegularMode; + ScriptedInstance *pInstance; + + int orbsNum; + uint32 WhiteoutTimer; + uint32 OrbsTimer; + uint32 FreezeTimer; + + void Reset() + { + WhiteoutTimer = 40000; + OrbsTimer = 15000; + FreezeTimer = 20000 + rand()%5000; + + if(pInstance) + pInstance->SetData(TYPE_TORAVON, NOT_STARTED); + } + + void Aggro(Unit *who) + { + DoCastSpellIfCan(m_creature, SP_FROZEN_MALLET); + + if(pInstance) + pInstance->SetData(TYPE_TORAVON, IN_PROGRESS); + } + + void JustDied(Unit *killer) + { + if(pInstance) + pInstance->SetData(TYPE_TORAVON, DONE); + } + + void JustSummoned(Creature *orb) + { + orb->CastSpell(orb, FROZEN_ORB_AURA, false); + orb->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 diff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(WhiteoutTimer < diff) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SP_WHITEOUT : H_SP_WHITEOUT); + WhiteoutTimer = 40000; + } + else + WhiteoutTimer -= diff; + + if(OrbsTimer < diff) + { + for(int i=0; iSelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->SummonCreature(CR_FROZEN_ORB, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 3000); + } + OrbsTimer = 40000; + } + else + OrbsTimer -= diff; + + if(FreezeTimer < diff) + { + DoCastSpellIfCan(m_creature, SP_FREEZING_GROUND); + FreezeTimer = 20000 + rand()%5000; + } + else + FreezeTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_toravon(Creature *pCreature) +{ + return new boss_toravonAI (pCreature); +}; + +void AddSC_boss_toravon() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "boss_toravon"; + newscript->GetAI = &GetAI_boss_toravon; + newscript->RegisterSelf(); +}; diff --git a/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp b/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp new file mode 100644 index 0000000000..6d34ff89fe --- /dev/null +++ b/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp @@ -0,0 +1,168 @@ +/* Copyright (C) 2006 - 2013 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: Instance_Vault_of_Archavon +SD%Complete: 0 +SDComment: +SDCategory: Vault of Archavon +EndScriptData */ + +#include "precompiled.h" +#include "vault_of_archavon.h" + +struct MANGOS_DLL_DECL instance_vault_of_archavon : public ScriptedInstance +{ + instance_vault_of_archavon(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string strInstData; + + uint8 m_uiMinion; + + void Initialize() override + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + m_uiMinion = 0; + } + + void OnCreatureCreate(Creature* pCreature) override + { + switch (pCreature->GetEntry()) + { + case NPC_TORAVON: + case NPC_ARCHAVON: + case NPC_EMALON: + case NPC_KORALON: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_TEMPEST_MINION: + switch (m_uiMinion) + { + case 0: + case 1: + case 2: + case 3: + m_mNpcEntryGuidStore[m_uiMinion + DATA_TEMPEST_MINION_1] = pCreature->GetObjectGuid(); + ++m_uiMinion; + break; + case 4: + default: + m_uiMinion = 0; + break; + } + break; + } + } + + void SetData(uint32 uiType, uint32 uiData) override + { + switch (uiType) + { + case TYPE_ARCHAVON: + m_auiEncounter[0] = uiData; + break; + case TYPE_EMALON: + m_auiEncounter[1] = uiData; + break; + case TYPE_KORALON: + m_auiEncounter[2] = uiData; + break; + case TYPE_TORAVON: + m_auiEncounter[3] = 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]; + + strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + uint32 GetData(uint32 uiType) const override + { + switch (uiType) + { + case TYPE_ARCHAVON: + return m_auiEncounter[0]; + case TYPE_EMALON: + return m_auiEncounter[1]; + case TYPE_KORALON: + return m_auiEncounter[2]; + case TYPE_TORAVON: + return m_auiEncounter[3]; + } + return 0; + } + + + const char* Save() const override + { + return strInstData.c_str(); + } + + void Load(const char* in) + { + if (!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + + std::istringstream loadStream(in); + 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; + } + + bool IsEncounterInProgress() const override + { + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + return false; + } +}; + +InstanceData* GetInstanceData_instance_vault_of_archavon(Map* pMap) +{ + return new instance_vault_of_archavon(pMap); +} + +void AddSC_instance_vault_of_archavon() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "instance_vault_of_archavon"; + newscript->GetInstanceData = &GetInstanceData_instance_vault_of_archavon; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/vault_of_archavon/vault_of_archavon.h b/scripts/northrend/vault_of_archavon/vault_of_archavon.h new file mode 100644 index 0000000000..ec1ef2820b --- /dev/null +++ b/scripts/northrend/vault_of_archavon/vault_of_archavon.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_VAULT_OF_ARCHAVON_H +#define DEF_VAULT_OF_ARCHAVON_H + +enum +{ + MAX_ENCOUNTER = 4, + + TYPE_ARCHAVON = 0, + TYPE_EMALON = 1, + TYPE_KORALON = 2, + TYPE_TORAVON = 3, + + DATA_TEMPEST_MINION_1 = 101, + DATA_TEMPEST_MINION_2 = 102, + DATA_TEMPEST_MINION_3 = 103, + DATA_TEMPEST_MINION_4 = 104, + + + NPC_TORAVON = 38433, + NPC_ARCHAVON = 31125, + NPC_EMALON = 33993, + NPC_KORALON = 35013, + NPC_TEMPEST_MINION = 33998, +}; + +#endif diff --git a/scripts/northrend/violet_hold/boss_cyanigosa.cpp b/scripts/northrend/violet_hold/boss_cyanigosa.cpp new file mode 100644 index 0000000000..850f569137 --- /dev/null +++ b/scripts/northrend/violet_hold/boss_cyanigosa.cpp @@ -0,0 +1,196 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for 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_cyanigosa +SDAuthor: ckegg +SD%Complete: 0 +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + +enum +{ + SAY_AGGRO = -1608046, + SAY_SLAY_1 = -1608051, + SAY_SLAY_2 = -1608052, + SAY_SLAY_3 = -1608053, + SAY_DEATH = -1608054, + SAY_SPAWN = -1608045, + SAY_DISRUPTION = -1608050, + SAY_BREATH_ATTACK = -1608047, + SAY_SPECIAL_ATTACK_1 = -1608048, + SAY_SPECIAL_ATTACK_2 = -1608049, + + SPELL_ARCANE_VACUM = 58694, + SPELL_BLIZZARD = 58693, + SPELL_BLIZZARD_H = 59369, + SPELL_MANA_DESTRUCTION = 59374, + SPELL_TAIL_SWEEP = 58690, + SPELL_TAIL_SWEEP_H = 59283, + SPELL_UNCONTROLLABLE_ENERGY = 58688, + SPELL_UNCONTROLLABLE_ENERGY_H = 59281, + SPELL_CYANIGOSA_TRANSFORM = 58668, +}; + +struct MANGOS_DLL_DECL boss_cyanigosaAI : public ScriptedAI +{ + boss_cyanigosaAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + + bool m_bIsRegularMode; + + uint32 m_uiTailSweep_Timer; + uint32 m_uiManaDestruction_Timer; + uint32 m_uiBlizzard_Timer; + uint32 m_uiUncontrollableEnergy_Timer; + uint32 m_uiArcaneVacuum_Timer; + bool MovementStarted; + + void Reset() + { + m_uiUncontrollableEnergy_Timer = urand(15000, 16000); + m_uiManaDestruction_Timer = urand(5000, 6000); + m_uiBlizzard_Timer = urand(20000, 25000); + m_uiTailSweep_Timer = urand(10000, 11000); + m_uiArcaneVacuum_Timer = urand(28000, 33000); + MovementStarted = false; + m_creature->SetInCombatWithZone(); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_CYANIGOSA, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + } + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_AGGRO, m_creature); + DoCast(m_creature, SPELL_CYANIGOSA_TRANSFORM); + m_pInstance->SetData(TYPE_CYANIGOSA, IN_PROGRESS); + } + + void UpdateAI(const uint32 uiDiff) override + { + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiUncontrollableEnergy_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_UNCONTROLLABLE_ENERGY : SPELL_UNCONTROLLABLE_ENERGY_H); + m_uiUncontrollableEnergy_Timer = urand(15000, 16000); + } + else + m_uiUncontrollableEnergy_Timer -= uiDiff; + + if (m_uiManaDestruction_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_MANA_DESTRUCTION); + m_uiManaDestruction_Timer = urand(8000, 13000); + } + else + m_uiManaDestruction_Timer -= uiDiff; + + if (m_uiBlizzard_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsRegularMode ? SPELL_BLIZZARD: SPELL_BLIZZARD_H ); + m_uiBlizzard_Timer = urand(20000, 25000); + } + else + m_uiBlizzard_Timer -= uiDiff; + + if (m_uiArcaneVacuum_Timer < uiDiff) + { + DoCast(m_creature, SPELL_ARCANE_VACUM); + 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) + if (i->getSource()->isAlive()) + DoTeleportPlayer(i->getSource(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), i->getSource()->GetOrientation()); + } + DoResetThreat(); + m_uiArcaneVacuum_Timer = urand(28000, 33000); + } + else + m_uiArcaneVacuum_Timer -= uiDiff; + + if (m_uiTailSweep_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_TAIL_SWEEP : SPELL_TAIL_SWEEP_H); + m_uiTailSweep_Timer = urand(10000, 11000); + } + else + m_uiTailSweep_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_RIFT, DONE); + m_pInstance->SetData(TYPE_EVENT, DONE); + m_pInstance->SetData(TYPE_CYANIGOSA, DONE); + } + } + + 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; + case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + } + } +}; + +CreatureAI* GetAI_boss_cyanigosa(Creature* pCreature) +{ + return new boss_cyanigosaAI (pCreature); +} + +void AddSC_boss_cyanigosa() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_cyanigosa"; + newscript->GetAI = &GetAI_boss_cyanigosa; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/violet_hold/boss_erekem.cpp b/scripts/northrend/violet_hold/boss_erekem.cpp new file mode 100644 index 0000000000..2a883c75d4 --- /dev/null +++ b/scripts/northrend/violet_hold/boss_erekem.cpp @@ -0,0 +1,429 @@ +/* Copyright (C) 2006 - 2013 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_erekem +SDAuthor: ckegg +SD%Complete: 50% +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + +enum +{ + SAY_AGGRO = -1608012, + SAY_SLAY_1 = -1608066, + SAY_SLAY_2 = -1608067, + SAY_SLAY_3 = -1608068, + SAY_DEATH = -1608018, + SAY_SPAWN = -1608008, + SAY_ADD_KILED = -1608013, + SAY_BOTH_ADDS_KILED = -1608014, + + SPELL_BLOODLUST = 54516, + SPELL_BREAK_BONDS = 59463, + SPELL_CHAIN_HEAL = 54481, + SPELL_CHAIN_HEAL_H = 59473, + SPELL_EARTH_SHIELD = 54479, + SPELL_EARTH_SHIELD_H = 59471, + SPELL_EARTH_SHOCK = 54511, + SPELL_LIGHTNING_BOLT = 53044, + SPELL_STORMSTRIKE = 51876, + + SPELL_GUSHING_WOUND = 39215, + SPELL_HOWLING_SCREECH = 54462, + SPELL_STRIKE = 14516, +}; + +struct MANGOS_DLL_DECL boss_erekemAI : public ScriptedAI +{ + boss_erekemAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + + bool m_bIsRegularMode; + bool m_bIsAddDead; + bool MovementStarted; + + uint32 m_uiBloodlust_Timer; + uint32 m_uiBreakBonds_Timer; + uint32 m_uiChainHeal_Timer; + uint32 m_uiEarthShield_Timer; + uint32 m_uiEarthShock_Timer; + uint32 m_uiLightningBolt_Timer; + uint32 m_uiStormstrike_Timer; + + void Reset() + { + if (!m_pInstance) return; + + m_bIsAddDead = false; + MovementStarted = false; + m_uiLightningBolt_Timer = 2000; + m_uiEarthShield_Timer = urand(10000, 15000); + m_uiEarthShock_Timer = urand(12000, 17000); + m_uiChainHeal_Timer = urand(5000, 25000); + m_uiBreakBonds_Timer = urand(25000, 30000); + m_uiBloodlust_Timer = urand(60000, 65000); + m_uiStormstrike_Timer = urand(1000, 2000); + + std::list lUnitList; + GetCreatureListWithEntryInGrid(lUnitList, m_creature, NPC_EREKEM_GUARD, 100.0f); + if (!lUnitList.empty()) + for(std::list::iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter) + if ((*iter)) + if ((*iter)->isDead()) + (*iter)->Respawn(); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_EREKEM, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, NOT_STARTED);} + else {m_pInstance->SetData(TYPE_PORTAL12, NOT_STARTED);} + } + } + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + DoScriptText(SAY_AGGRO, m_creature); + m_pInstance->SetData(TYPE_EREKEM, IN_PROGRESS); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EREKEM) != SPECIAL && m_pInstance->GetData(TYPE_EREKEM) != IN_PROGRESS) + return; + + if (!pWho || pWho == m_creature) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + + std::list lUnitList; + GetCreatureListWithEntryInGrid(lUnitList, m_creature, NPC_EREKEM_GUARD, 100.0f); + if (!lUnitList.empty()) + for(std::list::iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter) + if (*iter) + if ((*iter)->isAlive()) + { + (*iter)->AddThreat(pWho, 0.0f); + /* (*iter)->AI()->AttackStart(pWho);*/ + } + } + } + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetInCombatWithZone(); + MovementStarted = true; + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted) return; + if (id == 0) + { + MovementStarted = false; + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_EREKEM) == SPECIAL && !MovementStarted) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEarthShield_Timer < uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, m_bIsRegularMode ? SPELL_EARTH_SHIELD : SPELL_EARTH_SHIELD_H); + m_uiEarthShield_Timer = urand(25000, 30000); + } + else m_uiEarthShield_Timer -= uiDiff; + + if (m_uiEarthShock_Timer < uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_EARTH_SHOCK); + m_uiEarthShock_Timer = urand(12000, 17000); + } + else m_uiEarthShock_Timer -= uiDiff; + + if (m_uiChainHeal_Timer < uiDiff) + { + //m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, m_bIsRegularMode ? SPELL_CHAIN_HEAL : SPELL_CHAIN_HEAL_H); + m_uiChainHeal_Timer = urand(5000, 25000); + } + else m_uiChainHeal_Timer -= uiDiff; + + if (m_uiBreakBonds_Timer < uiDiff) + { + m_creature->InterruptNonMeleeSpells(false); + DoCast(m_creature, SPELL_BREAK_BONDS); + m_uiBreakBonds_Timer = urand(25000, 30000); + } + else m_uiBreakBonds_Timer -= uiDiff; + + if (!m_bIsAddDead) + { + if (m_uiLightningBolt_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_LIGHTNING_BOLT); + m_uiLightningBolt_Timer = 2000; + } + else m_uiLightningBolt_Timer -= uiDiff; + } + else + { + if (m_uiStormstrike_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_STORMSTRIKE); + m_uiStormstrike_Timer = 1000; + } + else m_uiStormstrike_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) { + m_pInstance->SetData(TYPE_EREKEM, DONE); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, DONE);} + else {m_pInstance->SetData(TYPE_PORTAL12, DONE);} + + } + } + + 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; + case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + } + } +}; + +struct MANGOS_DLL_DECL npc_erekem_guardAI : public ScriptedAI +{ + npc_erekem_guardAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + ScriptedInstance *m_pInstance; + + uint32 m_uiGushingWound_Timer; + uint32 m_uiHowlingScreech_Timer; + uint32 m_uiStrike_Timer; + uint32 m_uiBloodlust_Timer; + bool MovementStarted; + + void Reset() + { + m_uiGushingWound_Timer = urand(5000, 10000); + m_uiBloodlust_Timer = urand(25000, 30000); + m_uiHowlingScreech_Timer = urand(12000, 15000); + m_uiStrike_Timer = urand(10000, 11000); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = false; + + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + + /* void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_EREKEM) != SPECIAL && m_pInstance->GetData(TYPE_EREKEM) != IN_PROGRESS) + return; + + + if (!pWho || pWho == m_creature) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + }*/ + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = true; + m_creature->SetInCombatWithZone(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted) return; + if (id == 0) + { + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) return; + + if (m_pInstance->GetData(TYPE_EREKEM) == IN_PROGRESS && !MovementStarted && !m_creature->getVictim()) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiGushingWound_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_GUSHING_WOUND); + m_uiGushingWound_Timer = urand(30000, 32000); + } + else m_uiGushingWound_Timer -= uiDiff; + + if (m_uiBloodlust_Timer < uiDiff) + { + if (m_pInstance) + if (Creature* pErekem = m_pInstance->GetSingleCreatureFromStorage(DATA_EREKEM)) + if (pErekem->isAlive()) + { + pErekem->InterruptNonMeleeSpells(false); + pErekem->CastSpell(pErekem, SPELL_BLOODLUST, false); + m_uiBloodlust_Timer = urand(25000, 30000); + } + } + else m_uiBloodlust_Timer -= uiDiff; + + if (m_uiHowlingScreech_Timer < uiDiff) + { + DoCast(m_creature, SPELL_HOWLING_SCREECH); + m_uiHowlingScreech_Timer = urand(24000, 30000); + } + else m_uiHowlingScreech_Timer -= uiDiff; + + if (m_uiStrike_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_STRIKE); + m_uiStrike_Timer = urand(15000, 16000); + } + else m_uiStrike_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance) + if (Creature* pErekem = m_pInstance->GetSingleCreatureFromStorage(DATA_EREKEM)) + if (pErekem->isAlive()) + { + DoScriptText(SAY_ADD_KILED, pErekem); + // pErekem->InterruptNonMeleeSpells(false); + // pErekem->CastSpell(pErekem, SPELL_BLOODLUST, false); + ((boss_erekemAI*)pErekem->AI())->m_bIsAddDead = true; + } + } +}; + +CreatureAI* GetAI_boss_erekem(Creature* pCreature) +{ + return new boss_erekemAI (pCreature); +} + +CreatureAI* GetAI_npc_erekem_guard(Creature* pCreature) +{ + return new npc_erekem_guardAI (pCreature); +} + +void AddSC_boss_erekem() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_erekem"; + newscript->GetAI = &GetAI_boss_erekem; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_erekem_guard"; + newscript->GetAI = &GetAI_npc_erekem_guard; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/violet_hold/boss_ichoron.cpp b/scripts/northrend/violet_hold/boss_ichoron.cpp new file mode 100644 index 0000000000..5f9f0eb4bc --- /dev/null +++ b/scripts/northrend/violet_hold/boss_ichoron.cpp @@ -0,0 +1,387 @@ +/* Copyright (C) 2006 - 2013 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_ichoron +SDAuthor: ckegg +SD%Complete: 30% +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + + +enum +{ + SAY_AGGRO = -1608019, + SAY_SLAY_1 = -1608022, + SAY_SLAY_2 = -1608023, + SAY_SLAY_3 = -1608024, + SAY_DEATH = -1608026, + SAY_SPAWN = -1608069, + SAY_ENRAGE = -1608025, + SAY_SHATTER = -1608020, + SAY_BUBBLE = -1608021, + EMOTE_ICHORON_PROTECTIVE_BUBBLE = -1608028, + + 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, + + NPC_ICHOR_GLOBULE = 29321, + SPELL_SPLASH = 59516, + SPELL_WATER_GLOBULE = 54268, + SPELL_WATER_GLOBULE_2 = 54260, + GLOBULE_HEAL_H = 9000, + GLOBULE_HEAL = 5000 +}; + +struct MANGOS_DLL_DECL boss_ichoronAI : public ScriptedAI +{ + boss_ichoronAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + std::list m_lWaterElementsGuidList; + + bool m_bIsRegularMode; + bool m_bIsExploded; + bool m_bIsFrenzy; + bool MovementStarted; + + uint32 m_uiBuubleChecker_Timer; + uint32 m_uiWaterBoltVolley_Timer; + uint32 m_uiShowup_Counter; + uint32 m_uiVisible_Timer; + uint32 m_uiHealth; + + void Reset() + { + if (!m_pInstance) return; + DoCastSpellIfCan(m_creature, SPELL_PROTECTIVE_BUBBLE); + m_bIsExploded = false; + m_bIsFrenzy = false; + MovementStarted = false; + m_uiBuubleChecker_Timer = 1000; + // m_uiDrained_Timer = 1000; + m_uiVisible_Timer = 0; + m_uiWaterBoltVolley_Timer = urand(5000, 10000); + // m_uiShowup_Counter = 0; + + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DespawnWaterElements(); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_ICHORON, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, NOT_STARTED);} + else {m_pInstance->SetData(TYPE_PORTAL12, NOT_STARTED);} + } + } + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + + DoScriptText(SAY_AGGRO, m_creature); + m_pInstance->SetData(TYPE_ICHORON, IN_PROGRESS); + SetCombatMovement(true); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_ICHORON) != SPECIAL && m_pInstance->GetData(TYPE_ICHORON) != IN_PROGRESS) + return; + + + if (!pWho || pWho == m_creature) + return; + + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void WaterElementHit() + { + if (Creature* pIchoron = m_pInstance->GetSingleCreatureFromStorage(DATA_ICHORON)) + { + if(pIchoron->isAlive()) + { + pIchoron->ModifyHealth( m_bIsRegularMode ? GLOBULE_HEAL : GLOBULE_HEAL_H); + if (m_bIsExploded) + { + if(m_creature->HasAura(SPELL_DRAINED)) + { + m_creature->RemoveAurasByCasterSpell(SPELL_DRAINED,m_creature->GetObjectGuid()); + } + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->SetSpeedRate(MOVE_RUN, 0.2f); + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + pSummoned->CastSpell(pSummoned, SPELL_WATER_GLOBULE, false); + m_lWaterElementsGuidList.push_back(pSummoned->GetObjectGuid()); + } + void DespawnWaterElements() + { + if (m_lWaterElementsGuidList.empty()) + return; + + for(std::list::iterator itr = m_lWaterElementsGuidList.begin(); itr != m_lWaterElementsGuidList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + if (pTemp->isAlive()) + //pTemp->ForcedDespawn(); + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + m_lWaterElementsGuidList.clear(); + } + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = true; + m_creature->SetInCombatWithZone(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted || m_creature->GetVisibility() == VISIBILITY_OFF ) return; + if (id == 0) + { + MovementStarted = false; + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_ICHORON) == SPECIAL && !MovementStarted) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bIsFrenzy) + { + if (m_uiBuubleChecker_Timer < uiDiff) + { + if(!m_creature->HasAura(SPELL_PROTECTIVE_BUBBLE) && m_creature->GetVisibility() == VISIBILITY_ON && m_bIsExploded) + { + DoCastSpellIfCan(m_creature, SPELL_PROTECTIVE_BUBBLE); + DoScriptText(SAY_BUBBLE, m_creature); + m_bIsExploded = false; + m_uiBuubleChecker_Timer = 3000; + } + if(!m_creature->HasAura(SPELL_PROTECTIVE_BUBBLE) && m_creature->GetVisibility() == VISIBILITY_ON && !m_bIsExploded) + { + DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_WATER_BLAST : SPELL_WATER_BLAST_H); + + for(uint8 i = 0; i < 10; i++) + { + int tmp = urand(0, 5); + m_creature->SummonCreature(NPC_ICHOR_GLOBULE, PortalLoc[tmp].x, PortalLoc[tmp].y, PortalLoc[tmp].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + DoScriptText(EMOTE_ICHORON_PROTECTIVE_BUBBLE, m_creature); + //DoScriptText(SAY_SHATTER, m_creature); + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth()*0.25, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->SetVisibility(VISIBILITY_OFF); + m_bIsExploded = true; + m_uiVisible_Timer = 15000; + } + + } + else m_uiBuubleChecker_Timer -= uiDiff; + + if(m_creature->GetVisibility() == VISIBILITY_OFF && m_uiVisible_Timer < uiDiff) + { + m_creature->SetVisibility(VISIBILITY_ON); + m_uiVisible_Timer = 3000; + } + else m_uiVisible_Timer -= uiDiff; + + } + if (m_creature->GetVisibility() == VISIBILITY_OFF && !m_creature->HasAura(SPELL_DRAINED) ) + { + DoCastSpellIfCan(m_creature, SPELL_DRAINED); + } + + if (m_creature->GetVisibility() == VISIBILITY_ON ) + { + if (m_uiWaterBoltVolley_Timer < uiDiff) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WATER_BOLT_VOLLEY : SPELL_WATER_BOLT_VOLLEY_H); + m_uiWaterBoltVolley_Timer = urand(15000, 20000); + } + else m_uiWaterBoltVolley_Timer -= uiDiff; + + } + if (!m_bIsFrenzy && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FRENZY : SPELL_FRENZY_H); + DoScriptText(SAY_ENRAGE, m_creature); + if(m_creature->HasAura(SPELL_DRAINED)) + { + m_creature->RemoveAurasByCasterSpell(SPELL_DRAINED,m_creature->GetObjectGuid()); + } + if(m_creature->GetVisibility() == VISIBILITY_OFF){m_creature->SetVisibility(VISIBILITY_ON);} + m_bIsFrenzy = true; + } + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + DespawnWaterElements(); + + if (m_pInstance){ + m_pInstance->SetData(TYPE_ICHORON, DONE); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, DONE);} + else {m_pInstance->SetData(TYPE_PORTAL12, DONE);} + } + + if(m_creature->GetVisibility() == VISIBILITY_OFF) + m_creature->SetVisibility(VISIBILITY_ON); + } + + 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; + case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + } + } +}; + + +struct MANGOS_DLL_DECL mob_ichor_globuleAI : public ScriptedAI +{ + mob_ichor_globuleAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + ScriptedInstance *m_pInstance; + + uint32 m_uiRangeCheck_Timer; + + void Reset() + { + m_uiRangeCheck_Timer = 1000; + } + + void AttackStart(Unit* pWho) override + { + return; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiRangeCheck_Timer < uiDiff) + { + if (m_pInstance) + { + if (Creature* pIchoron = m_pInstance->GetSingleCreatureFromStorage(DATA_ICHORON)) + { + float fDistance = m_creature->GetDistance2d(pIchoron); + if (fDistance <= 2) + { + ((boss_ichoronAI*)pIchoron->AI())->WaterElementHit(); + + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + } + m_uiRangeCheck_Timer = 1000; + } + else m_uiRangeCheck_Timer -= uiDiff; + } + + void JustDied(Unit* pKiller) override + { + DoCast(m_creature, SPELL_SPLASH); + DoCast(m_creature, SPELL_WATER_GLOBULE_2); + + } +}; + +CreatureAI* GetAI_boss_ichoron(Creature* pCreature) +{ + return new boss_ichoronAI (pCreature); +} + +CreatureAI* GetAI_mob_ichor_globule(Creature* pCreature) +{ + return new mob_ichor_globuleAI (pCreature); +} + +void AddSC_boss_ichoron() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_ichoron"; + newscript->GetAI = &GetAI_boss_ichoron; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ichor_globule"; + newscript->GetAI = &GetAI_mob_ichor_globule; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/violet_hold/boss_lavanthor.cpp b/scripts/northrend/violet_hold/boss_lavanthor.cpp new file mode 100644 index 0000000000..18c934d88b --- /dev/null +++ b/scripts/northrend/violet_hold/boss_lavanthor.cpp @@ -0,0 +1,193 @@ +/* Copyright (C) 2006 - 2013 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_lavanthor +SDAuthor: ckegg +SD%Complete: 0 +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + +enum +{ + SPELL_CAUTERIZING_FLAMES = 59466, + SPELL_FIREBOLT = 54235, + SPELL_FIREBOLT_H = 59468, + SPELL_FLAME_BREATH = 54282, + SPELL_FLAME_BREATH_H = 59469, + SPELL_LAVA_BURN = 54249, + SPELL_LAVA_BURN_H = 59594, +}; + +struct MANGOS_DLL_DECL boss_lavanthorAI : public ScriptedAI +{ + boss_lavanthorAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + + bool m_bIsRegularMode; + bool MovementStarted; + + uint32 m_uiCauterizingFlames_Timer; + uint32 m_uiFlameBreath_Timer; + uint32 m_uiFirebolt_Timer; + + void Reset() + { + if (!m_pInstance) return; + m_uiCauterizingFlames_Timer = urand(40000, 41000); + m_uiFlameBreath_Timer = urand(15000, 16000); + m_uiFirebolt_Timer = urand(10000, 11000); + MovementStarted = false; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LAVANTHOR, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, NOT_STARTED);} + else {m_pInstance->SetData(TYPE_PORTAL12, NOT_STARTED);} + } + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + m_pInstance->SetData(TYPE_LAVANTHOR, IN_PROGRESS); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_LAVANTHOR) != SPECIAL && m_pInstance->GetData(TYPE_LAVANTHOR) != IN_PROGRESS) + return; + + if (!pWho || pWho == m_creature) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = true; + m_creature->SetInCombatWithZone(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted) return; + if (id == 0 ) + { + MovementStarted = false; + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_LAVANTHOR) == SPECIAL && !MovementStarted) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCauterizingFlames_Timer < uiDiff) + { + DoCast(m_creature, SPELL_CAUTERIZING_FLAMES); + m_uiCauterizingFlames_Timer = urand(40000, 41000); + } + else m_uiCauterizingFlames_Timer -= uiDiff; + + if (m_uiFirebolt_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FIREBOLT: SPELL_FIREBOLT_H ); + m_uiFirebolt_Timer = urand(10000, 11000); + } + else m_uiFirebolt_Timer -= uiDiff; + + if (m_uiFlameBreath_Timer < uiDiff) + { + switch (urand(0, 1)) + { + case 0: + DoCast(m_creature, m_bIsRegularMode ? SPELL_FLAME_BREATH : SPELL_FLAME_BREATH_H); + break; + case 1: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsRegularMode ? SPELL_LAVA_BURN : SPELL_LAVA_BURN_H); + break; + } + m_uiFlameBreath_Timer = urand(15000, 16000); + } + else m_uiFlameBreath_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance){ + m_pInstance->SetData(TYPE_LAVANTHOR, DONE); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, DONE);} + else {m_pInstance->SetData(TYPE_PORTAL12, DONE);} + } + } +}; + +CreatureAI* GetAI_boss_lavanthor(Creature* pCreature) +{ + return new boss_lavanthorAI (pCreature); +} + +void AddSC_boss_lavanthor() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_lavanthor"; + newscript->GetAI = &GetAI_boss_lavanthor; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/violet_hold/boss_moragg.cpp b/scripts/northrend/violet_hold/boss_moragg.cpp new file mode 100644 index 0000000000..c0fa957074 --- /dev/null +++ b/scripts/northrend/violet_hold/boss_moragg.cpp @@ -0,0 +1,183 @@ +/* Copyright (C) 2006 - 2013 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_moragg +SDAuthor: ckegg +SD%Complete: 50% +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + +enum +{ + SPELL_CORROSICE_SALIVA = 54527, + SPELL_OPTIC_LINK = 54396, + SPELL_RAY_PAIN = 59525, + SPELL_RAY_SUFFERING = 54417, +}; + +struct MANGOS_DLL_DECL boss_moraggAI : public ScriptedAI +{ + boss_moraggAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + + bool m_bIsRegularMode; + uint32 m_uiCorrosiveSaliva_Timer; + uint32 m_uiOpticLink_Timer; + uint32 m_uiRay_Timer; + + bool MovementStarted; + + void Reset() + { + MovementStarted = false; + m_uiCorrosiveSaliva_Timer = urand(10000, 11000); + m_uiOpticLink_Timer = urand(25000, 30000); + m_uiRay_Timer = urand(2000, 7000); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + } + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_MORAGG, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, NOT_STARTED);} + else {m_pInstance->SetData(TYPE_PORTAL12, NOT_STARTED);} + } + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + m_pInstance->SetData(TYPE_MORAGG, IN_PROGRESS); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_MORAGG) != SPECIAL && m_pInstance->GetData(TYPE_MORAGG) != IN_PROGRESS) + return; + + if (!pWho || pWho == m_creature) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = true; + m_creature->SetInCombatWithZone(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted) return; + if (id == 0) + { + MovementStarted = false; + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_MORAGG) == SPECIAL && !MovementStarted) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCorrosiveSaliva_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CORROSICE_SALIVA); + m_uiCorrosiveSaliva_Timer = urand(10000, 11000); + } + else m_uiCorrosiveSaliva_Timer -= uiDiff; + + if (m_uiOpticLink_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, SPELL_OPTIC_LINK); + m_uiOpticLink_Timer = urand(25000, 30000); + } + else m_uiOpticLink_Timer -= uiDiff; + + if (m_uiRay_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCast(pTarget, urand(0, 1) ? SPELL_RAY_PAIN : SPELL_RAY_SUFFERING); + m_uiRay_Timer = urand(2000, 7000); + } + else m_uiRay_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + if (m_pInstance){ + m_pInstance->SetData(TYPE_MORAGG, DONE); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, DONE);} + else {m_pInstance->SetData(TYPE_PORTAL12, DONE);} + } + } +}; + +CreatureAI* GetAI_boss_moragg(Creature* pCreature) +{ + return new boss_moraggAI (pCreature); +} + +void AddSC_boss_moragg() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_moragg"; + newscript->GetAI = &GetAI_boss_moragg; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/violet_hold/boss_xevozz.cpp b/scripts/northrend/violet_hold/boss_xevozz.cpp new file mode 100644 index 0000000000..d3633d9e5b --- /dev/null +++ b/scripts/northrend/violet_hold/boss_xevozz.cpp @@ -0,0 +1,360 @@ +/* Copyright (C) 2006 - 2013 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_xevozz +SDAuthor: ckegg +SD%Complete: 60% +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + +enum +{ + SAY_AGGRO = -1608070, + SAY_SLAY_1 = -1608071, + SAY_SLAY_2 = -1608029, + SAY_SLAY_3 = -1608030, + SAY_DEATH = -1608031, + SAY_SPAWN = -1608010, + SAY_CHARGED = -1608033, + SAY_REPEAT_SUMMON_1 = -1608034, + SAY_REPEAT_SUMMON_2 = -1608035, + SAY_SUMMON_ENERGY = -1608036, + + SPELL_ARCANE_BARRAGE_VOLLEY = 54202, + SPELL_ARCANE_BARRAGE_VOLLEY_H = 59483, + SPELL_ARCANE_BUFFET = 54226, + SPELL_ARCANE_BUFFET_H = 59485, + SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102, + SPELL_SUMMON_ETHEREAL_SPHERE_2 = 54137, + SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138, + + NPC_ETHEREAL_SPHERE = 29271, + //NPC_ETHEREAL_SPHERE2 = 32582, // heroic only? + SPELL_ARCANE_POWER = 54160, + SPELL_ARCANE_POWER_H = 59474, + SPELL_SUMMON_PLAYERS = 54164, + SPELL_ARCANE_TEMPEST = 35845, + SPELL_ARCANE_TEMPEST_H = 49366, + SPELL_ETHEREAL_BEACON_VISUAL = 32368 +}; + +struct MANGOS_DLL_DECL boss_xevozzAI : public ScriptedAI +{ + boss_xevozzAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + + bool m_bIsRegularMode; + bool MovementStarted; + + uint32 m_uiSummonEtherealSphere_Timer; + uint32 m_uiArcaneBarrageVolley_Timer; + uint32 m_uiArcaneBuffet_Timer; + uint32 m_uiDespawn_Timer; + + void Reset() + { + m_uiSummonEtherealSphere_Timer = 10000; + m_uiDespawn_Timer = 35000; + m_uiArcaneBarrageVolley_Timer = urand(20000, 22000); + m_uiArcaneBuffet_Timer = m_uiSummonEtherealSphere_Timer + urand(5000, 6000); + DespawnSphere(); + MovementStarted = false; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + + DoScriptText(SAY_AGGRO, m_creature); + m_pInstance->SetData(TYPE_XEVOZZ, IN_PROGRESS); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_XEVOZZ, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, NOT_STARTED);} + else {m_pInstance->SetData(TYPE_PORTAL12, NOT_STARTED);} + } + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_XEVOZZ) != SPECIAL && m_pInstance->GetData(TYPE_XEVOZZ) != IN_PROGRESS) + return; + + if (!pWho || pWho == m_creature) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void DespawnSphere() + { + std::list assistList; + GetCreatureListWithEntryInGrid(assistList,m_creature, NPC_ETHEREAL_SPHERE ,150.0f); + + if (assistList.empty()) + return; + + for(std::list::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) + (*iter)->DealDamage((*iter), (*iter)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->SetSpeedRate(MOVE_RUN, 0.5f); + pSummoned->StopMoving(); + pSummoned->CastSpell(pSummoned, SPELL_ETHEREAL_BEACON_VISUAL, false); + } + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = true; + m_creature->SetInCombatWithZone(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted) return; + if (id == 0) + { + MovementStarted = false; + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_XEVOZZ) == SPECIAL && !MovementStarted) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiArcaneBarrageVolley_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_ARCANE_BARRAGE_VOLLEY : SPELL_ARCANE_BARRAGE_VOLLEY_H); + m_uiArcaneBarrageVolley_Timer = urand(20000, 22000); + } + else m_uiArcaneBarrageVolley_Timer -= uiDiff; + + if (m_uiArcaneBuffet_Timer) + { + if (m_uiArcaneBuffet_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_BUFFET : SPELL_ARCANE_BUFFET_H); + m_uiArcaneBuffet_Timer = 0; + } + else m_uiArcaneBuffet_Timer -= uiDiff; + } + + if (m_uiSummonEtherealSphere_Timer < uiDiff) + { + DoScriptText(SAY_SPAWN, m_creature); + DoCast(m_creature, SPELL_SUMMON_ETHEREAL_SPHERE_1); + if (!m_bIsRegularMode) // extra one for heroic + m_creature->SummonCreature(NPC_ETHEREAL_SPHERE, m_creature->GetPositionX()-5+rand()%10, m_creature->GetPositionY()-5+rand()%10, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 40000); + + m_uiSummonEtherealSphere_Timer = 30000; + m_uiArcaneBuffet_Timer = urand(5000, 6000); + m_uiDespawn_Timer= 30000; + } + else m_uiSummonEtherealSphere_Timer -= uiDiff; + + if (m_uiDespawn_Timer < uiDiff) + { + DespawnSphere(); + } + else m_uiDespawn_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + DespawnSphere(); + + if (m_pInstance){ + m_pInstance->SetData(TYPE_XEVOZZ, DONE); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, DONE);} + else {m_pInstance->SetData(TYPE_PORTAL12, DONE);} + } + } + + 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; + case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + } + } +}; + +struct MANGOS_DLL_DECL mob_ethereal_sphereAI : public ScriptedAI +{ + mob_ethereal_sphereAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiSummonPlayers_Timer; + uint32 m_uiRangeCheck_Timer; + uint32 m_uiPhaseCheck_Timer; + bool bNormalPhase; + + + void Reset() + { + m_uiSummonPlayers_Timer = 5000; + m_uiRangeCheck_Timer = 1000; + m_uiPhaseCheck_Timer = 10000; + bNormalPhase = false; + } + + void UpdateAI(const uint32 uiDiff) override + { + //Return since we have no target + /* if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return;*/ + if(!bNormalPhase) + { + if (m_uiPhaseCheck_Timer < uiDiff ) + { + bNormalPhase = true; + m_uiPhaseCheck_Timer=3000000; + Creature* pXevozz = m_pInstance->GetSingleCreatureFromStorage(DATA_XEVOZZ); + m_creature->GetMotionMaster()->MoveFollow(pXevozz, 0, 0); + } + else m_uiPhaseCheck_Timer -= uiDiff; + } + if(bNormalPhase) + { + + if (m_uiRangeCheck_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_ARCANE_TEMPEST: SPELL_ARCANE_TEMPEST_H); + if (m_pInstance) + { + if (Creature* pXevozz = m_pInstance->GetSingleCreatureFromStorage(DATA_XEVOZZ)) + { + float fDistance = m_creature->GetDistance2d(pXevozz); + if (fDistance <= 3) + { + m_creature->CastSpell(pXevozz, SPELL_ARCANE_POWER_H, false); + // DoCast(pXevozz,SPELL_ARCANE_POWER_H); + } + } + } + m_uiRangeCheck_Timer = 1000; + } + else m_uiRangeCheck_Timer -= uiDiff; + + if (m_uiSummonPlayers_Timer < uiDiff) + { + if (Creature* pXevozz = (m_pInstance->GetSingleCreatureFromStorage(DATA_XEVOZZ))) + { + float fDistance = m_creature->GetDistance2d(pXevozz); + + if(fDistance<=20 && fDistance >6) + { + DoCast(m_creature, SPELL_SUMMON_PLAYERS); // not working right + + 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) + if (i->getSource()->isAlive()) + DoTeleportPlayer(i->getSource(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), i->getSource()->GetOrientation()); + } + + m_uiSummonPlayers_Timer = 15000; + } + } + } + else m_uiSummonPlayers_Timer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_xevozz(Creature* pCreature) +{ + return new boss_xevozzAI (pCreature); +} + +CreatureAI* GetAI_mob_ethereal_sphere(Creature* pCreature) +{ + return new mob_ethereal_sphereAI (pCreature); +} + +void AddSC_boss_xevozz() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_xevozz"; + newscript->GetAI = &GetAI_boss_xevozz; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_ethereal_sphere"; + newscript->GetAI = &GetAI_mob_ethereal_sphere; + newscript->RegisterSelf(); +} diff --git a/scripts/northrend/violet_hold/boss_zuramat.cpp b/scripts/northrend/violet_hold/boss_zuramat.cpp new file mode 100644 index 0000000000..534a30e341 --- /dev/null +++ b/scripts/northrend/violet_hold/boss_zuramat.cpp @@ -0,0 +1,296 @@ +/* Copyright (C) 2006 - 2013 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_zuramat +SDAuthor: ckegg +SD%Complete: 60% +SDComment: +SDCategory: The Violet Hold +EndScriptData */ + +#include "precompiled.h" +#include "violet_hold.h" + +enum +{ + SAY_AGGRO = -1608037, + SAY_SLAY_1 = -1608038, + SAY_SLAY_2 = -1608039, + SAY_SLAY_3 = -1608040, + SAY_DEATH = -1608041, + SAY_SPAWN = -1608011, + SAY_SHIELD = -1608043, + SAY_WHISPER = -1608044, + + SPELL_SHROUD_OF_DARKNESS = 54524, + SPELL_SHROUD_OF_DARKNESS_H = 59745, + SPELL_SUMMON_VOID_SENTRY = 54369, + SPELL_VOID_SHIFT = 54361, + SPELL_VOID_SHIFT_H = 59743, + + NPC_VOID_SENTRY = 29364, + SPELL_VOID_SENTRY_AURA = 54341, + SPELL_VOID_SENTRY_AURA_H = 54351, + SPELL_SHADOW_BOLT_VOLLEY = 54358, // 54342? 54358? + SPELL_SHADOW_BOLT_VOLLEY_H = 59747, + SPELL_VOID_SHIFTED = 54343 +}; + +struct MANGOS_DLL_DECL boss_zuramatAI : public ScriptedAI +{ + boss_zuramatAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + ScriptedInstance *m_pInstance; + + bool m_bIsRegularMode; + bool MovementStarted; + std::list m_lSentryGuidList; + + uint32 m_uiShroudDarkness_Timer; + uint32 m_uiVoidShift_Timer; + uint32 m_uiSummonVoidSentry_Timer; + + void Reset() + { + m_uiShroudDarkness_Timer = urand(8000, 9000); + m_uiSummonVoidSentry_Timer = 10000; + m_uiVoidShift_Timer = 10000; + MovementStarted = false; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_ZURAMAT, FAIL); + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) + m_pInstance->SetData(TYPE_PORTAL6, NOT_STARTED); + else + m_pInstance->SetData(TYPE_PORTAL12, NOT_STARTED); + } + } + + void Aggro(Unit* pWho) + { + if (!m_pInstance) return; + DoScriptText(SAY_AGGRO, m_creature); + m_pInstance->SetData(TYPE_ZURAMAT, IN_PROGRESS); + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_ZURAMAT) != SPECIAL && m_pInstance->GetData(TYPE_ZURAMAT) != IN_PROGRESS) + return; + + if (!pWho || pWho == m_creature) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho); + } + } + + void JustSummoned(Creature* pSummoned) override + { + m_lSentryGuidList.push_back(pSummoned->GetObjectGuid()); + //pSummoned->AddThreat(m_creature); + //pSummoned->AI()->AttackStart(m_creature); + } + + void DespawnSentry() + { + if (m_lSentryGuidList.empty()) + return; + + for(std::list::iterator itr = m_lSentryGuidList.begin(); itr != m_lSentryGuidList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + if (pTemp->isAlive()) + //pTemp->ForcedDespawn(); + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + m_lSentryGuidList.clear(); + } + + void StartMovement(uint32 id) + { + m_creature->GetMotionMaster()->MovePoint(id, PortalLoc[id].x, PortalLoc[id].y, PortalLoc[id].z); + m_creature->SetWalk(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + MovementStarted = true; + m_creature->SetInCombatWithZone(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || !MovementStarted) return; + if (id == 0) + { + MovementStarted = false; + m_creature->GetMotionMaster()->MovementExpired(); + SetCombatMovement(true); + m_creature->SetInCombatWithZone(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_ZURAMAT) == SPECIAL && !MovementStarted) + StartMovement(0); + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiShroudDarkness_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_SHROUD_OF_DARKNESS : SPELL_SHROUD_OF_DARKNESS_H); + m_uiShroudDarkness_Timer = urand(7000, 8000); + } + else m_uiShroudDarkness_Timer -= uiDiff; + + if (m_uiVoidShift_Timer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + DoCast(pTarget, m_bIsRegularMode ? SPELL_VOID_SHIFT : SPELL_VOID_SHIFT_H); + pTarget->CastSpell(pTarget, SPELL_VOID_SHIFTED, true); + } + m_uiVoidShift_Timer = urand(10000, 11000); + } + else m_uiVoidShift_Timer -= uiDiff; + + if (m_uiSummonVoidSentry_Timer < uiDiff) + { + m_creature->SummonCreature(NPC_VOID_SENTRY, m_creature->GetPositionX()-10+rand()%20, m_creature->GetPositionY()-10+rand()%20, m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_uiSummonVoidSentry_Timer = urand(10000, 10000); + } + else m_uiSummonVoidSentry_Timer -= uiDiff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + DoScriptText(SAY_DEATH, m_creature); + DespawnSentry(); + + if (m_pInstance){ + m_pInstance->SetData(TYPE_ZURAMAT, DONE); + if(m_pInstance->GetData(TYPE_PORTAL6) == IN_PROGRESS) {m_pInstance->SetData(TYPE_PORTAL6, DONE);} + else {m_pInstance->SetData(TYPE_PORTAL12, DONE);} + } + } + + 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; + case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + } + } +}; + +struct MANGOS_DLL_DECL mob_zuramat_sentryAI : public ScriptedAI +{ + mob_zuramat_sentryAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + SetCombatMovement(false); + Reset(); + } + ScriptedInstance *m_pInstance; + bool m_bIsRegularMode; + uint32 m_uiShadowBoltVolley_Timer; + + void Reset() + { + m_uiShadowBoltVolley_Timer = 3000; +// DoCast(m_creature, m_bIsRegularMode ? SPELL_VOID_SENTRY_AURA_H : SPELL_VOID_SENTRY_AURA); +// m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);*/ + DoCast(m_creature, m_bIsRegularMode ? SPELL_SHADOW_BOLT_VOLLEY : SPELL_SHADOW_BOLT_VOLLEY_H); + } + + void DamageTaken(Unit *killer, uint32 &damage) + { + if(!killer->HasAura(SPELL_VOID_SHIFTED)) + damage=0; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiShadowBoltVolley_Timer < uiDiff) + { + DoCast(m_creature, m_bIsRegularMode ? SPELL_SHADOW_BOLT_VOLLEY : SPELL_SHADOW_BOLT_VOLLEY_H); + m_uiShadowBoltVolley_Timer = 3000; + } + else m_uiShadowBoltVolley_Timer -= uiDiff; + } + +}; + +CreatureAI* GetAI_boss_zuramat(Creature* pCreature) +{ + return new boss_zuramatAI (pCreature); +} + +CreatureAI* GetAI_mob_zuramat_sentry(Creature* pCreature) +{ + return new mob_zuramat_sentryAI (pCreature); +} + +void AddSC_boss_zuramat() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "boss_zuramat"; + newscript->GetAI = &GetAI_boss_zuramat; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_zuramat_sentry"; + newscript->GetAI = &GetAI_mob_zuramat_sentry; + newscript->RegisterSelf(); + +} diff --git a/scripts/northrend/violet_hold/instance_violet_hold.cpp b/scripts/northrend/violet_hold/instance_violet_hold.cpp index 10b637b53b..c4e5c7582c 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,384 +15,288 @@ */ /* ScriptData -SDName: Instance_Violet_Hold -SD%Complete: 50 -SDComment: "experimental" use of header/source object -SDCategory: Violet Hold +SDName: Instance The Violet Hold +SD%Complete: 60% +SDComment: +SDCategory: The Violet Hold EndScriptData */ #include "precompiled.h" #include "violet_hold.h" -instance_violet_hold::instance_violet_hold(Map* pMap) : ScriptedInstance(pMap), - m_uiSinclariGUID(0), - m_uiSinclariAltGUID(0), - m_uiErekemGUID(0), - m_uiMoraggGUID(0), - m_uiIchoronGUID(0), - m_uiXevozzGUID(0), - m_uiLavanthorGUID(0), - m_uiZuramatGUID(0), - - m_uiCellErekemGuard_LGUID(0), - m_uiCellErekemGuard_RGUID(0), - m_uiIntroCrystalGUID(0), - - m_uiWorldState(0), - m_uiWorldStateSealCount(100), - m_uiWorldStatePortalCount(0), - - m_uiPortalId(0), - m_uiPortalTimer(0), - m_uiMaxCountPortalLoc(0) +/* The Violet Hold encounters: +0 Whole Event +1 Rift +2 Erekem +3 Moragg +4 Ichoron +5 Xevozz +6 Lavanthor +7 Zuramat +*/ +//inline uint32 RandRiftBoss() { return ((rand()%2) ? NPC_GUARDIAN : NPC_KEEPER); } + +struct MANGOS_DLL_DECL instance_violet_hold : public ScriptedInstance { - Initialize(); -} + instance_violet_hold(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; -void instance_violet_hold::Initialize() -{ - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - m_uiMaxCountPortalLoc = (sizeof(afPortalLocation)/sizeof(sPortalData)) - 1; -} + uint32 m_auiEncounter[MAX_ENCOUNTER+1]; + std::string m_strInstData; -void instance_violet_hold::ResetVariables() -{ - m_uiWorldStateSealCount = 100; - m_uiWorldStatePortalCount = 0; -} + bool bIsInBoss; -void instance_violet_hold::ResetAll() -{ - ResetVariables(); - UpdateWorldState(false); - CallGuards(true); - SetIntroPortals(false); -} + uint8 m_uiLastBossID; + uint8 m_uiLastBossIDConst; + uint8 m_uiRiftPortalCount; + uint32 m_uiShieldPercent; + uint32 m_uiDisruptions; + int8 m_uiPortalTime; -void instance_violet_hold::OnCreatureCreate(Creature* pCreature) -{ - switch(pCreature->GetEntry()) + void Initialize() override { - case NPC_SINCLARI: m_uiSinclariGUID = pCreature->GetGUID(); break; - case NPC_SINCLARI_ALT: m_uiSinclariAltGUID = pCreature->GetGUID(); break; - case NPC_DOOR_SEAL: m_uiDoorSealGUID = pCreature->GetGUID(); break; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + m_auiEncounter[i] = NOT_STARTED; - case NPC_EREKEM: - m_lRandomBossList.push_back(pCreature->GetEntry()); - m_uiErekemGUID = pCreature->GetGUID(); - break; - case NPC_MORAGG: - m_lRandomBossList.push_back(pCreature->GetEntry()); - m_uiMoraggGUID = pCreature->GetGUID(); - break; - case NPC_ICHORON: - m_lRandomBossList.push_back(pCreature->GetEntry()); - m_uiIchoronGUID = pCreature->GetGUID(); - break; - case NPC_XEVOZZ: - m_lRandomBossList.push_back(pCreature->GetEntry()); - m_uiXevozzGUID = pCreature->GetGUID(); - break; - case NPC_LAVANTHOR: - m_lRandomBossList.push_back(pCreature->GetEntry()); - m_uiLavanthorGUID = pCreature->GetGUID(); - break; - case NPC_ZURAMAT: - m_lRandomBossList.push_back(pCreature->GetEntry()); - m_uiZuramatGUID = pCreature->GetGUID(); - break; - - case NPC_PORTAL_INTRO: - m_lIntroPortalList.push_back(pCreature->GetGUID()); - break; - case NPC_HOLD_GUARD: - m_lGuardsList.push_back(pCreature->GetGUID()); - break; + Clear(); } -} -void instance_violet_hold::OnObjectCreate(GameObject* pGo) -{ - switch(pGo->GetEntry()) - { - case GO_CELL_LAVANTHOR: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_LAVANTHOR, pGo->GetGUID())); - break; - case GO_CELL_MORAGG: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_MORAGG, pGo->GetGUID())); - break; - case GO_CELL_ZURAMAT: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_ZURAMAT, pGo->GetGUID())); - break; - case GO_CELL_XEVOZZ: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_XEVOZZ, pGo->GetGUID())); - break; - case GO_CELL_ICHORON: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_ICHORON, pGo->GetGUID())); - break; - case GO_CELL_EREKEM: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_EREKEM, pGo->GetGUID())); - break; - case GO_CELL_EREKEM_GUARD_L: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_EREKEM, pGo->GetGUID())); - break; - case GO_CELL_EREKEM_GUARD_R: - m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_EREKEM, pGo->GetGUID())); - break; + void Clear(){ + bIsInBoss = false; - case GO_INTRO_CRYSTAL: - m_uiIntroCrystalGUID = pGo->GetGUID(); - break; - case GO_PRISON_SEAL_DOOR: - m_uiDoorSealGUID = pGo->GetGUID(); - break; + m_uiLastBossID = 0; + m_uiRiftPortalCount = 0; + m_uiPortalTime = 0; + m_uiShieldPercent = 100; } -} - -void instance_violet_hold::UpdateCellForBoss(uint32 uiBossEntry) -{ - BossToCellMap::const_iterator itrCellLower = m_mBossToCellMap.lower_bound(uiBossEntry); - BossToCellMap::const_iterator itrCellUpper = m_mBossToCellMap.upper_bound(uiBossEntry); - - if (itrCellLower == itrCellUpper) - return; - - for(BossToCellMap::const_iterator itr = itrCellLower; itr != itrCellUpper; ++itr) - DoUseDoorOrButton(itr->second); -} -void instance_violet_hold::UpdateWorldState(bool bEnable) -{ - if (bEnable) - m_uiWorldState = 1; - else - m_uiWorldState = 0; - - DoUpdateWorldState(WORLD_STATE_ID, m_uiWorldState); - DoUpdateWorldState(WORLD_STATE_SEAL, m_uiWorldStateSealCount); - DoUpdateWorldState(WORLD_STATE_PORTALS, m_uiWorldStatePortalCount); -} - -void instance_violet_hold::OnPlayerEnter(Player* pPlayer) -{ - UpdateWorldState(m_auiEncounter[0] == IN_PROGRESS ? true : false); -} + void InitWorldState(bool Enable = true) + { + DoUpdateWorldState(WORLD_STATE_VH,Enable ? 1 : 0); + DoUpdateWorldState(WORLD_STATE_VH_PRISON,100); + DoUpdateWorldState(WORLD_STATE_VH_PORTALS,0); + } -void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) -{ - debug_log("SD2: instance_violet_hold: SetData got type % u, data %u.", uiType, uiData); + void OnPlayerEnter(Player* pPlayer) override + { + if(m_auiEncounter[0] != NOT_STARTED) + pPlayer->SendUpdateWorldState(WORLD_STATE_VH,1); + } - switch(uiType) + bool IsEncounterInProgress() const override { - case TYPE_MAIN: - { - if (uiData == m_auiEncounter[0]) - return; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + return true; - switch(uiData) - { - case NOT_STARTED: - ResetAll(); - break; - case IN_PROGRESS: - DoUseDoorOrButton(m_uiDoorSealGUID); - SetRandomBosses(); - UpdateWorldState(); - m_uiPortalId = urand(0, 2); - m_uiPortalTimer = 15000; - break; - case FAIL: - if (Creature* pSinclari = instance->GetCreature(m_uiSinclariGUID)) - pSinclari->Respawn(); - - break; - case DONE: - break; - case SPECIAL: - break; - } - m_auiEncounter[0] = uiData; - break; - } - case TYPE_SEAL: - m_auiEncounter[1] = uiData; - break; - case TYPE_PORTAL: - { - switch(uiData) - { - case SPECIAL: // timer to next - m_uiPortalTimer = 90000; - break; - case DONE: // portal done, set timer to 5 secs - m_uiPortalTimer = 5000; - break; - } - m_auiEncounter[2] = uiData; - break; - } + return false; } -} -void instance_violet_hold::SetIntroPortals(bool bDeactivate) -{ - for(std::list::iterator i = m_lIntroPortalList.begin(); i != m_lIntroPortalList.end(); ++i) + void OnCreatureCreate(Creature* pCreature) override { - if (Creature* pPortal = instance->GetCreature(*i)) + switch(pCreature->GetEntry()) { - if (bDeactivate) - pPortal->ForcedDespawn(); - else - pPortal->Respawn(); + case NPC_SINCLARI: + case NPC_DOOR_SEAL: + case NPC_EREKEM: + case NPC_MORAGG: + case NPC_ICHORON: + case NPC_XEVOZZ: + case NPC_LAVANTHOR: + case NPC_ZURAMAT: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } } -} -void instance_violet_hold::SpawnPortal() -{ - if (const sPortalData* pData = GetPortalData()) + void OnObjectCreate(GameObject* pGo) override { - if (Creature* pController = instance->GetCreature(m_uiSinclariAltGUID)) - { - uint32 uiPortalEntry; - - switch(pData->pPortalType) - { - case PORTAL_TYPE_NORM: uiPortalEntry = NPC_PORTAL; break; - case PORTAL_TYPE_SQUAD: - case PORTAL_TYPE_BOSS: uiPortalEntry = NPC_PORTAL_ELITE; break; - } - - pController->SummonCreature(uiPortalEntry, pData->fX, pData->fY, pData->fZ, pData->fOrient, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 1800*IN_MILLISECONDS); - } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } -} -void instance_violet_hold::SetPortalId() -{ - if (IsCurrentPortalForTrash()) + void SetData(uint32 uiType, uint32 uiData) override { - int iTemp = rand()%(m_uiMaxCountPortalLoc - 1); - - if (iTemp >= m_uiPortalId) - ++iTemp; + switch(uiType) + { + case TYPE_EVENT: + if (uiData == IN_PROGRESS) + { + Clear(); + InitWorldState(); + } + else if (uiData == FAIL || uiData == DONE) + { + DoUpdateWorldState(WORLD_STATE_VH, 0); + DoUseDoorOrButton(GO_DOOR_SEAL); + if (Creature* pSinclari = GetSingleCreatureFromStorage(NPC_SINCLARI)) + pSinclari->ForcedDespawn(1000); + } + m_auiEncounter[0] = uiData; + break; + case TYPE_EREKEM: + m_auiEncounter[2] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_MORAGG: + m_auiEncounter[3] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_ICHORON: + m_auiEncounter[4] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_XEVOZZ: + m_auiEncounter[5] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_LAVANTHOR: + m_auiEncounter[6] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_ZURAMAT: + m_auiEncounter[7] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_CYANIGOSA: + m_auiEncounter[8] = uiData; + if (uiData == IN_PROGRESS) bIsInBoss = true; + break; + case TYPE_PORTAL6: + m_auiEncounter[9] = uiData; + break; + case TYPE_PORTAL12: + m_auiEncounter[10] = uiData; + break; + case TYPE_RIFT: + if (uiData == FAIL) + DoUseDoorOrButton(GO_DOOR_SEAL); + m_auiEncounter[1] = uiData; + break; + case TYPE_DOOR: + if (uiData == SPECIAL) + { + m_uiShieldPercent = m_uiShieldPercent - 5; + if(m_uiShieldPercent > 0) + DoUpdateWorldState(WORLD_STATE_VH_PRISON, m_uiShieldPercent); + else + { DoUpdateWorldState(WORLD_STATE_VH, 0); + DoUseDoorOrButton(GO_DOOR_SEAL); + m_auiEncounter[0] = FAIL; + } + } + break; + case TYPE_DISRUPTIONS: + m_uiDisruptions = uiData; +// DoUpdateWorldState(WORLD_STATE_VH_PRISON, 100-m_uiDisruptions*5); + break; + case TYPE_LASTBOSS_ID: + m_uiLastBossIDConst = uiData; + break; - debug_log("SD2: instance_violet_hold: SetPortalId %i, old was id %u.", iTemp, m_uiPortalId); + } + if (uiData == DONE) + { + bIsInBoss = false; + OUT_SAVE_INST_DATA; - m_uiPortalId = iTemp; - } - else - { - debug_log("SD2: instance_violet_hold: SetPortalId %u (is boss), old was id %u.", m_uiMaxCountPortalLoc, m_uiPortalId); - m_uiPortalId = m_uiMaxCountPortalLoc; - } -} + std::ostringstream saveStream; -void instance_violet_hold::SetRandomBosses() -{ - while (m_lRandomBossList.size() > 2) - { - uint32 uiPosition = urand(0, m_lRandomBossList.size()-1); + for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + saveStream << m_auiEncounter[i] << " "; - for(std::list::iterator itr = m_lRandomBossList.begin(); itr != m_lRandomBossList.end(); ++itr, --uiPosition) - { - if (!*itr) - continue; + m_strInstData = saveStream.str(); - if (!uiPosition) - { - m_lRandomBossList.erase(itr); - break; - } + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } - } - for(std::list::iterator itr = m_lRandomBossList.begin(); itr != m_lRandomBossList.end(); ++itr) - debug_log("SD2: instance_violet_hold random boss is entry %u", *itr); -} + } -void instance_violet_hold::CallGuards(bool bRespawn) -{ - for(std::list::iterator i = m_lGuardsList.begin(); i != m_lGuardsList.end(); ++i) + uint32 GetData(uint32 uiType) { - if (Creature* pGuard = instance->GetCreature(*i)) + switch(uiType) { - if (bRespawn) - { - pGuard->Respawn(); - } - else if (pGuard->isAlive()) + case TYPE_EVENT: + return m_auiEncounter[0]; + case TYPE_EREKEM: + return m_auiEncounter[2]; + case TYPE_MORAGG: + return m_auiEncounter[3]; + case TYPE_ICHORON: + return m_auiEncounter[4]; + case TYPE_XEVOZZ: + return m_auiEncounter[5]; + case TYPE_LAVANTHOR: + return m_auiEncounter[6]; + case TYPE_ZURAMAT: + return m_auiEncounter[7]; + case TYPE_CYANIGOSA: + return m_auiEncounter[8]; + case TYPE_PORTAL6: + return m_auiEncounter[9]; + case TYPE_PORTAL12: + return m_auiEncounter[10]; + case TYPE_RIFT: + return m_uiRiftPortalCount; + case TYPE_LASTBOSS_ID: + return m_uiLastBossIDConst; + case TYPE_LASTBOSS: { - pGuard->AI()->EnterEvadeMode(); - - if (Creature* pSinclari = instance->GetCreature(m_uiSinclariGUID)) - pGuard->GetMotionMaster()->MoveFollow(pSinclari, 0.0f, 0.0f); - - pGuard->ForcedDespawn(20000); + if (m_uiLastBossID == 0) + m_uiLastBossID = urand(2, 7); + else + { + m_uiLastBossID = urand(2, 7); + if ( m_auiEncounter[2] == DONE && + m_auiEncounter[3] == DONE && + m_auiEncounter[4] == DONE && + m_auiEncounter[5] == DONE && + m_auiEncounter[6] == DONE && + m_auiEncounter[7] == DONE) return 0; + while ( m_auiEncounter[m_uiLastBossID] == DONE + || m_auiEncounter[m_uiLastBossID] == IN_PROGRESS + || m_auiEncounter[m_uiLastBossID] == SPECIAL ) + { + m_uiLastBossID = urand(2, 7); + } + } + return m_uiLastBossID; } + case DATA_BOSSTIME: + return bIsInBoss; + case TYPE_DISRUPTIONS: + return m_uiDisruptions; } + return 0; } -} -void instance_violet_hold::ProcessActivationCrystal(Unit* pUser, bool bIsIntro) -{ - if (Creature* pSummon = pUser->SummonCreature(NPC_DEFENSE_SYSTEM, fDefenseSystemLoc[0], fDefenseSystemLoc[1], fDefenseSystemLoc[2], fDefenseSystemLoc[3], TEMPSUMMON_TIMED_DESPAWN, 10000)) +const char* Save() const override { - pSummon->CastSpell(pSummon, SPELL_DEFENSE_SYSTEM_VISUAL, true); - - // TODO: figure out how the rest work - // NPC's NPC_DEFENSE_DUMMY_TARGET are probably channeling some spell to the defense system + return m_strInstData.c_str(); } - if (bIsIntro) - DoUseDoorOrButton(m_uiIntroCrystalGUID); - - // else, kill (and despawn?) certain trash mobs. Also boss affected, but not killed. -} - -uint32 instance_violet_hold::GetRandomPortalEliteEntry() -{ - return (urand(0, 1) ? NPC_PORTAL_GUARDIAN : NPC_PORTAL_KEEPER); -} - -uint32 instance_violet_hold::GetRandomMobForNormalPortal() -{ - switch(urand(1, 4)) +void Load(const char* strIn) { - case 1: return NPC_AZURE_INVADER; - case 2: return NPC_MAGE_HUNTER; - case 3: return NPC_AZURE_SPELLBREAKER; - case 4: return NPC_AZURE_BINDER; - } - - return 0; -} + if (!strIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } -uint64 instance_violet_hold::GetData64(uint32 uiData) -{ - return 0; -} + OUT_LOAD_INST_DATA(strIn); -void instance_violet_hold::Update(uint32 uiDiff) -{ - if (m_auiEncounter[0] != IN_PROGRESS) - return; + std::istringstream loadStream(strIn); - if (m_uiPortalTimer) - { - if (m_uiPortalTimer <= uiDiff) + for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - DoUpdateWorldState(WORLD_STATE_PORTALS, ++m_uiWorldStatePortalCount); - - SetPortalId(); - SpawnPortal(); + loadStream >> m_auiEncounter[i]; - m_uiPortalTimer = 0; + if (m_auiEncounter[i] == IN_PROGRESS && i != 1) + m_auiEncounter[i] = NOT_STARTED; } - else - m_uiPortalTimer -= uiDiff; + + OUT_LOAD_INST_DATA_COMPLETE; } -} +}; InstanceData* GetInstanceData_instance_violet_hold(Map* pMap) { @@ -404,6 +308,6 @@ void AddSC_instance_violet_hold() Script *newscript; newscript = new Script; newscript->Name = "instance_violet_hold"; - newscript->GetInstanceData = GetInstanceData_instance_violet_hold; + newscript->GetInstanceData = &GetInstanceData_instance_violet_hold; newscript->RegisterSelf(); } diff --git a/scripts/northrend/violet_hold/violet_hold.cpp b/scripts/northrend/violet_hold/violet_hold.cpp index 3832167bc0..2c437104fe 100644 --- a/scripts/northrend/violet_hold/violet_hold.cpp +++ b/scripts/northrend/violet_hold/violet_hold.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -15,58 +15,580 @@ */ /* ScriptData -SDName: Violet_Hold -SD%Complete: 40 -SDComment: -SDCategory: Violet Hold +SDName: violet_hold +SDAuthor: ckegg, modified by rsa +SD%Complete: 60 +SDComment: +SDCategory: The Violet Hold EndScriptData */ -/* ContentData -go_activation_crystal -npc_door_seal -npc_sinclari -npc_teleportation_portal -EndContentData */ - #include "precompiled.h" #include "violet_hold.h" #include "escort_ai.h" +enum +{ + SPELL_TELEPORT_INSIDE = 62139, + SPELL_SHIELD_DISRUPTION = 58291, + + //DRAGONS SPELLS + //Azure Captain + SPELL_MORTAL_STRIKE = 32736, + SPELL_WHIRLWIND = 41057, + + //Azure Raider + SPELL_CONCUSSION_BLOW = 52719, + SPELL_MAGIC_REFLECTION = 60158, + + //Azure Sorceror + SPELL_ARCANE_STREAM = 60181, + SPELL_ARCANE_STREAM_H = 60204, + SPELL_MANA_DETONATION = 60182, + SPELL_MANA_DETONATION_H = 60205, + + //Azure stalker + SPELL_BACKSTAB = 58471, + SPELL_TACTICAL_BLINK = 58470, + AZURE_SAY_AGGRO_1 = -1608055, + AZURE_SAY_AGGRO_2 = -1608056, + AZURE_SAY_AGGRO_3 = -1608057, + AZURE_SAY_AGGRO_4 = -1608058, + PORTAL_KEEPER_GUARDIAN_AGGRO_1 = -1608059, + PORTAL_KEEPER_GUARDIAN_AGGRO_2 = -1608060, + PORTAL_KEEPER_GUARDIAN_AGGRO_3 = -1608061, + PORTAL_KEEPER_GUARDIAN_DEATH_1 = -1608062, + PORTAL_KEEPER_GUARDIAN_DEATH_2 = -1608063, + PORTAL_KEEPER_GUARDIAN_DEATH_3 = -1608064, + AZURE_CAPTAIN_AGGRO_1 = -1608065 + +}; + +uint32 m_uiNextPortal_Timer; /*###### -## go_activation_crystal +## mob_vh_dragons +## This script is for ALL mobs which are spawned from portals, +## they have to be scripted in SD2 because in EventAI you cant +## check for distance from door seal :/ +## (Intro not implented yet) ######*/ - -bool GOHello_go_activation_crystal(Player* pPlayer, GameObject* pGo) +struct MANGOS_DLL_DECL mob_vh_dragonsAI : public ScriptedAI { - if (instance_violet_hold* pInstance = (instance_violet_hold*)pGo->GetInstanceData()) - pInstance->ProcessActivationCrystal(pPlayer); + mob_vh_dragonsAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegular = pCreature->GetMap()->IsRegularDifficulty(); + WayPointList.clear(); + Reset(); + } - return false; -} + ScriptedInstance* m_pInstance; + bool m_bIsRegular; + uint32 creatureEntry; + uint32 motherPortalID; + uint32 WalkTimer; + int8 portalLoc; + bool IsWalking; + bool IsInCombat; + bool MovementStarted; + Creature* pDoorSeal; + + std::list WayPointList; + std::list::iterator WayPoint; + + //Azure Captain + uint32 m_uiMortalStrike_Timer; + uint32 m_uiWhirlwind_Timer; + + //Azure Raider + uint32 m_uiConcussionBlow_Timer; + uint32 m_uiMagicReflection_Timer; + + //Azure Sorceror + uint32 m_uiArcaneStream_Timer; + uint32 m_uiManaDetonation_Timer; + + //Azure Stalker + uint32 m_uiBackstab_Timer; + uint32 m_uiBlink_Timer; + + void Reset(){ + creatureEntry = m_creature->GetEntry(); + motherPortalID = 0; + WalkTimer = 200; + portalLoc = -1; + IsWalking = false; + IsInCombat = false; + MovementStarted = false; + pDoorSeal = GetClosestCreatureWithEntry(m_creature, NPC_DOOR_SEAL, 150.0f); + + //Azure Captain + m_uiMortalStrike_Timer = 3000; + m_uiWhirlwind_Timer = 5000; + + //Azure Raider + m_uiConcussionBlow_Timer = 3000; + m_uiMagicReflection_Timer = 10000; + + //Azure Sorceror + m_uiArcaneStream_Timer = 5000; + m_uiManaDetonation_Timer = 3000; + + //Azure Stalker + m_uiBackstab_Timer = 7100; + m_uiBlink_Timer = 7000; + + if (creatureEntry == NPC_KEEPER || creatureEntry == NPC_GUARDIAN) + { + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveRandom(); + } + + } + + void StartMovement() + { + if(!WayPointList.empty() || MovementStarted) + return; + + uint8 start = 0; + uint8 end = 0; + switch(portalLoc) + { + case -1: + return; + //center & ichoron + case 0: + case 5: + start = 0; + end = 2; + break; + //From lavanthor + case 1: + start = 3; + end = 5; + break; + // From Zuramat + case 2: + start = 6; + end = 11; + break; + //From Moragg + case 3: + start = 12; + end = 16; + break; + //From Erekem + case 4: + start = 17; + end = 21; + break; + //From highest platform + case 6: + start = 22; + end = 26; + break; + } + uint8 wpId = 0; + for(uint8 i = start; i <= end; ++i){ + debug_log("AddWP: %u", i); + AddWaypoint(wpId, DragonsWP[i].x, DragonsWP[i].y, DragonsWP[i].z); + wpId++; + } + + WayPoint = WayPointList.begin(); + m_creature->SetWalk(true); + IsWalking = true; + MovementStarted = true; + } + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_EVENT, FAIL); + m_pInstance->SetData(TYPE_RIFT, FAIL); + } + } + void AddWaypoint(uint32 id, float x, float y, float z) + { + WayPoints DWP(id, x, y, z); + WayPointList.push_back(DWP); + } + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if(uiType != POINT_MOTION_TYPE || creatureEntry == NPC_GUARDIAN || creatureEntry == NPC_KEEPER) + return; + + if(WayPoint->id != uiPointId) + return; + + ++WayPoint; + WalkTimer = 200; + } + void JustDied(Unit* pKiller) override + { + switch(creatureEntry) + { + case NPC_GUARDIAN: + case NPC_KEEPER: + switch(urand(0,2)) + { + case 0: DoScriptText(PORTAL_KEEPER_GUARDIAN_DEATH_1, m_creature); break; + case 1: DoScriptText(PORTAL_KEEPER_GUARDIAN_DEATH_2, m_creature); break; + case 2: DoScriptText(PORTAL_KEEPER_GUARDIAN_DEATH_3, m_creature); break; + } + break; + } + } + void Aggro(Unit* pWho) + { + switch(creatureEntry) + { + case NPC_AZURE_CAPTAIN: + DoScriptText(AZURE_CAPTAIN_AGGRO_1, m_creature); + break; + case NPC_AZURE_RAIDER: + case NPC_AZURE_SORCEROR: + case NPC_AZURE_STALKER: + case NPC_AZURE_BINDER: + case NPC_AZURE_INVADER: + case NPC_AZURE_MAGE_SLAYER: + case NPC_AZURE_SPELLBREAKER: + switch(urand(0,3)) + { + case 0: DoScriptText(AZURE_SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(AZURE_SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(AZURE_SAY_AGGRO_3, m_creature); break; + case 3: DoScriptText(AZURE_SAY_AGGRO_4, m_creature); break; + } + break; + case NPC_GUARDIAN: + case NPC_KEEPER: + switch(urand(0,2)) + { + case 0: DoScriptText(PORTAL_KEEPER_GUARDIAN_AGGRO_1, m_creature); break; + case 1: DoScriptText(PORTAL_KEEPER_GUARDIAN_AGGRO_2, m_creature); break; + case 2: DoScriptText(PORTAL_KEEPER_GUARDIAN_AGGRO_3, m_creature); break; + } + break; + default: + debug_log("SD2: The Violet Hold: Unhandled dragon entry %u!", m_creature->GetEntry()); + break; + } + } + void UpdateAI(const uint32 uiDiff) override{ + if(portalLoc != -1) + StartMovement(); + + if (IsWalking && WalkTimer) + { + if (WalkTimer <= uiDiff) + { + if (WayPoint != WayPointList.end()) + { + m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); + WalkTimer = 0; + } + }else WalkTimer -= uiDiff; + } + + //Corrupt Seal + + if(Creature *pDoorSeal2 = GetClosestCreatureWithEntry(m_creature, NPC_DOOR_SEAL, 150.0f)){ + if(m_creature->IsWithinDist(pDoorSeal2, 27.0f, false) && !IsInCombat) + { + IsWalking = false; + WayPointList.clear(); + m_creature->GetMotionMaster()->Clear(false); + m_creature->SetWalk(false); + DoCast(pDoorSeal2, SPELL_CORRUPT); + m_pInstance->SetData(TYPE_DOOR,SPECIAL); + } + } + if(!IsWalking && !IsInCombat) { + if (Unit* m_uEmbraceTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + m_creature->GetMotionMaster()->MoveChase(m_uEmbraceTarget); + m_creature->SetInCombatWithZone(); + IsInCombat = true; + } + + + //Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if(m_creature->getVictim()) + if(m_creature->getVictim()->GetEntry() == NPC_DOOR_SEAL) + return; + switch(creatureEntry) + { + case NPC_AZURE_CAPTAIN: + AzureCaptain_UpdateAI(uiDiff); + break; + case NPC_AZURE_RAIDER: + AzureRaider_UpdateAI(uiDiff); + break; + case NPC_AZURE_SORCEROR: + AzureSorceror_UpdateAI(uiDiff); + break; + case NPC_AZURE_STALKER: + AzureStalker_UpdateAI(uiDiff); + break; + case NPC_GUARDIAN: + case NPC_KEEPER: + case NPC_AZURE_BINDER: + case NPC_AZURE_INVADER: + case NPC_AZURE_MAGE_SLAYER: + case NPC_AZURE_SPELLBREAKER: + break; + default: + debug_log("SD2: The Violet Hold: Unhandled dragon entry %u!", m_creature->GetEntry()); + break; + } + DoMeleeAttackIfReady(); + } + //Azure Captain + void AzureCaptain_UpdateAI(const uint32 uiDiff) + { + //Mortal Strike + if (m_uiMortalStrike_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + m_uiMortalStrike_Timer = 6000; + }else m_uiMortalStrike_Timer -= uiDiff; + + //Whirlwind + if (m_uiWhirlwind_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_WHIRLWIND); + m_uiWhirlwind_Timer = 15000; + }else m_uiWhirlwind_Timer -= uiDiff; + } + //Azure Raider + void AzureRaider_UpdateAI(const uint32 uiDiff) + { + //Concusion Blow + if (m_uiConcussionBlow_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CONCUSSION_BLOW); + m_uiMortalStrike_Timer = 7000; + }else m_uiConcussionBlow_Timer -= uiDiff; + + //Magic reflection + if (m_uiMagicReflection_Timer <= uiDiff) + { + DoCast(m_creature, SPELL_MAGIC_REFLECTION); + m_uiMagicReflection_Timer = 30000; + }else m_uiMagicReflection_Timer -= uiDiff; + } + //Azure Sorceror + void AzureSorceror_UpdateAI(const uint32 uiDiff) + { + //Arcane Stream + if (m_uiArcaneStream_Timer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + DoCast(pTarget, m_bIsRegular ? SPELL_ARCANE_STREAM : SPELL_ARCANE_STREAM_H); + m_uiArcaneStream_Timer = 7000; + }else m_uiArcaneStream_Timer -= uiDiff; + + //Mana Detonation + if (m_uiManaDetonation_Timer <= uiDiff) + { + DoCast(m_creature, m_bIsRegular ? SPELL_MANA_DETONATION : SPELL_MANA_DETONATION_H); + m_uiManaDetonation_Timer = 18000; + }else m_uiManaDetonation_Timer -= uiDiff; + } + //Azure Stalker + void AzureStalker_UpdateAI(const uint32 uiDiff) + { + //Backstab + if (m_uiBackstab_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_BACKSTAB); + m_uiBackstab_Timer = 15100; + }else m_uiBackstab_Timer -= uiDiff; + + //Tactical blink + if (m_uiBlink_Timer <= uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_TACTICAL_BLINK); + m_uiBlink_Timer = 15000; + }else m_uiBlink_Timer -= uiDiff; + } +}; /*###### -## npc_door_seal +## npc_teleportation_portal ######*/ - -bool EffectDummyCreature_npc_door_seal(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +struct MANGOS_DLL_DECL npc_teleportation_portalAI : public ScriptedAI { - //always check spellid and effectindex - if (uiSpellId == SPELL_DESTROY_DOOR_SEAL && uiEffIndex == EFFECT_INDEX_0) + npc_teleportation_portalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + bool m_uiGroupSpawned; + uint8 portalType; // 0 = nothing, 1 = Guard & spawns, 2 = Group of elites + uint32 portalID; // To identify portal... + int8 portalLoc; + + uint32 TimeRiftWave_Timer; + uint32 Check_Timer; + + void Reset() { - if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreatureTarget->GetInstanceData()) - pInstance->SetData(TYPE_SEAL, SPECIAL); + m_uiGroupSpawned = false; + portalType = 0; + portalID = 0; + portalLoc = -1; + TimeRiftWave_Timer = 15000; + Check_Timer = 5000; - //always return true when we are handling this spell and effect - return true; + m_creature->SetRespawnDelay(DAY); } - return false; -} + void JustSummoned(Creature* pSummoned) override + { + switch(pSummoned->GetEntry()) + { + case NPC_GUARDIAN: + DoScriptText(EMOTE_GUARDIAN_PORTAL, pSummoned); + break; + case NPC_KEEPER: + DoScriptText(EMOTE_KEEPER_PORTAL, pSummoned); + break; + case NPC_AZURE_CAPTAIN: + DoScriptText(EMOTE_DRAGONFLIGHT_PORTAL, pSummoned); + break; + default: + return; + } + + } + + uint32 SelectRandSummon() + { + uint32 entry = 0; + if(portalType == 1) + { + switch (urand(0, 3)) + { + case 0: entry = NPC_AZURE_BINDER; break; + case 1: entry = NPC_AZURE_INVADER; break; + case 2: entry = NPC_AZURE_MAGE_SLAYER; break; + case 3: entry = NPC_AZURE_SPELLBREAKER; break; + } + }else{ + switch (urand(0, 3)) + { + case 0: entry = NPC_AZURE_CAPTAIN; break; + case 1: entry = NPC_AZURE_RAIDER; break; + case 2: entry = NPC_AZURE_SORCEROR; break; + case 3: entry = NPC_AZURE_STALKER; break; + } + } + return entry; + } + void SpawnGroup() + { + if(portalType == 0) + return; + + uint8 uiSpawnCount = (m_pInstance->GetData(TYPE_RIFT) < 12) ? 3 : 4; + for(uint8 i = 0; i < uiSpawnCount; i++) + { + uint32 uiSpawnEntry = SelectRandSummon(); + if(Creature* pSummoned = m_creature->SummonCreature(uiSpawnEntry, m_creature->GetPositionX()-5+rand()%10, m_creature->GetPositionY()-5+rand()%10, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000)) + { + debug_log("Spawn NPC %u, motherPortalID %u, portalLoc %u", uiSpawnEntry, portalID, portalLoc); + ((mob_vh_dragonsAI*)pSummoned->AI())->motherPortalID = portalID; + ((mob_vh_dragonsAI*)pSummoned->AI())->portalLoc = portalLoc; + } + } + } + bool IsThereNearElite(float range) + { + //Azure captain + if(Creature* pTemp = GetClosestCreatureWithEntry(m_creature, NPC_AZURE_CAPTAIN, range)) + { + if(((mob_vh_dragonsAI*)pTemp->AI())->motherPortalID == portalID) + return true; + } + //Azure raider + else if(Creature* pTemp = GetClosestCreatureWithEntry(m_creature, NPC_AZURE_RAIDER, range)) + { + if(((mob_vh_dragonsAI*)pTemp->AI())->motherPortalID == portalID) + return true; + } + //Azure sorceror + else if(Creature* pTemp = GetClosestCreatureWithEntry(m_creature, NPC_AZURE_SORCEROR, range)) + { + if(((mob_vh_dragonsAI*)pTemp->AI())->motherPortalID == portalID) + return true; + } + //Azure Stalker + else if(Creature* pTemp = GetClosestCreatureWithEntry(m_creature, NPC_AZURE_STALKER, range)) + { + if(((mob_vh_dragonsAI*)pTemp->AI())->motherPortalID == portalID) + return true; + } + return false; + } + + void UpdateAI(const uint32 diff) + { + if (!m_pInstance) + return; + + if(m_pInstance->GetData(TYPE_EVENT) != IN_PROGRESS) + return; + + switch(portalType) + { + case 0: + return; + case 1: + if (TimeRiftWave_Timer < diff) + { + debug_log("SpawnGroup()"); + SpawnGroup(); + TimeRiftWave_Timer = 15000; + }else TimeRiftWave_Timer -= diff; + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + m_uiNextPortal_Timer = 5000; + debug_log("SD2: npc_time_rift: not casting anylonger, i need to die."); + m_creature->ForcedDespawn(); + } + break; + case 2: + if(!m_uiGroupSpawned) + { + SpawnGroup(); + m_uiGroupSpawned = true; + } + if (Check_Timer < diff) + { + if(!IsThereNearElite(150.0f)) + { + m_uiNextPortal_Timer = 5000; + debug_log("SD2: npc_time_rift: No elite, i need to die."); + m_creature->ForcedDespawn(); + } + Check_Timer = 1000; + }else Check_Timer -= diff; + break; + } + } +}; /*###### ## npc_sinclari ######*/ - enum { SAY_BEGIN = -1608000, @@ -77,60 +599,245 @@ enum GOSSIP_TEXT_ID_INTRO = 13853, GOSSIP_TEXT_ID_START = 13854, + SAY_END = -1608009, }; -struct MANGOS_DLL_DECL npc_sinclariAI : public npc_escortAI +struct MANGOS_DLL_DECL npc_sinclariAI : public ScriptedAI { - npc_sinclariAI(Creature* pCreature) : npc_escortAI(pCreature) + npc_sinclariAI(Creature *pCreature) : ScriptedAI(pCreature) { - m_pInstance = (instance_violet_hold*)pCreature->GetInstanceData(); + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); Reset(); } + ScriptedInstance *m_pInstance; - instance_violet_hold* m_pInstance; + uint8 m_uiRiftPortalCount; + uint8 m_bIsRegular; + uint32 m_uiBossCheck_Timer; + uint32 m_uiPortalCheck_Timer; + std::list m_lGuardsList; + uint32 m_uiWaypoint; + bool start; + uint32 m_uiWalkTimer; void Reset() { + m_uiRiftPortalCount = 0; + m_uiWalkTimer = 0; + m_uiNextPortal_Timer = 0; + m_uiBossCheck_Timer = 0; + m_uiPortalCheck_Timer = 1000; + m_bIsRegular = m_creature->GetMap()->IsRegularDifficulty(); + m_uiWaypoint = 0; + start = false; + } + + void CallGuards(bool bRespawn) + { + GetCreatureListWithEntryInGrid(m_lGuardsList, m_creature, NPC_GUARD, 50.0f); + for(std::list::iterator i = m_lGuardsList.begin(); i != m_lGuardsList.end(); ++i) + { + if (Creature* pGuard = *i) + { + if (bRespawn) + { + pGuard->Respawn(); + } + else if (pGuard->isAlive()) + { + pGuard->AI()->EnterEvadeMode(); + + if (Creature* pSinclari = GetClosestCreatureWithEntry(pGuard,NPC_SINCLARI,50.0f)) + pGuard->GetMotionMaster()->MoveFollow(pSinclari, 0.0f, 0.0f); + + pGuard->ForcedDespawn(20000); + } + } } +} + - void WaypointReached(uint32 uiPointId) + void SetEvent() { - if (!m_pInstance) - return; - switch(uiPointId) + m_uiNextPortal_Timer = 5000; + + if (m_pInstance){ + m_pInstance->SetData(TYPE_EVENT, IN_PROGRESS); + m_pInstance->DoUseDoorOrButton(GO_DOOR_SEAL); + } + } + void EventEscort() + { + start=true; + m_uiWalkTimer = 1000; + + + } + + void DoSpawnPortal() + { + int tmp = urand(1, 6); + if (Creature* pTemp = m_creature->SummonCreature(NPC_PORTAL, PortalLoc[tmp].x, PortalLoc[tmp].y, PortalLoc[tmp].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000)) { - case 0: - m_pInstance->ProcessActivationCrystal(m_creature, true); - break; - case 1: - DoScriptText(SAY_BEGIN, m_creature); - m_pInstance->SetIntroPortals(true); - m_pInstance->CallGuards(false); - break; - case 2: - DoScriptText(SAY_LOCK_DOOR, m_creature); - m_pInstance->SetData(TYPE_MAIN, IN_PROGRESS); - break; + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + //set portal type + uint8 portalType = rand()%2+1; + uint32 portalID = rand()%50000; + ((npc_teleportation_portalAI*)pTemp->AI())->portalType = portalType; + ((npc_teleportation_portalAI*)pTemp->AI())->portalID = portalID; + ((npc_teleportation_portalAI*)pTemp->AI())->portalLoc = tmp; + + if(portalType == 1) + { + uint32 entry = urand(0, 1) ? NPC_GUARDIAN : NPC_KEEPER; + if (Creature* pSummoned = pTemp->SummonCreature(entry, PortalLoc[tmp].x, PortalLoc[tmp].y, PortalLoc[tmp].z, pTemp->GetOrientation(), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000)) + { + pSummoned->AddThreat(pTemp); + pTemp->CastSpell(pSummoned, SPELL_PORTAL_CHANNEL,false); + ((mob_vh_dragonsAI*)pSummoned->AI())->motherPortalID = portalID; + } + } } } - void JustRespawned() + void UpdateAI(const uint32 uiDiff) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_MAIN, NOT_STARTED); + if(start) + { + if (m_uiWalkTimer <= uiDiff) + { + switch(m_uiWaypoint) + { + case 0: m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, SinclariWP[m_uiWaypoint].x, SinclariWP[m_uiWaypoint].y, SinclariWP[m_uiWaypoint].z); + m_uiWalkTimer = 1000; + m_uiWaypoint++; + break; + case 1: m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, SinclariWP[m_uiWaypoint].x, SinclariWP[m_uiWaypoint].y, SinclariWP[m_uiWaypoint].z); + DoScriptText(SAY_BEGIN, m_creature); + CallGuards(false); + m_uiWalkTimer = 2000; + m_uiWaypoint++; + break; + case 2: + m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, SinclariWP[m_uiWaypoint].x, SinclariWP[m_uiWaypoint].y, SinclariWP[m_uiWaypoint].z); + m_uiWalkTimer = 3000; + m_uiWaypoint++; + break; + case 3: m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, SinclariWP[m_uiWaypoint].x, SinclariWP[m_uiWaypoint].y, SinclariWP[m_uiWaypoint].z); + DoScriptText(SAY_LOCK_DOOR, m_creature); + m_uiWalkTimer = 3000; + m_uiWaypoint++; + break; + case 4: + m_creature->GetMotionMaster()->MovePoint(4, 1815.571f, 800.112f, 44.364f); + SetEvent(); + m_uiWalkTimer = 3000; + m_uiWaypoint++; + break; + case 5: + m_creature->GetMotionMaster()->Clear(); + start = false; + m_uiWalkTimer = 0; + break; + + } + } + else m_uiWalkTimer -= uiDiff; + } + + if(m_pInstance->GetData(TYPE_EVENT) != IN_PROGRESS || m_pInstance->GetData(TYPE_CYANIGOSA) == IN_PROGRESS) + return; + + if (m_uiNextPortal_Timer && m_pInstance->GetData(TYPE_RIFT) != DONE ) + { + if (m_uiNextPortal_Timer <= uiDiff) + { + ++m_uiRiftPortalCount; + if (m_pInstance && m_uiRiftPortalCount < 19) + { + m_pInstance->DoUpdateWorldState(WORLD_STATE_VH_PORTALS, m_uiRiftPortalCount); + m_pInstance->SetData(TYPE_RIFT, SPECIAL); + } + + if ( m_uiRiftPortalCount != 6 + && m_uiRiftPortalCount != 12 + && m_uiRiftPortalCount != 18 + && m_uiRiftPortalCount < 18 + ) + { + DoSpawnPortal(); + if (m_uiRiftPortalCount < 12) + m_uiNextPortal_Timer = 120000; + else + m_uiNextPortal_Timer = 90000; + } + else if ( m_uiRiftPortalCount == 6 + || m_uiRiftPortalCount == 12) + { + if(m_uiRiftPortalCount == 6 && m_pInstance->GetData(TYPE_PORTAL6) != DONE || m_uiRiftPortalCount == 12 && m_pInstance->GetData(TYPE_PORTAL12) != DONE) + { + if (Creature* pTemp = m_creature->SummonCreature(NPC_PORTAL, PortalLoc[0].x, PortalLoc[0].y, PortalLoc[0].z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) + { + pTemp->SetRespawnDelay(7*DAY*IN_MILLISECONDS); + Creature* pSummoned = m_creature->SummonCreature(NPC_AZURE_SABOTEUR, PortalLoc[0].x, PortalLoc[0].y, PortalLoc[0].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); +// pSummoned->AddThreat(pTemp); + pTemp->CastSpell(pSummoned, SPELL_PORTAL_CHANNEL, false); + if(m_uiRiftPortalCount == 6) {m_pInstance->SetData(TYPE_PORTAL6, IN_PROGRESS);} + else m_pInstance->SetData(TYPE_PORTAL12, IN_PROGRESS); + } + m_uiNextPortal_Timer = m_bIsRegular ? 180000 : 120000; + } + else m_uiNextPortal_Timer = 4000; + m_pInstance->SetData(TYPE_RIFT, IN_PROGRESS); + m_uiBossCheck_Timer = 1000; + } + else if (m_uiRiftPortalCount == 18 && m_pInstance->GetData(TYPE_RIFT) != DONE) + { + Creature* pCyanigossa = GetClosestCreatureWithEntry(m_creature, NPC_CYANIGOSA, 300.0f); + + if (!pCyanigossa) + { + m_creature->SummonCreature(NPC_CYANIGOSA, 1922.420f, 803.240f, 52.40f, 3.022f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN , 99999999);} + m_pInstance->SetData(TYPE_RIFT, DONE); + m_pInstance->SetData(TYPE_DISRUPTIONS, 20); + m_uiNextPortal_Timer = 1*DAY; + } + } + else + m_uiNextPortal_Timer -= uiDiff; + + return; + } + + if (m_uiBossCheck_Timer) + { + if (m_uiBossCheck_Timer <= uiDiff) + { + if (!m_pInstance->GetData(DATA_BOSSTIME)) + m_uiNextPortal_Timer = 10000; + m_uiBossCheck_Timer = 1000; + } + else + m_uiBossCheck_Timer -= uiDiff; + + return; + } } }; -CreatureAI* GetAI_npc_sinclari(Creature* pCreature) -{ - return new npc_sinclariAI(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); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_INTRO, pCreature->GetGUID()); + if (ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if (m_pInstance->GetData(TYPE_EVENT) == NOT_STARTED || m_pInstance->GetData(TYPE_EVENT) == FAIL) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INTRO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_INTRO, pCreature->GetObjectGuid()); + } + } return true; } @@ -138,12 +845,13 @@ bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSe { if (uiAction == GOSSIP_ACTION_INFO_DEF+1) { - if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreature->GetInstanceData()) + if (ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) { - if (pInstance->GetData(TYPE_MAIN) == NOT_STARTED) + if (m_pInstance->GetData(TYPE_EVENT) == NOT_STARTED || m_pInstance->GetData(TYPE_EVENT) == FAIL) { + pPlayer->PlayerTalkClass->ClearMenus(); 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->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_START, pCreature->GetObjectGuid()); } } else @@ -152,16 +860,16 @@ bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSe if (uiAction == GOSSIP_ACTION_INFO_DEF+2) { - if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreature->GetInstanceData()) + if (ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) { pPlayer->CLOSE_GOSSIP_MENU(); - if (pInstance->GetData(TYPE_MAIN) == NOT_STARTED) + if (m_pInstance->GetData(TYPE_EVENT) == NOT_STARTED || m_pInstance->GetData(TYPE_EVENT) == FAIL) { - pInstance->SetData(TYPE_MAIN, SPECIAL); - if (npc_sinclariAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(); + if (Creature* pSinclari = (m_pInstance->GetSingleCreatureFromStorage(NPC_SINCLARI))) + + ((npc_sinclariAI*)pSinclari->AI())->EventEscort(); } } else @@ -170,193 +878,206 @@ bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSe return true; } - /*###### -## npc_teleportation_portal +## npc_door_seal ######*/ - -struct MANGOS_DLL_DECL npc_teleportation_portalAI : public ScriptedAI +struct MANGOS_DLL_DECL npc_door_sealAI : public ScriptedAI { - npc_teleportation_portalAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_door_sealAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (instance_violet_hold*)pCreature->GetInstanceData(); - m_uiMyPortalNumber = 0; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - instance_violet_hold* m_pInstance; - - std::set m_lMobSet; + ScriptedInstance* m_pInstance; - bool m_bNeedInvisible; - bool m_bIntro; - uint32 m_uiIntroTimer; - uint32 m_uiMyPortalNumber; + uint32 CheckTimer; + uint32 SpellCorrupt_Timer; + uint8 lastPortal; void Reset() { - m_bNeedInvisible = false; - m_bIntro = false; - m_uiIntroTimer = 10000; - - if (m_pInstance) - m_uiMyPortalNumber = m_pInstance->GetCurrentPortalNumber(); - } - - void DoSummon() + CheckTimer = 0; + SpellCorrupt_Timer = 0; + lastPortal = 0; +} + void SpellHit(Unit* caster, const SpellEntry* spell) override { - if (m_creature->GetEntry() == NPC_PORTAL_INTRO) - { - //not made yet + if (SpellCorrupt_Timer) return; - } - else if (m_creature->GetEntry() == NPC_PORTAL) - { - 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); - } - else if (m_pInstance->IsCurrentPortalForTrash()) - { - for(uint8 i = 0; i < 4; ++i) - { - uint32 uiSummonId; - - switch(i) - { - 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; - } - m_creature->SummonCreature(uiSummonId, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); + if (spell->Id == SPELL_CORRUPT) { + SpellCorrupt_Timer = 1000; } + } + void JustDied(Unit* pKiller) override + { + m_creature->Respawn(); + } - m_bNeedInvisible = true; - } - else + void UpdateAI(const uint32 diff){ + if (SpellCorrupt_Timer) { - 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; + if (SpellCorrupt_Timer <= diff) + { + if (m_creature->HasAura(SPELL_CORRUPT,EFFECT_INDEX_0)) + SpellCorrupt_Timer = 1500; + else + SpellCorrupt_Timer = 0; + }else SpellCorrupt_Timer -= diff; } } +}; - void JustSummoned(Creature* pSummoned) +/*###### +## npc_azure_saboteur +######*/ +struct MANGOS_DLL_DECL npc_azure_saboteurAI : public ScriptedAI +{ + npc_azure_saboteurAI(Creature *pCreature) : ScriptedAI(pCreature) { - switch(pSummoned->GetEntry()) - { - 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->GetGUID()); - break; - case NPC_AZURE_RAIDER: - case NPC_AZURE_SORCEROR: - case NPC_AZURE_STALKER: - m_lMobSet.insert(pSummoned->GetGUID()); - return; - default: - return; - } + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + ScriptedInstance *m_pInstance; - if (m_pInstance) - m_pInstance->SetData(TYPE_PORTAL, SPECIAL); + bool m_bIsActiving; + + uint32 m_uiDisruption_Timer; + uint32 m_uiDisruptionCounter; + uint32 m_uiDisruptionsCount; + + uint8 m_uiBossID; + uint8 m_bIsRegular; + uint32 m_uiBossType; + uint32 m_uiDoorGUID; + + void AttackStart(Unit* pWho) override + { + return; } - void SummonedCreatureJustDied(Creature* pSummoned) + void Reset() { - switch(pSummoned->GetEntry()) - { - case NPC_PORTAL_GUARDIAN: - case NPC_PORTAL_KEEPER: - break; - case NPC_AZURE_CAPTAIN: - case NPC_AZURE_RAIDER: - case NPC_AZURE_SORCEROR: - case NPC_AZURE_STALKER: - { - m_lMobSet.erase(pSummoned->GetGUID()); + m_bIsActiving = false; - if (!m_lMobSet.empty()) - return; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetWalk(false); + m_uiDisruptionCounter = 0; + m_uiDisruptionsCount = 0; + m_uiDisruption_Timer = 1000; +// m_bIsRegular = m_creature->GetMap()->IsRegularDifficulty(); - break; + if (m_pInstance) + { + m_uiBossID = m_pInstance->GetData(TYPE_LASTBOSS); + m_uiDisruptionsCount = m_pInstance->GetData(TYPE_DISRUPTIONS); + switch (m_uiBossID) + { + case 6: // Lavanthor + m_uiBossType = TYPE_LAVANTHOR; + m_uiDoorGUID = GO_DOOR_LAVANTHOR; + break; + case 7: // Zuramat + m_uiBossType = TYPE_ZURAMAT; + m_uiDoorGUID = GO_DOOR_ZURAMAT; + break; + case 3: // Moragg + m_uiBossType = TYPE_MORAGG; + m_uiDoorGUID = GO_DOOR_MORAGG; + break; + case 2: // Erekem + m_uiBossType = TYPE_EREKEM; + m_uiDoorGUID = GO_DOOR_EREKEM; + break; + case 4: // Ichoron + m_uiBossType = TYPE_ICHORON; + m_uiDoorGUID = GO_DOOR_ICHORON; + break; + case 5: // Xevozz + m_uiBossType = TYPE_XEVOZZ; + m_uiDoorGUID = GO_DOOR_XEVOZZ; + break; + case 0: // No boss + m_uiBossType = 0; + break; } - default: - return; + m_pInstance->SetData(TYPE_LASTBOSS_ID, m_uiBossType); + if (m_uiBossType != 0) m_creature->GetMotionMaster()->MovePoint(0, BossLoc[m_uiBossID].x, BossLoc[m_uiBossID].y, BossLoc[m_uiBossID].z); + else m_creature->GetMotionMaster()->MovePoint(0, 1827.960f, 804.208f, 44.364f); } + } - if (m_pInstance) + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if(uiType != POINT_MOTION_TYPE) + return; + + switch(uiPointId) { - // 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 0: + m_bIsActiving = true; + break; } - - m_creature->ForcedDespawn(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_uiIntroTimer) - { - if (m_uiIntroTimer <= uiDiff) + if (m_bIsActiving) + if (m_uiDisruption_Timer < uiDiff) { - if (!m_pInstance) + if (m_uiDisruptionCounter < 3) { - m_creature->ForcedDespawn(); - return; + DoCast(m_creature, SPELL_SHIELD_DISRUPTION); + ++m_uiDisruptionsCount; + m_pInstance->SetData(TYPE_DISRUPTIONS, m_uiDisruptionsCount); + } + else if (m_uiDisruptionCounter == 3) + { + m_pInstance->DoUseDoorOrButton(m_uiDoorGUID); + if (m_uiBossType == TYPE_EREKEM) + { + m_pInstance->DoUseDoorOrButton(GO_DOOR_EREKEM_RIGHT); + m_pInstance->DoUseDoorOrButton(GO_DOOR_EREKEM_LEFT); + } + } + else + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (m_pInstance->GetData(TYPE_LASTBOSS_ID) != 0) + m_pInstance->SetData(m_pInstance->GetData(TYPE_LASTBOSS_ID), SPECIAL); + m_bIsActiving = false; } - m_uiIntroTimer = 0; - } - else - { - m_uiIntroTimer -= uiDiff; - return; + ++m_uiDisruptionCounter; + m_uiDisruption_Timer = 1000; } - } - - if (!m_bIntro) - { - DoSummon(); - m_bIntro = true; - } - - if (m_bNeedInvisible) - { - // hack; find a better way - m_creature->SetVisibility(VISIBILITY_OFF); - m_bNeedInvisible = false; - } + else m_uiDisruption_Timer -= uiDiff; } }; -CreatureAI* GetAI_npc_teleportation_portal(Creature* pCreature) + + +CreatureAI* GetAI_npc_azure_saboteur(Creature* pCreature) { - return new npc_teleportation_portalAI(pCreature); + return new npc_azure_saboteurAI (pCreature); } -bool EffectDummyCreature_npc_teleportation_portal(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +CreatureAI* GetAI_mob_vh_dragons(Creature* pCreature) { - //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); - - //always return true when we are handling this spell and effect - return true; - } - - return false; + return new mob_vh_dragonsAI(pCreature); +} +CreatureAI* GetAI_npc_sinclari(Creature* pCreature) +{ + return new npc_sinclariAI (pCreature); +} +CreatureAI* GetAI_npc_teleportation_portal(Creature* pCreature) +{ + return new npc_teleportation_portalAI (pCreature); +} +CreatureAI* GetAI_npc_door_seal(Creature* pCreature) +{ + return new npc_door_sealAI(pCreature); } void AddSC_violet_hold() @@ -364,25 +1085,30 @@ void AddSC_violet_hold() Script *newscript; newscript = new Script; - newscript->Name = "go_activation_crystal"; - newscript->pGOHello = &GOHello_go_activation_crystal; + newscript->Name = "npc_sinclari"; + newscript->GetAI = &GetAI_npc_sinclari; + newscript->pGossipHello = &GossipHello_npc_sinclari; + newscript->pGossipSelect = &GossipSelect_npc_sinclari; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "npc_teleportation_portal"; + newscript->GetAI = &GetAI_npc_teleportation_portal; newscript->RegisterSelf(); newscript = new Script; newscript->Name = "npc_door_seal"; - newscript->pEffectDummyCreature = &EffectDummyCreature_npc_door_seal; + newscript->GetAI = &GetAI_npc_door_seal; newscript->RegisterSelf(); newscript = new Script; - newscript->Name = "npc_sinclari"; - newscript->GetAI = &GetAI_npc_sinclari; - newscript->pGossipHello = &GossipHello_npc_sinclari; - newscript->pGossipSelect = &GossipSelect_npc_sinclari; + newscript->Name = "npc_azure_saboteur"; + newscript->GetAI = &GetAI_npc_azure_saboteur; newscript->RegisterSelf(); newscript = new Script; - newscript->Name = "npc_teleportation_portal"; - newscript->GetAI = &GetAI_npc_teleportation_portal; - newscript->pEffectDummyCreature = &EffectDummyCreature_npc_teleportation_portal; + newscript->Name = "mob_vh_dragons"; + newscript->GetAI = &GetAI_mob_vh_dragons; newscript->RegisterSelf(); + } diff --git a/scripts/northrend/violet_hold/violet_hold.h b/scripts/northrend/violet_hold/violet_hold.h index b8f4a8b179..cc3f04b522 100644 --- a/scripts/northrend/violet_hold/violet_hold.h +++ b/scripts/northrend/violet_hold/violet_hold.h @@ -1,229 +1,178 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ -#ifndef DEF_VIOLET_H -#define DEF_VIOLET_H +#ifndef DEF_VIOLET_HOLD_H +#define DEF_VIOLET_HOLD_H enum { - MAX_ENCOUNTER = 3, - - TYPE_MAIN = 1, - TYPE_SEAL = 2, - TYPE_PORTAL = 3, - - WORLD_STATE_ID = 3816, - WORLD_STATE_SEAL = 3815, - WORLD_STATE_PORTALS = 3810, - - GO_INTRO_CRYSTAL = 193615, - GO_PRISON_SEAL_DOOR = 191723, - - GO_CELL_LAVANTHOR = 191566, - GO_CELL_MORAGG = 191606, - GO_CELL_ZURAMAT = 191565, - GO_CELL_EREKEM = 191564, - GO_CELL_EREKEM_GUARD_L = 191563, - GO_CELL_EREKEM_GUARD_R = 191562, - GO_CELL_XEVOZZ = 191556, - GO_CELL_ICHORON = 191722, - - NPC_EVENT_CONTROLLER = 30883, - NPC_PORTAL_INTRO = 31011, - NPC_PORTAL = 30679, - NPC_PORTAL_ELITE = 32174, - NPC_DOOR_SEAL = 30896, - - NPC_SINCLARI = 30658, - NPC_SINCLARI_ALT = 32204, // yeller for seal weakening and summoner for portals - NPC_HOLD_GUARD = 30659, - - NPC_EREKEM = 29315, - NPC_EREKEM_GUARD = 29395, - NPC_MORAGG = 29316, - NPC_ICHORON = 29313, - NPC_XEVOZZ = 29266, - NPC_LAVANTHOR = 29312, - NPC_ZURAMAT = 29314, - NPC_CYANIGOSA = 31134, - - NPC_PORTAL_GUARDIAN = 30660, - NPC_PORTAL_KEEPER = 30695, - - NPC_AZURE_INVADER = 30661, - NPC_AZURE_SPELLBREAKER = 30662, - NPC_AZURE_BINDER = 30663, - NPC_AZURE_MAGE_SLAYER = 30664, - NPC_MAGE_HUNTER = 30665, - NPC_AZURE_CAPTAIN = 30666, - NPC_AZURE_SORCEROR = 30667, - NPC_AZURE_RAIDER = 30668, - NPC_AZURE_STALKER = 32191, - - // used for intro - NPC_AZURE_BINDER_INTRO = 31007, - NPC_AZURE_INVADER_INTRO = 31008, - NPC_AZURE_SPELLBREAKER_INTRO= 31009, - NPC_AZURE_MAGE_SLAYER_INTRO = 31010, - - NPC_AZURE_SABOTEUR = 31079, - - NPC_DEFENSE_SYSTEM = 30837, - NPC_DEFENSE_DUMMY_TARGET = 30857, - - NPC_ARAKKOA = 32226, - NPC_VOID_LORD = 32230, - NPC_ETHERAL = 32231, - NPC_SWIRLING = 32234, - NPC_WATCHER = 32235, - NPC_LAVA_HOUND = 32237, - - SPELL_DEFENSE_SYSTEM_VISUAL = 57887, - SPELL_DEFENSE_SYSTEM_SPAWN = 57886, - - 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_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 - SPELL_PORTAL_BEAM = 56046, // large beam, unsure if really used here (or possible for something different) - - SPELL_PORTAL_VISUAL_1 = 57872, // no idea, but is possibly related based on it's visual appearence - SPELL_PORTAL_VISUAL_2 = 57630, - - SAY_SEAL_75 = -1608002, - SAY_SEAL_50 = -1608003, - SAY_SEAL_5 = -1608004, + MAX_ENCOUNTER = 11, + + TYPE_EVENT = 0, + TYPE_RIFT = 1, + TYPE_EREKEM = 2, + TYPE_MORAGG = 3, + TYPE_ICHORON = 4, + TYPE_XEVOZZ = 5, + TYPE_LAVANTHOR = 6, + TYPE_ZURAMAT = 7, + TYPE_CYANIGOSA = 8, + TYPE_PORTAL6 = 9, + TYPE_PORTAL12 = 10, + + + WORLD_STATE_VH = 3816, + WORLD_STATE_VH_PRISON = 3815, + WORLD_STATE_VH_PORTALS = 3810, + + TYPE_LASTBOSS = 19, + TYPE_DOOR = 21, + TYPE_PORTAL_TIME = 22, + + TYPE_DISRUPTIONS = 101, + TYPE_LASTBOSS_ID = 102, + + DATA_EREKEM = 23, + DATA_MORAGG = 24, + DATA_ICHORON = 25, + DATA_XEVOZZ = 26, + DATA_LAVANTHOR = 27, + DATA_ZURAMAT = 28, + DATA_SINCLARI = 29, + DATA_BOSSTIME = 30, + + NPC_EREKEM = 29315, + NPC_EREKEM_GUARD = 29395, + NPC_MORAGG = 29316, + NPC_ICHORON = 29313, + NPC_XEVOZZ = 29266, + NPC_LAVANTHOR = 29312, + NPC_ZURAMAT = 29314, + NPC_CYANIGOSA = 31134, + + NPC_AZURE_SABOTEUR = 31079, // Open boss's cell + + NPC_AZURE_CAPTAIN = 30666, //Melee, 40k - 60k hp, 3 for 1-11, 4 for 13-17 + NPC_AZURE_RAIDER = 30668, //Melee, 40k - 60k hp + NPC_AZURE_SORCEROR = 30667, //Caster, 40k - 60k hp + NPC_AZURE_STALKER = 32191, //Melee, 40k - 60k hp + NPC_GUARDIAN = 30660, + NPC_KEEPER = 30695, + NPC_AZURE_BINDER = 30663, //Caster, 7k - 10k hp + NPC_AZURE_INVADER = 30661, //Melee, 8k - 12k hp + NPC_AZURE_MAGE_SLAYER = 30664, //Melee, 10k - 15k hp + NPC_AZURE_SPELLBREAKER = 30662, //Caster, 10k - 15k hp + + NPC_SINCLARI = 30658, + NPC_GUARD = 30659, + NPC_PORTAL = 31011, + NPC_DOOR_SEAL = 30896, + + GO_DOOR_SEAL = 191723, + GO_DOOR_EREKEM = 191564, + GO_DOOR_EREKEM_RIGHT = 191563, + GO_DOOR_EREKEM_LEFT = 191562, + GO_DOOR_MORAGG = 191606, + GO_DOOR_ICHORON = 191722, + GO_DOOR_XEVOZZ = 191556, + GO_DOOR_LAVANTHOR = 191566, + GO_DOOR_ZURAMAT = 191565, + + SPELL_PORTAL_CHANNEL = 58012, + SPELL_CORRUPT = 58040, EMOTE_GUARDIAN_PORTAL = -1608005, EMOTE_DRAGONFLIGHT_PORTAL = -1608006, - EMOTE_KEEPER_PORTAL = -1608007, - - MAX_NORMAL_PORTAL = 8 + EMOTE_KEEPER_PORTAL = -1608007 }; -static float fDefenseSystemLoc[4] = {1888.146f, 803.382f, 58.604f, 3.072f}; - -enum ePortalType +struct WayPoints { - PORTAL_TYPE_NORM = 0, - PORTAL_TYPE_SQUAD, - PORTAL_TYPE_BOSS, + WayPoints(uint32 _id, float _x, float _y, float _z) + { + id = _id; + x = _x; + y = _y; + z = _z; + } + uint32 id; + float x, y, z; }; -struct sPortalData +static LOCATION SinclariWP[]= { - ePortalType pPortalType; - float fX, fY, fZ, fOrient; + {1830.5f, 799.357f, 44.3418f}, // 0 use activation + {1832.46f, 800.431f, 44.3117f}, // 1 SAY_BEGIN call back guards + {1824.79f, 803.828f, 44.3634f}, // 2 SAY_LOCK_DOOR close door + {1807.25f, 803.904f, 44.3634f}, // 3 + {1808.07f, 804.259f, 44.3641f}, // 4 + }; -static sPortalData afPortalLocation[]= +static LOCATION PortalLoc[]= { - {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 + {1888.271f, 810.781f, 38.441f}, // 0 center + {1857.125f, 763.295f, 38.654f}, // 1 Lavanthor + {1925.480f, 849.981f, 47.174f}, // 2 Zuramat + {1892.737f, 744.589f, 47.666f}, // 3 Moragg + {1878.198f, 850.005f, 43.333f}, // 4 Portal in front of Erekem + {1909.381f, 806.796f, 38.645f}, // 5 Portal outside of Ichoron + {1936.101f, 802.950f, 52.417f}, // 6 at the highest platform }; -class MANGOS_DLL_DECL instance_violet_hold : public ScriptedInstance +static LOCATION BossLoc[]= { - public: - instance_violet_hold(Map* pMap); - ~instance_violet_hold() {} - - void Initialize(); - void ResetAll(); - void ResetVariables(); - - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); - - void UpdateCellForBoss(uint32 uiBossEntry); - void UpdateWorldState(bool bEnable = true); - - void SetIntroPortals(bool bDeactivate); - void SpawnPortal(); - - void SetPortalId(); - - void CallGuards(bool bRespawn); - - uint32 GetRandomPortalEliteEntry(); - uint32 GetRandomMobForNormalPortal(); - - uint32 GetCurrentPortalNumber() { return m_uiWorldStatePortalCount; } - - sPortalData const* GetPortalData() { return &afPortalLocation[m_uiPortalId]; } - - bool IsCurrentPortalForTrash() - { - if (m_uiWorldStatePortalCount % 6) - return true; - - return false; - } - - bool IsNextPortalForTrash() - { - if ((m_uiWorldStatePortalCount+1) % 6) - return true; - - return false; - } - - void ProcessActivationCrystal(Unit* pUser, bool bIsIntro = false); - - void SetRandomBosses(); - - void OnPlayerEnter(Player* pPlayer); - - void SetData(uint32 uiType, uint32 uiData); - uint64 GetData64(uint32 uiData); - - void Update(uint32 uiDiff); - - typedef std::multimap BossToCellMap; - - protected: - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiSinclariGUID; - uint64 m_uiSinclariAltGUID; - uint64 m_uiErekemGUID; - uint64 m_uiMoraggGUID; - uint64 m_uiIchoronGUID; - uint64 m_uiXevozzGUID; - uint64 m_uiLavanthorGUID; - uint64 m_uiZuramatGUID; - - uint64 m_uiCellErekemGuard_LGUID; - uint64 m_uiCellErekemGuard_RGUID; - uint64 m_uiIntroCrystalGUID; - uint64 m_uiDoorSealGUID; - - uint32 m_uiWorldState; - uint32 m_uiWorldStateSealCount; - uint32 m_uiWorldStatePortalCount; - - uint8 m_uiPortalId; - uint32 m_uiPortalTimer; - uint32 m_uiMaxCountPortalLoc; - - BossToCellMap m_mBossToCellMap; + {0,0,0}, + {0,0,0}, + {1876.100f, 857.079f, 43.333f}, // Erekem + {1892.737f, 744.589f, 47.666f}, // Moragg + {1908.863f, 785.647f, 37.435f}, // Ichoron + {1905.364f, 840.607f, 38.670f}, // Xevozz + {1857.125f, 763.295f, 38.654f}, // Lavanthor + {1925.480f, 849.981f, 47.174f}, // Zuramat +}; - std::list m_lIntroPortalList; - std::list m_lGuardsList; - std::list m_lRandomBossList; +static LOCATION DragonsWP[]= +{ + //center, ichoron + {1869.393f, 803.902f, 38.768f}, // 0 + {1859.843f, 804.222f, 44.008f}, // 1 + {1829.64f, 804.194f, 44.355f}, // 2 + + //From left side (lavanthor) + {1861.016f, 789.717f, 38.908f}, // 3 + {1856.217f, 796.705f, 44.008f}, // 4 + {1829.64f, 804.194f, 44.355f}, // 5 + + //From Zuramat + {1931.446f, 826.734f, 47.556f}, // 6 + {1913.049f, 823.930f, 38.792f}, // 7 + {1827.960f, 804.208f, 44.364f}, // 8 + {1869.393f, 803.902f, 38.768f}, // 9 + {1859.843f, 804.222f, 44.008f}, // 10 + {1829.64f, 804.194f, 44.355f}, // 11 + + //From Morag + {1887.500f, 763.096f, 47.666f}, // 12 + {1880.837f, 775.769f, 38.796f}, // 13 + {1861.016f, 789.717f, 38.908f}, // 14 + {1856.217f, 796.705f, 44.008f}, // 15 + {1829.64f, 804.194f, 44.355f}, // 16 + + //From erekem + {1878.280f, 843.267f, 43.333f}, // 17 + {1872.311f, 835.531f, 38.780f}, // 18 + {1861.997f, 818.766f, 38.650f}, // 19 + {1857.348f, 811.230f, 44.008f}, // 20 + {1829.64f, 804.194f, 44.355f}, // 21 + + //From Highest platform + {1937.298f, 824.557f, 52.332f}, // 22 + {1913.049f, 823.930f, 38.792f}, // 23 + {1869.393f, 803.902f, 38.768f}, // 24 + {1859.843f, 804.222f, 44.008f}, // 25 + {1829.64f, 804.194f, 44.355f}, // 26 }; #endif diff --git a/scripts/northrend/wintergrasp.cpp b/scripts/northrend/wintergrasp.cpp new file mode 100644 index 0000000000..ff8f82fc40 --- /dev/null +++ b/scripts/northrend/wintergrasp.cpp @@ -0,0 +1,165 @@ +/* Copyright (C) 2006 - 2013 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 + */ + +#include "precompiled.h" + +/*###### +## go_wg_def_portal +######*/ + +static float SpawnLocation[10][3]= +{ + { 5153.41f, 2901.35f, 409.191f }, + { 5268.70f, 2666.42f, 409.099f }, + { 5197.05f, 2944.81f, 409.191f }, + { 5196.67f, 2737.34f, 409.189f }, + { 5314.58f, 3055.85f, 408.862f }, + { 5391.28f, 2828.09f, 418.675f }, + { 5153.93f, 2781.67f, 409.246f }, + { 5311.44f, 2618.93f, 409.092f }, + { 5269.21f, 3013.84f, 408.77f }, + { 5401.63f, 2853.67f, 418.675f }, +}; + +static float TeleLocation[10][3]= +{ + { 5157.1f, 2912.0f, 413.494f }, + { 5270.11f, 2655.62f, 413.403f }, + { 5187.48f, 2942.62f, 413.495f }, + { 5187.25f, 2739.45f, 413.492f }, + { 5304.47f, 3054.62f, 412.147f }, + { 5401.77f, 2853.72f, 418.896f }, + { 5155.76f, 2771.45f, 413.493f }, + { 5302.64f, 2623.39f, 413.403f }, + { 5271.58f, 3023.12f, 412.147f }, + { 5391.28f, 2828.09f, 418.675f }, +}; + +bool GOHello_go_wg_teleport(Player* pPlayer, GameObject* pGo) +{ + for (uint32 i=0; i < 10; ++i) + { + if (fabs(pGo->GetDistance2d(SpawnLocation[i][0], SpawnLocation[i][1])) < M_NULL_F) + pPlayer->TeleportTo(pPlayer->GetMapId(),TeleLocation[i][0],TeleLocation[i][1],TeleLocation[i][2],0); + } + + return false; +} + +/*###### +## npc_wg_demolisher_engineer +######*/ + +#define GOSSIP_HELLO_DEMO1 "Build catapult." +#define GOSSIP_HELLO_DEMO2 "Build demolisher." +#define GOSSIP_HELLO_DEMO3 "Build siege engine." +#define GOSSIP_HELLO_DEMO4 "I cannot build more!" + +enum +{ + //WG World States + WS_VEHICLE_COUNT_H = 3490, + WS_VEHICLE_COUNT_MAX_H = 3491, + WS_VEHICLE_COUNT_A = 3680, + WS_VEHICLE_COUNT_MAX_A = 3681, + //Spells + SPELL_CORPORAL = 33280, + SPELL_LIEUTENANT = 55629, + //BuildSpellsWG + SPELL_BUILD_CATAPULT = 56664, + SPELL_BUILD_DEMOLISHER = 56659, + SPELL_BUILD_SIEGE_A = 56662, + SPELL_BUILD_SIEGE_H = 61409, +}; + +bool GossipHello_npc_wg_demolisher_engineer(Player* pPlayer, Creature* pCreature) +{ + uint32 team = 0; + uint32 count = 0; + uint32 maxCount = 0; + + if (pCreature->GetEntry() == 30499) + { + team = ALLIANCE; + count = pCreature->GetWorldState(WS_VEHICLE_COUNT_A); + maxCount = pCreature->GetWorldState(WS_VEHICLE_COUNT_MAX_A); + } + else if(pCreature->GetEntry() == 30400) + { + team = HORDE; + count = pCreature->GetWorldState(WS_VEHICLE_COUNT_H); + maxCount = pCreature->GetWorldState(WS_VEHICLE_COUNT_MAX_H); + } + + if (maxCount > count) + { + if (pPlayer->GetSpellAuraHolder(SPELL_CORPORAL)) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + else if (pPlayer->GetSpellAuraHolder(SPELL_LIEUTENANT)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + } + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +// FIXME - Need make over DB +bool GossipSelect_npc_wg_demolisher_engineer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF: + pPlayer->CastSpell(pPlayer, SPELL_BUILD_CATAPULT, true); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 1: + pPlayer->CastSpell(pPlayer, SPELL_BUILD_DEMOLISHER, true); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF + 2: + if(pCreature->GetEntry() == 30499) + pPlayer->CastSpell(pPlayer, SPELL_BUILD_SIEGE_A, true); + else if(pCreature->GetEntry() == 30400) + pPlayer->CastSpell(pPlayer, SPELL_BUILD_SIEGE_H, true); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + default: + break; + } + + return true; +} + +void AddSC_wintergrasp() +{ + Script *pNewScript; + + pNewScript = new Script; + pNewScript->Name = "go_wg_teleport"; + pNewScript->pGOUse = &GOHello_go_wg_teleport; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_wg_demolisher_engineer"; + pNewScript->pGossipHello = &GossipHello_npc_wg_demolisher_engineer; + pNewScript->pGossipSelect = &GossipSelect_npc_wg_demolisher_engineer; + pNewScript->RegisterSelf(); +} \ No newline at end of file diff --git a/scripts/northrend/zuldrak.cpp b/scripts/northrend/zuldrak.cpp index d0c526ea62..0ff963790d 100644 --- a/scripts/northrend/zuldrak.cpp +++ b/scripts/northrend/zuldrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 @@ -48,26 +51,29 @@ struct MANGOS_DLL_DECL npc_gurgthockAI : public ScriptedAI { npc_gurgthockAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; - void SetPlayerGUID(uint64 uiPlayerGUID) { m_uiPlayerGUID = uiPlayerGUID; } + void SetPlayer(Player* pPlayer) + { + m_playerGuid = pPlayer->GetObjectGuid(); + } - void Reset() + void Reset() override { - m_uiPlayerGUID = 0; + 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]) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) pPlayer->GroupEventHappens(QUEST_FROM_BEYOND, m_creature); - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); return; } } @@ -78,10 +84,10 @@ 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->SetPlayerGUID(pPlayer->GetGUID()); + pGurthockAI->SetPlayer(pPlayer); } return true; } @@ -91,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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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; @@ -98,6 +279,17 @@ void AddSC_zuldrak() pNewScript = new Script; pNewScript->Name = "npc_gurgthock"; pNewScript->GetAI = &GetAI_npc_gurgthock; - pNewScript->pQuestAccept = &QuestAccept_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 943b36d8a9..8e0dabc19a 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, @@ -50,7 +52,9 @@ struct MANGOS_DLL_DECL mob_stolen_soulAI : public ScriptedAI 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; @@ -156,7 +166,7 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI Reset(); } - uint64 m_uiTargetGUID; + ObjectGuid m_targetGuid; uint32 m_uiFearTimer; uint32 m_uiRibbonOfSoulsTimer; @@ -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_uiTargetGUID = 0; + 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_uiTargetGUID)) + 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,43 +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)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_STOLEN_SOUL, SELECT_FLAG_PLAYER)) { - if (pTarget->GetTypeId() == TYPEID_PLAYER) + if (DoCastSpellIfCan(pTarget, SPELL_STOLEN_SOUL) == CAST_OK) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - DoScriptText(urand(0, 1) ? SAY_ROAR : SAY_SOUL_CLEAVE, m_creature); - - m_uiTargetGUID = pTarget->GetGUID(); + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_ROAR : SAY_SOUL_CLEAVE, m_creature); - DoCastSpellIfCan(pTarget, SPELL_STOLEN_SOUL); - 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 - m_uiStolenSoulTimer = 1000; } } else @@ -277,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; @@ -301,61 +307,17 @@ 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 +void AddSC_boss_exarch_maladaar() { - 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; + Script* pNewScript; - DoMeleeAttackIfReady(); - } -}; + pNewScript = new Script; + pNewScript->Name = "boss_exarch_maladaar"; + pNewScript->GetAI = &GetAI_boss_exarch_maladaar; + pNewScript->RegisterSelf(); -CreatureAI* GetAI_mob_avatar_of_martyred(Creature* pCreature) -{ - return new mob_avatar_of_martyredAI(pCreature); -} - -void AddSC_boss_exarch_maladaar() -{ - Script* newscript; - - newscript = new Script; - newscript->Name = "boss_exarch_maladaar"; - newscript->GetAI = &GetAI_boss_exarch_maladaar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_avatar_of_martyred"; - newscript->GetAI = &GetAI_mob_avatar_of_martyred; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_stolen_soul"; - newscript->GetAI = &GetAI_mob_stolen_soul; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_stolen_soul"; + pNewScript->GetAI = &GetAI_mob_stolen_soul; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp b/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp new file mode 100644 index 0000000000..479a7081f9 --- /dev/null +++ b/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp @@ -0,0 +1,152 @@ +/* Copyright (C) 2006 - 2013 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_shirrak +SD%Complete: 100 +SDComment: +SDCategory: Auchindoun, Auchenai Crypts +EndScriptData */ + +#include "precompiled.h" + +enum +{ + EMOTE_FOCUS = -1558010, + + SPELL_CARNIVOROUS_BITE = 36383, + SPELL_CARNIVOROUS_BITE_H = 39382, + SPELL_INHIBIT_MAGIC = 32264, + SPELL_ATTRACT_MAGIC = 32265, + + SPELL_FOCUS_TARGET_VISUAL = 32286, + NPC_FOCUS_FIRE = 18374 +}; + +struct MANGOS_DLL_DECL boss_shirrakAI : public ScriptedAI +{ + boss_shirrakAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + + uint32 m_uiCarnivorousBiteTimer; + uint32 m_uiFocusFireTimer; + uint32 m_uiAttractMagicTimer; + + uint8 m_uiFocusFireCount; + + ObjectGuid m_focusTargetGuid; + + void Reset() override + { + m_uiCarnivorousBiteTimer = urand(4000, 7000); + m_uiFocusFireTimer = 15000; + m_uiAttractMagicTimer = urand(20000, 24000); + m_uiFocusFireCount = 0; + + DoCastSpellIfCan(m_creature, SPELL_INHIBIT_MAGIC); + } + + 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) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCarnivorousBiteTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CARNIVOROUS_BITE : SPELL_CARNIVOROUS_BITE_H) == CAST_OK) + m_uiCarnivorousBiteTimer = urand(4000, 10000); + } + else + m_uiCarnivorousBiteTimer -= uiDiff; + + if (m_uiAttractMagicTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ATTRACT_MAGIC) == CAST_OK) + m_uiAttractMagicTimer = urand(25000, 38000); + } + else + m_uiAttractMagicTimer -= uiDiff; + + if (m_uiFocusFireTimer < uiDiff) + { + ++m_uiFocusFireCount; + Unit* pTarget = NULL; + + switch (m_uiFocusFireCount) + { + case 1: + { + // engage the target + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_PLAYER); + + if (!pTarget) + pTarget = m_creature->getVictim(); + + DoScriptText(EMOTE_FOCUS, m_creature, pTarget); + m_focusTargetGuid = pTarget->GetObjectGuid(); + // no break; + } + case 2: + // we have a delay of 1 sec between the summons + m_uiFocusFireTimer = 1000; + break; + case 3: + // reset the timers and the summon count + m_uiFocusFireCount = 0; + m_uiFocusFireTimer = 15000; + break; + } + + if (!pTarget) + pTarget = m_creature->GetMap()->GetUnit(m_focusTargetGuid); + + // Summon focus fire at target location + if (pTarget) + m_creature->SummonCreature(NPC_FOCUS_FIRE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); + } + else + m_uiFocusFireTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_shirrak(Creature* pCreature) +{ + return new boss_shirrakAI(pCreature); +} + +void AddSC_boss_shirrak() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_shirrak"; + pNewScript->GetAI = &GetAI_boss_shirrak; + pNewScript->RegisterSelf(); +} diff --git a/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp b/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp index 39cae8b157..190d43e147 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,10 +44,8 @@ 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 @@ -58,29 +56,26 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI Reset(); } - uint32 m_uiBlink_Timer; - uint32 m_uiBeacon_Timer; - uint32 m_uiFireBall_Timer; - uint32 m_uiFrostbolt_Timer; - uint32 m_uiFrostNova_Timer; + uint32 m_uiBlinkTimer; + uint32 m_uiBeaconTimer; + uint32 m_uiFireBallTimer; + uint32 m_uiFrostboltTimer; + uint32 m_uiFrostNovaTimer; bool m_bHasTaunted; - bool m_bCanBlink; - void Reset() + void Reset() override { - m_uiBlink_Timer = 1500; - m_uiBeacon_Timer = 10000; - m_uiFireBall_Timer = 8000; - m_uiFrostbolt_Timer = 4000; - m_uiFrostNova_Timer = 15000; - - m_bCanBlink = false; + m_uiBlinkTimer = 30000; + 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; @@ -89,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; @@ -99,82 +94,78 @@ 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; - if (m_uiFrostNova_Timer < uiDiff) + if (m_uiFrostNovaTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - DoCastSpellIfCan(m_creature,SPELL_FROSTNOVA); - m_uiFrostNova_Timer = urand(17500, 25000); - m_bCanBlink = true; - }else m_uiFrostNova_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_FROSTNOVA) == CAST_OK) + m_uiFrostNovaTimer = urand(10000, 20000); + } + else + m_uiFrostNovaTimer -= uiDiff; - if (m_uiFrostbolt_Timer < uiDiff) + if (m_uiFrostboltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLT); - m_uiFrostbolt_Timer = urand(4500, 6000); - }else m_uiFrostbolt_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROSTBOLT) == CAST_OK) + m_uiFrostboltTimer = urand(3000, 8000); + } + else + m_uiFrostboltTimer -= uiDiff; - if (m_uiFireBall_Timer < uiDiff) + if (m_uiFireBallTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FIREBALL); - m_uiFireBall_Timer = urand(4500, 6000); - }else m_uiFireBall_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL) == CAST_OK) + m_uiFireBallTimer = urand(3000, 8000); + } + else + m_uiFireBallTimer -= uiDiff; - if (m_bCanBlink) + if (m_uiBlinkTimer <= uiDiff) { - if (m_uiBlink_Timer < uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_BLINK) == CAST_OK) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - //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(); - DoCastSpellIfCan(m_creature,SPELL_BLINK); - - m_uiBlink_Timer = urand(1000, 2500); - m_bCanBlink = false; - }else m_uiBlink_Timer -= uiDiff; + m_uiBlinkTimer = urand(25000, 30000); + } } + else + m_uiBlinkTimer -= uiDiff; - if (m_uiBeacon_Timer < uiDiff) + if (m_uiBeaconTimer < uiDiff) { - if (!urand(0,3)) - DoScriptText(SAY_SUMMON, m_creature); - - DoCastSpellIfCan(m_creature, SPELL_ETHEREAL_BEACON, CAST_TRIGGERED); + if (DoCastSpellIfCan(m_creature, SPELL_ETHEREAL_BEACON) == CAST_OK) + { + if (!urand(0, 3)) + DoScriptText(SAY_SUMMON, m_creature); - m_uiBeacon_Timer = 10000; - }else m_uiBeacon_Timer -= uiDiff; + m_uiBeaconTimer = urand(45000, 75000); + } + } + else + m_uiBeaconTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -185,81 +176,12 @@ 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_uiApprentice_Timer; - uint32 m_uiArcaneBolt_Timer; - - void Reset() - { - m_uiApprentice_Timer = m_bIsRegularMode ? 20000 : 10000; - m_uiArcaneBolt_Timer = 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_uiArcaneBolt_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BOLT); - m_uiArcaneBolt_Timer = urand(2000, 4500); - }else m_uiArcaneBolt_Timer -= uiDiff; - - if (m_uiApprentice_Timer < uiDiff) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - m_creature->CastSpell(m_creature, SPELL_ETHEREAL_APPRENTICE, true); - - m_creature->ForcedDespawn(); - return; - - }else m_uiApprentice_Timer -= 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_nexusprince_shaffar"; - newscript->GetAI = &GetAI_boss_nexusprince_shaffar; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "mob_ethereal_beacon"; - newscript->GetAI = &GetAI_mob_ethereal_beacon; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_nexusprince_shaffar"; + pNewScript->GetAI = &GetAI_boss_nexusprince_shaffar; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp b/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp index 8be002a7a0..f943993b36 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,28 +16,30 @@ /* 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 */ #include "precompiled.h" -#define SAY_AGGRO_1 -1557008 -#define SAY_AGGRO_2 -1557009 -#define SAY_AGGRO_3 -1557010 - -#define SAY_KILL_1 -1557011 -#define SAY_KILL_2 -1557012 - -#define SAY_DEATH -1557013 - -#define EMOTE_DARK_SHELL -1557014 - -#define SPELL_VOID_BLAST 32325 -#define H_SPELL_VOID_BLAST 38760 -#define SPELL_DARK_SHELL 32358 -#define H_SPELL_DARK_SHELL 38759 +enum +{ + SAY_AGGRO_1 = -1557008, + SAY_AGGRO_2 = -1557009, + SAY_AGGRO_3 = -1557010, + SAY_KILL_1 = -1557011, + SAY_KILL_2 = -1557012, + SAY_DEATH = -1557013, + EMOTE_DARK_SHELL = -1557014, + + SPELL_VOID_BLAST = 32325, + SPELL_VOID_BLAST_H = 38760, + SPELL_DARK_SHELL = 32358, + SPELL_DARK_SHELL_H = 38759, + + MAX_VOID_BLASTS = 5, +}; struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI { @@ -48,71 +50,77 @@ struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI } bool m_bIsRegularMode; - uint32 VoidBlast_Timer; - uint32 DarkShell_Timer; - uint32 VoidBlast_Counter; - void Reset() + uint32 m_uiVoidBlastTimer; + uint32 m_uiDarkShellTimer; + uint8 m_uiVoidBlastCounter; + + void Reset() override { - VoidBlast_Timer = urand(8000, 23000); - DarkShell_Timer = 20000; - VoidBlast_Counter = 0; + m_uiVoidBlastTimer = urand(15000, 20000); + m_uiDarkShellTimer = 15000; + m_uiVoidBlastCounter = 0; } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - 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; case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; } - } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (VoidBlast_Timer < diff) + if (m_uiVoidBlastTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_VOID_BLAST : SPELL_VOID_BLAST_H); + + // reset timer and counter when counter has reached the max limit + if (m_uiVoidBlastCounter == MAX_VOID_BLASTS) { - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_VOID_BLAST : H_SPELL_VOID_BLAST); - VoidBlast_Timer = 500; - ++VoidBlast_Counter; + m_uiVoidBlastTimer = urand(25000, 30000); + m_uiVoidBlastCounter = 0; } - - if (VoidBlast_Counter == 5) + // cast the void blasts in a row until we reach the max limit + else { - VoidBlast_Timer = urand(15000, 25000); - VoidBlast_Counter = 0; + m_uiVoidBlastTimer = 500; + ++m_uiVoidBlastCounter; } - }else VoidBlast_Timer -= diff; + } + else + m_uiVoidBlastTimer -= uiDiff; - if (!VoidBlast_Counter) + // use the darkshell only when the boss isn't casting the void blasts + if (!m_uiVoidBlastCounter) { - if (DarkShell_Timer < diff) + if (m_uiDarkShellTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - DoScriptText(EMOTE_DARK_SHELL, m_creature); - - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DARK_SHELL : H_SPELL_DARK_SHELL); - DarkShell_Timer = 20000; - }else DarkShell_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DARK_SHELL : SPELL_DARK_SHELL_H) == CAST_OK) + { + DoScriptText(EMOTE_DARK_SHELL, m_creature); + m_uiDarkShellTimer = urand(25000, 30000); + } + } + else + m_uiDarkShellTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -126,9 +134,10 @@ CreatureAI* GetAI_boss_pandemonius(Creature* pCreature) void AddSC_boss_pandemonius() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_pandemonius"; - newscript->GetAI = &GetAI_boss_pandemonius; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_pandemonius"; + pNewScript->GetAI = &GetAI_boss_pandemonius; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp b/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp new file mode 100644 index 0000000000..caae48e967 --- /dev/null +++ b/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp @@ -0,0 +1,236 @@ +/* Copyright (C) 2006 - 2013 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_anzu +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 MANGOS_DLL_DECL 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 d5dd136c19..9a45b455c8 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,44 +16,46 @@ /* ScriptData SDName: Boss_Darkweaver_Syth -SD%Complete: 85 -SDComment: Shock spells/times need more work. +SD%Complete: 100 +SDComment: SDCategory: Auchindoun, Sethekk Halls EndScriptData */ #include "precompiled.h" -#define SAY_SUMMON -1556000 - -#define SAY_AGGRO_1 -1556001 -#define SAY_AGGRO_2 -1556002 -#define SAY_AGGRO_3 -1556003 - -#define SAY_SLAY_1 -1556004 -#define SAY_SLAY_2 -1556005 - -#define SAY_DEATH -1556006 - -#define SPELL_FROST_SHOCK 37865 -#define SPELL_FLAME_SHOCK 34354 -#define SPELL_SHADOW_SHOCK 30138 -#define SPELL_ARCANE_SHOCK 37132 - -#define SPELL_CHAIN_LIGHTNING 39945 - -#define SPELL_SUMMON_SYTH_FIRE 33537 // Spawns 19203 -#define SPELL_SUMMON_SYTH_ARCANE 33538 // Spawns 19205 -#define SPELL_SUMMON_SYTH_FROST 33539 // Spawns 19204 -#define SPELL_SUMMON_SYTH_SHADOW 33540 // Spawns 19206 - -#define SPELL_FLAME_BUFFET 33526 -#define H_SPELL_FLAME_BUFFET 38141 -#define SPELL_ARCANE_BUFFET 33527 -#define H_SPELL_ARCANE_BUFFET 38138 -#define SPELL_FROST_BUFFET 33528 -#define H_SPELL_FROST_BUFFET 38142 -#define SPELL_SHADOW_BUFFET 33529 -#define H_SPELL_SHADOW_BUFFET 38143 +enum +{ + SAY_SUMMON = -1556000, + SAY_AGGRO_1 = -1556001, + SAY_AGGRO_2 = -1556002, + SAY_AGGRO_3 = -1556003, + SAY_SLAY_1 = -1556004, + SAY_SLAY_2 = -1556005, + SAY_DEATH = -1556006, + + 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 = 15659, + SPELL_CHAIN_LIGHTNING_H = 15305, + + SPELL_SUMMON_SYTH_FIRE = 33537, // Spawns 19203 + SPELL_SUMMON_SYTH_ARCANE = 33538, // Spawns 19205 + SPELL_SUMMON_SYTH_FROST = 33539, // Spawns 19204 + SPELL_SUMMON_SYTH_SHADOW = 33540, // Spawns 19206 + + // Npc entries + NPC_FIRE_ELEMENTAL = 19203, + NPC_FROST_ELEMENTAL = 19204, + NPC_ARCANE_ELEMENTAL = 19205, + NPC_SHADOW_ELEMENTAL = 19206, +}; struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI { @@ -64,32 +66,28 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI } bool m_bIsRegularMode; - uint32 flameshock_timer; - uint32 arcaneshock_timer; - uint32 frostshock_timer; - uint32 shadowshock_timer; - uint32 chainlightning_timer; + uint32 m_uiFlameshockTimer; + uint32 m_uiArcaneshockTimer; + uint32 m_uiFrostshockTimer; + uint32 m_uiShadowshockTimer; + uint32 m_uiChainlightningTimer; - bool summon90; - bool summon50; - bool summon10; + float m_fHpCheck; - void Reset() + void Reset() override { - flameshock_timer = 2000; - arcaneshock_timer = 4000; - frostshock_timer = 6000; - shadowshock_timer = 8000; - chainlightning_timer = 15000; - - summon90 = false; - summon50 = false; - summon10 = false; + m_uiFlameshockTimer = 18000; + m_uiArcaneshockTimer = 19000; + m_uiFrostshockTimer = 18000; + m_uiShadowshockTimer = 17000; + m_uiChainlightningTimer = urand(6000, 9000); + + m_fHpCheck = 90.0f; } - 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; @@ -97,12 +95,12 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI } } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -110,12 +108,29 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustSummoned(Creature *summoned) + void JustSummoned(Creature* pSummoned) override { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - summoned->AI()->AttackStart(target); + switch (pSummoned->GetEntry()) + { + case NPC_FIRE_ELEMENTAL: + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); + break; + case NPC_FROST_ELEMENTAL: + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); + break; + case NPC_ARCANE_ELEMENTAL: + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true); + break; + case NPC_SHADOW_ELEMENTAL: + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); + break; + } + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } + // Wrapper to handle the elementals summon void SythSummoning() { DoScriptText(SAY_SUMMON, m_creature); @@ -123,74 +138,78 @@ 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->GetHealthPercent() < 90.0f && !summon90) + // Summon elementals at 90%, 50% and 10% health + if (m_creature->GetHealthPercent() < m_fHpCheck) { SythSummoning(); - summon90 = true; + m_fHpCheck -= 40.0f; } - if (m_creature->GetHealthPercent() < 50.0f && !summon50) + if (m_uiFlameshockTimer < uiDiff) { - SythSummoning(); - summon50 = true; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + 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 + m_uiFlameshockTimer -= uiDiff; - if (m_creature->GetHealthPercent() < 10.0f && !summon10) + if (m_uiArcaneshockTimer < uiDiff) { - SythSummoning(); - summon10 = true; + 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 = m_bIsRegularMode ? urand(13000, 28000) : urand(11000, 20000); + } } + else + m_uiArcaneshockTimer -= uiDiff; - if (flameshock_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_FLAME_SHOCK); - - flameshock_timer = urand(10000, 15000); - } else flameshock_timer -= diff; - - if (arcaneshock_timer < diff) + if (m_uiFrostshockTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_ARCANE_SHOCK); - - arcaneshock_timer = urand(10000, 15000); - } else arcaneshock_timer -= diff; - - if (frostshock_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_FROST_SHOCK); - - frostshock_timer = urand(10000, 15000); - } else frostshock_timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + 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 + m_uiFrostshockTimer -= uiDiff; - if (shadowshock_timer < diff) + if (m_uiShadowshockTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_SHADOW_SHOCK); - - shadowshock_timer = urand(10000, 15000); - } else shadowshock_timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + 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 + m_uiShadowshockTimer -= uiDiff; - if (chainlightning_timer < diff) + if (m_uiChainlightningTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_CHAIN_LIGHTNING); - - chainlightning_timer = 25000; - } else chainlightning_timer -= 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 = m_bIsRegularMode ? urand(14000, 26000) : urand(13000, 19000); + } + } + else + m_uiChainlightningTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -201,231 +220,12 @@ 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() - { - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); - 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 ? H_SPELL_FLAME_BUFFET : SPELL_FLAME_BUFFET); - - 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() - { - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true); - 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 ? H_SPELL_ARCANE_BUFFET : SPELL_ARCANE_BUFFET); - - 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() - { - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); - 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 ? H_SPELL_FROST_BUFFET : SPELL_FROST_BUFFET); - - 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 +void AddSC_boss_darkweaver_syth() { - mob_syth_shadowAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - uint32 shadowshock_timer; - uint32 shadowbuffet_timer; + Script* pNewScript; - void Reset() - { - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); - 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 ? H_SPELL_SHADOW_BUFFET : SPELL_SHADOW_BUFFET); - - shadowbuffet_timer = 5000; - }else shadowbuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_shadow(Creature* pCreature) -{ - return new mob_syth_shadowAI(pCreature); + pNewScript = new Script; + pNewScript->Name = "boss_darkweaver_syth"; + pNewScript->GetAI = &GetAI_boss_darkweaver_syth; + pNewScript->RegisterSelf(); } - -void AddSC_boss_darkweaver_syth() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_darkweaver_syth"; - newscript->GetAI = &GetAI_boss_darkweaver_syth; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_syth_fire"; - newscript->GetAI = &GetAI_mob_syth_fire; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_syth_arcane"; - newscript->GetAI = &GetAI_mob_syth_arcane; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_syth_frost"; - newscript->GetAI = &GetAI_mob_syth_frost; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_syth_shadow"; - newscript->GetAI = &GetAI_mob_syth_shadow; - newscript->RegisterSelf(); -} \ No newline at end of file diff --git a/scripts/outland/auchindoun/sethekk_halls/boss_tailonking_ikiss.cpp b/scripts/outland/auchindoun/sethekk_halls/boss_tailonking_ikiss.cpp deleted file mode 100644 index 293e1a03a7..0000000000 --- a/scripts/outland/auchindoun/sethekk_halls/boss_tailonking_ikiss.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (C) 2006 - 2010 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_Talon_King_Ikiss -SD%Complete: 80 -SDComment: Heroic supported. Some details missing, but most are spell related. -SDCategory: Auchindoun, Sethekk Halls -EndScriptData */ - -#include "precompiled.h" -#include "sethekk_halls.h" - -#define SAY_INTRO -1556007 -#define SAY_AGGRO_1 -1556008 -#define SAY_AGGRO_2 -1556009 -#define SAY_AGGRO_3 -1556010 -#define SAY_SLAY_1 -1556011 -#define SAY_SLAY_2 -1556012 -#define SAY_DEATH -1556013 -#define EMOTE_ARCANE_EXP -1556015 - -#define SPELL_BLINK 38194 -#define SPELL_BLINK_TELEPORT 38203 -#define SPELL_MANA_SHIELD 38151 -#define SPELL_ARCANE_BUBBLE 9438 -#define H_SPELL_SLOW 35032 - -#define SPELL_POLYMORPH 38245 -#define H_SPELL_POLYMORPH 43309 - -#define SPELL_ARCANE_VOLLEY 35059 -#define H_SPELL_ARCANE_VOLLEY 40424 - -#define SPELL_ARCANE_EXPLOSION 38197 -#define H_SPELL_ARCANE_EXPLOSION 40425 - -struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI -{ - boss_talon_king_ikissAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; - - uint32 ArcaneVolley_Timer; - uint32 Sheep_Timer; - uint32 Blink_Timer; - uint32 Slow_Timer; - - bool ManaShield; - bool Blink; - bool Intro; - - void Reset() - { - ArcaneVolley_Timer = 5000; - Sheep_Timer = 8000; - Blink_Timer = 35000; - Slow_Timer = urand(15000, 30000); - Blink = false; - Intro = false; - ManaShield = false; - } - - void MoveInLineOfSight(Unit *who) - { - if (!m_creature->getVictim() && who->isTargetableForAttack() && (m_creature->IsHostileTo(who)) && who->isInAccessablePlaceFor(m_creature)) - { - if (!Intro && m_creature->IsWithinDistInMap(who, 100)) - { - Intro = true; - DoScriptText(SAY_INTRO, m_creature); - } - - if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(who); - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) - { - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - } - } - - void Aggro(Unit *who) - { - switch(urand(0, 2)) - { - case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; - case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; - case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; - } - } - - void JustDied(Unit* Killer) - { - DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(DATA_IKISSDOOREVENT, DONE); - } - - void KilledUnit(Unit* victim) - { - DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (Blink) - { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_EXPLOSION : H_SPELL_ARCANE_EXPLOSION); - m_creature->CastSpell(m_creature,SPELL_ARCANE_BUBBLE,true); - Blink = false; - } - - if (ArcaneVolley_Timer < diff) - { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_VOLLEY : H_SPELL_ARCANE_VOLLEY); - ArcaneVolley_Timer = urand(7000, 12000); - }else ArcaneVolley_Timer -= diff; - - if (Sheep_Timer < diff) - { - //second top aggro target in normal, random target in heroic correct? - Unit *target = NULL; - if (m_bIsRegularMode ? target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1) : target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_POLYMORPH : H_SPELL_POLYMORPH); - Sheep_Timer = urand(15000, 17500); - }else Sheep_Timer -= diff; - - //may not be correct time to cast - if (!ManaShield && m_creature->GetHealthPercent() < 20.0f) - { - DoCastSpellIfCan(m_creature,SPELL_MANA_SHIELD); - ManaShield = true; - } - - if (!m_bIsRegularMode) - { - if (Slow_Timer < diff) - { - DoCastSpellIfCan(m_creature,H_SPELL_SLOW); - Slow_Timer = urand(15000, 40000); - }else Slow_Timer -= diff; - } - - if (Blink_Timer < diff) - { - DoScriptText(EMOTE_ARCANE_EXP, m_creature); - - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - //Spell doesn't work, but we use for visual effect at least - DoCastSpellIfCan(target,SPELL_BLINK); - - float X = target->GetPositionX(); - float Y = target->GetPositionY(); - float Z = target->GetPositionZ(); - - m_creature->GetMap()->CreatureRelocation(m_creature,X,Y,Z,0.0f); - m_creature->SendMonsterMove(X, Y, Z, SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, 1); - - DoCastSpellIfCan(target,SPELL_BLINK_TELEPORT); - Blink = true; - } - Blink_Timer = urand(35000, 40000); - }else Blink_Timer -= diff; - - if (!Blink) - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_talon_king_ikiss(Creature* pCreature) -{ - return new boss_talon_king_ikissAI(pCreature); -} - -void AddSC_boss_talon_king_ikiss() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_talon_king_ikiss"; - newscript->GetAI = &GetAI_boss_talon_king_ikiss; - newscript->RegisterSelf(); -} diff --git a/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp b/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp new file mode 100644 index 0000000000..ffae43d0fb --- /dev/null +++ b/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp @@ -0,0 +1,222 @@ +/* Copyright (C) 2006 - 2013 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_Talon_King_Ikiss +SD%Complete: 100 +SDComment: +SDCategory: Auchindoun, Sethekk Halls +EndScriptData */ + +#include "precompiled.h" +#include "sethekk_halls.h" + +enum +{ + SAY_INTRO = -1556007, + SAY_AGGRO_1 = -1556008, + SAY_AGGRO_2 = -1556009, + SAY_AGGRO_3 = -1556010, + SAY_SLAY_1 = -1556011, + SAY_SLAY_2 = -1556012, + SAY_DEATH = -1556013, + EMOTE_ARCANE_EXP = -1556015, + + SPELL_BLINK = 38194, + SPELL_MANA_SHIELD = 38151, + SPELL_ARCANE_BUBBLE = 9438, + SPELL_SLOW_H = 35032, + + SPELL_POLYMORPH = 38245, + SPELL_POLYMORPH_H = 43309, + + SPELL_ARCANE_VOLLEY = 35059, + SPELL_ARCANE_VOLLEY_H = 40424, + + SPELL_ARCANE_EXPLOSION = 38197, + SPELL_ARCANE_EXPLOSION_H = 40425, +}; + +struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI +{ + boss_talon_king_ikissAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bIntro = false; + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiArcaneVolleyTimer; + uint32 m_uiSheepTimer; + uint32 m_uiSlowTimer; + uint8 m_uiBlinkPhase; + float m_fHealthCheck; + + bool m_bManaShield; + bool m_bBlink; + bool m_bIntro; + + void Reset() override + { + m_uiArcaneVolleyTimer = urand(5000, 12000); + m_uiSheepTimer = 8000; + m_uiSlowTimer = urand(9000, 13000); + m_uiBlinkPhase = 0; + m_fHealthCheck = 80.0f; + + m_bBlink = false; + m_bManaShield = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_creature->getVictim() && pWho->isTargetableForAttack() && (m_creature->IsHostileTo(pWho)) && pWho->isInAccessablePlaceFor(m_creature)) + { + if (!m_bIntro && m_creature->IsWithinDistInMap(pWho, 100.0f)) + { + m_bIntro = true; + DoScriptText(SAY_INTRO, m_creature); + } + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* /*pWho*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_IKISS, IN_PROGRESS); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_IKISS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_IKISS, FAIL); + } + + void KilledUnit(Unit* /*pVctim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (EnterEvadeIfOutOfCombatArea(uiDiff)) + return; + + if (m_bBlink) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_EXPLOSION : SPELL_ARCANE_EXPLOSION_H); + DoCastSpellIfCan(m_creature, SPELL_ARCANE_BUBBLE, CAST_TRIGGERED); + DoResetThreat(); + m_bBlink = false; + } + + if (m_uiArcaneVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY_H) == CAST_OK) + m_uiArcaneVolleyTimer = urand(8000, 12000); + } + else + m_uiArcaneVolleyTimer -= uiDiff; + + if (m_uiSheepTimer < uiDiff) + { + // second top aggro target in normal, random target in heroic + if (Unit* pTarget = m_bIsRegularMode ? m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1) : m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_POLYMORPH : SPELL_POLYMORPH_H); + m_uiSheepTimer = urand(15000, 17500); + } + else + m_uiSheepTimer -= uiDiff; + + if (!m_bManaShield && m_creature->GetHealthPercent() < 15.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_MANA_SHIELD) == CAST_OK) + m_bManaShield = true; + } + + if (!m_bIsRegularMode) + { + if (m_uiSlowTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SLOW_H) == CAST_OK) + m_uiSlowTimer = urand(15000, 24000); + } + else + m_uiSlowTimer -= uiDiff; + } + + if (m_creature->GetHealthPercent() < m_fHealthCheck) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLINK, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + m_bBlink = true; + 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; + } + } + + if (!m_bBlink) + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_talon_king_ikiss(Creature* pCreature) +{ + return new boss_talon_king_ikissAI(pCreature); +} + +void AddSC_boss_talon_king_ikiss() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_talon_king_ikiss"; + pNewScript->GetAI = &GetAI_boss_talon_king_ikiss; + pNewScript->RegisterSelf(); +} diff --git a/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp b/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp index 6bd4bd43b8..0eba1aba41 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,55 +16,171 @@ /* 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 */ #include "precompiled.h" #include "sethekk_halls.h" -#define IKISS_DOOR 177203 +instance_sethekk_halls::instance_sethekk_halls(Map* pMap) : ScriptedInstance(pMap) +{ + Initialize(); +} +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(); +} -struct MANGOS_DLL_DECL instance_sethekk_halls : public ScriptedInstance +void instance_sethekk_halls::OnObjectCreate(GameObject* pGo) { - instance_sethekk_halls(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + switch (pGo->GetEntry()) + { + case GO_IKISS_DOOR: + if (m_auiEncounter[TYPE_IKISS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_IKISS_CHEST: + 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; + } - uint64 m_uiIkissDoorGUID; + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void Initialize() +void instance_sethekk_halls::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - m_uiIkissDoorGUID = 0; + 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) + { + DoUseDoorOrButton(GO_IKISS_DOOR, DAY); + DoToggleGameObjectFlags(GO_IKISS_CHEST, GO_FLAG_NO_INTERACT | GO_FLAG_INTERACT_COND, false); + } + m_auiEncounter[uiType] = uiData; + break; + default: + return; } - void OnObjectCreate(GameObject* pGo) + if (uiData == DONE) { - if (pGo->GetEntry() == IKISS_DOOR) - m_uiIkissDoorGUID = pGo->GetGUID(); + 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_sethekk_halls::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - void SetData(uint32 uiType, uint32 uiData) + return 0; +} + +void instance_sethekk_halls::Load(const char* chrIn) +{ + if (!chrIn) { - switch(uiType) - { - case DATA_IKISSDOOREVENT: - if (uiData == DONE) - DoUseDoorOrButton(m_uiIkissDoorGUID,DAY*IN_MILLISECONDS); - break; - } + 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_sethekk_halls::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + if (uiCriteriaId != ACHIEV_CRITA_TURKEY_TIME) + return false; + + if (!pSource) + return false; + + return pSource->HasItemOrGemWithIdEquipped(ITEM_PILGRIMS_HAT, 1) && (pSource->HasItemOrGemWithIdEquipped(ITEM_PILGRIMS_DRESS, 1) + || pSource->HasItemOrGemWithIdEquipped(ITEM_PILGRIMS_ROBE, 1) || pSource->HasItemOrGemWithIdEquipped(ITEM_PILGRIMS_ATTIRE, 1)); +} 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 *newscript; - newscript = new Script; - newscript->Name = "instance_sethekk_halls"; - newscript->GetInstanceData = &GetInstanceData_instance_sethekk_halls; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + 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 c6034a9d3c..ee45a0f3ae 100644 --- a/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h +++ b/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h @@ -1,9 +1,62 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef DEF_SETHEKK_HALLS_H #define DEF_SETHEKK_HALLS_H -#define DATA_IKISSDOOREVENT 1 +enum +{ + MAX_ENCOUNTER = 3, + + TYPE_SYTH = 0, + 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, + ITEM_PILGRIMS_DRESS = 44785, + ITEM_PILGRIMS_ROBE = 46824, + ITEM_PILGRIMS_ATTIRE = 46800, +}; + +class MANGOS_DLL_DECL instance_sethekk_halls : public ScriptedInstance +{ + public: + instance_sethekk_halls(Map* pMap); + ~instance_sethekk_halls() {} + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + 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*/) 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; +}; + #endif diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp index 7e48175c51..50e4a8ce9c 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,117 +23,74 @@ EndScriptData */ #include "precompiled.h" #include "shadow_labyrinth.h" -#include "escort_ai.h" -#define SAY_INTRO -1555000 - -#define SAY_AGGRO1 -1555001 -#define SAY_AGGRO2 -1555002 -#define SAY_AGGRO3 -1555003 - -#define SAY_HELP -1555004 - -#define SAY_SLAY1 -1555005 -#define SAY_SLAY2 -1555006 - -#define SAY_DEATH -1555007 - -#define SPELL_BANISH 30231 -#define SPELL_CORROSIVE_ACID 33551 -#define SPELL_FEAR 33547 -#define SPELL_ENRAGE 34970 +enum +{ + SAY_AGGRO_1 = -1555001, + SAY_AGGRO_2 = -1555002, + SAY_AGGRO_3 = -1555003, + SAY_HELP = -1555004, + SAY_SLAY_1 = -1555005, + SAY_SLAY_2 = -1555006, + SAY_DEATH = -1555007, + + SPELL_CORROSIVE_ACID = 33551, + SPELL_FEAR = 33547, + SPELL_ENRAGE = 34970 +}; -struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public npc_escortAI +struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI { - boss_ambassador_hellmawAI(Creature* pCreature) : npc_escortAI(pCreature) + 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(); } - ScriptedInstance* m_pInstance; + instance_shadow_labyrinth* m_pInstance; bool m_bIsRegularMode; - uint32 EventCheck_Timer; - uint32 CorrosiveAcid_Timer; - uint32 Fear_Timer; - uint32 Enrage_Timer; - bool Intro; - bool IsBanished; - bool Enraged; + uint32 m_uiBanishTimer; + uint32 m_uiCorrosiveAcidTimer; + uint32 m_uiFearTimer; + uint32 m_uiEnrageTimer; + bool m_bIsEnraged; - void Reset() + void Reset() override { - EventCheck_Timer = 5000; - CorrosiveAcid_Timer = urand(5000, 10000); - Fear_Timer = urand(25000, 30000); - Enrage_Timer = 180000; - Intro = false; - IsBanished = true; - Enraged = false; - - if (m_pInstance && m_creature->isAlive()) - { - if (m_pInstance->GetData(TYPE_OVERSEER) != DONE) - m_creature->CastSpell(m_creature, SPELL_BANISH, true); - } + 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 WaypointReached(uint32 i) + void Aggro(Unit* /*pWho*/) override { - } - - void DoIntro() - { - if (m_creature->HasAura(SPELL_BANISH, EFFECT_INDEX_0)) - m_creature->RemoveAurasDueToSpell(SPELL_BANISH); - - IsBanished = false; - Intro = true; - - if (m_pInstance) + switch (urand(0, 2)) { - if (m_pInstance->GetData(TYPE_HELLMAW) != FAIL) - { - DoScriptText(SAY_INTRO, m_creature); - Start(false, 0, NULL, false, true); - } - - m_pInstance->SetData(TYPE_HELLMAW, IN_PROGRESS); + case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; } - } - - void MoveInLineOfSight(Unit *who) - { - if (m_creature->HasAura(SPELL_BANISH, EFFECT_INDEX_0)) - return; - - npc_escortAI::MoveInLineOfSight(who); - } - void Aggro(Unit *who) - { - 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; - } + if (m_pInstance) + m_pInstance->SetData(TYPE_HELLMAW, IN_PROGRESS); } - 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 { DoScriptText(SAY_DEATH, m_creature); @@ -141,52 +98,55 @@ struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public npc_escortAI m_pInstance->SetData(TYPE_HELLMAW, DONE); } - void UpdateEscortAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!Intro && !HasEscortState(STATE_ESCORT_ESCORTING)) + if (m_uiBanishTimer) { - if (EventCheck_Timer < diff) + if (m_uiBanishTimer <= uiDiff) { - if (m_pInstance) + if (!m_pInstance) + return; + + // Check for banish + if (m_pInstance->IsHellmawUnbanished()) { - if (m_pInstance->GetData(TYPE_OVERSEER) == DONE) - { - DoIntro(); - return; - } + m_creature->RemoveAurasDueToSpell(SPELL_BANISH); + m_creature->GetMotionMaster()->MoveWaypoint(); + m_uiBanishTimer = 0; } - EventCheck_Timer = 5000; - return; } else - { - EventCheck_Timer -= diff; - return; - } + m_uiBanishTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (CorrosiveAcid_Timer < diff) + if (m_uiCorrosiveAcidTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CORROSIVE_ACID); - CorrosiveAcid_Timer = urand(15000, 25000); - }else CorrosiveAcid_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_CORROSIVE_ACID) == CAST_OK) + m_uiCorrosiveAcidTimer = urand(23000, 35000); + } + else + m_uiCorrosiveAcidTimer -= uiDiff; - if (Fear_Timer < diff) + if (m_uiFearTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_FEAR); - Fear_Timer = urand(20000, 35000); - }else Fear_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = urand(20000, 38000); + } + else + m_uiFearTimer -= uiDiff; - if (!m_bIsRegularMode) + if (!m_bIsRegularMode && !m_bIsEnraged) { - if (!Enraged && Enrage_Timer < diff) + if (m_uiEnrageTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_ENRAGE); - Enraged = true; - }else Enrage_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bIsEnraged = true; + } + else + m_uiEnrageTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -200,9 +160,10 @@ CreatureAI* GetAI_boss_ambassador_hellmaw(Creature* pCreature) void AddSC_boss_ambassador_hellmaw() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_ambassador_hellmaw"; - newscript->GetAI = &GetAI_boss_ambassador_hellmaw; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ambassador_hellmaw"; + pNewScript->GetAI = &GetAI_boss_ambassador_hellmaw; + pNewScript->RegisterSelf(); } 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 257ae653b7..5bf9abe41b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,40 +16,42 @@ /* ScriptData SDName: Boss_Blackheart_the_Inciter -SD%Complete: 75 -SDComment: Incite Chaos not functional since core lacks Mind Control support +SD%Complete: 90 +SDComment: Not all yells are implemented. SDCategory: Auchindoun, Shadow Labyrinth EndScriptData */ #include "precompiled.h" #include "shadow_labyrinth.h" -#define SPELL_INCITE_CHAOS 33676 -#define SPELL_INCITE_CHAOS_B 33684 //debuff applied to each member of party -#define SPELL_CHARGE 33709 -#define SPELL_WAR_STOMP 33707 - -#define SAY_INTRO1 -1555008 -#define SAY_INTRO2 -1555009 -#define SAY_INTRO3 -1555010 -#define SAY_AGGRO1 -1555011 -#define SAY_AGGRO2 -1555012 -#define SAY_AGGRO3 -1555013 -#define SAY_SLAY1 -1555014 -#define SAY_SLAY2 -1555015 -#define SAY_HELP -1555016 -#define SAY_DEATH -1555017 - -#define SAY2_INTRO1 -1555018 -#define SAY2_INTRO2 -1555019 -#define SAY2_INTRO3 -1555020 -#define SAY2_AGGRO1 -1555021 -#define SAY2_AGGRO2 -1555022 -#define SAY2_AGGRO3 -1555023 -#define SAY2_SLAY1 -1555024 -#define SAY2_SLAY2 -1555025 -#define SAY2_HELP -1555026 -#define SAY2_DEATH -1555027 +enum +{ + SPELL_INCITE_CHAOS = 33676, // triggers 33684 on party members + SPELL_CHARGE = 33709, + SPELL_WAR_STOMP = 33707, + + SAY_INTRO1 = -1555008, + SAY_INTRO2 = -1555009, + SAY_INTRO3 = -1555010, + SAY_AGGRO1 = -1555011, + SAY_AGGRO2 = -1555012, + SAY_AGGRO3 = -1555013, + SAY_SLAY1 = -1555014, + SAY_SLAY2 = -1555015, + SAY_HELP = -1555016, + SAY_DEATH = -1555017, + + SAY2_INTRO1 = -1555018, + SAY2_INTRO2 = -1555019, + SAY2_INTRO3 = -1555020, + SAY2_AGGRO1 = -1555021, + SAY2_AGGRO2 = -1555022, + SAY2_AGGRO3 = -1555023, + SAY2_SLAY1 = -1555024, + SAY2_SLAY2 = -1555025, + SAY2_HELP = -1555026, + SAY2_DEATH = -1555027, +}; struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI { @@ -61,30 +63,27 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI ScriptedInstance* m_pInstance; - bool InciteChaos; - uint32 InciteChaos_Timer; - uint32 InciteChaosWait_Timer; - uint32 Charge_Timer; - uint32 Knockback_Timer; + uint32 m_uiInciteChaosTimer; + uint32 m_uiInciteChaosWaitTimer; + uint32 m_uiChargeTimer; + uint32 m_uiKnockbackTimer; - void Reset() - { - InciteChaos = false; - InciteChaos_Timer = 20000; - InciteChaosWait_Timer = 15000; - Charge_Timer = 5000; - Knockback_Timer = 15000; + GuidVector m_vTargetsGuids; - if (m_pInstance) - m_pInstance->SetData(TYPE_INCITER, NOT_STARTED); + void Reset() override + { + m_uiInciteChaosWaitTimer = 0; + m_uiInciteChaosTimer = 15000; + m_uiChargeTimer = urand(30000, 37000); + m_uiKnockbackTimer = urand(10000, 14000); } - 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 { DoScriptText(SAY_DEATH, m_creature); @@ -92,9 +91,9 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI m_pInstance->SetData(TYPE_INCITER, DONE); } - void Aggro(Unit *who) + 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; @@ -105,60 +104,87 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI m_pInstance->SetData(TYPE_INCITER, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_pInstance) + m_pInstance->SetData(TYPE_INCITER, FAIL); + } + + void EnterEvadeMode() + { + // if we are waiting for Incite chaos to expire don't evade + if (m_uiInciteChaosWaitTimer) return; - if (InciteChaos) + ScriptedAI::EnterEvadeMode(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiInciteChaosWaitTimer) { - if (InciteChaosWait_Timer < diff) + if (m_uiInciteChaosWaitTimer <= uiDiff) { - InciteChaos = false; - InciteChaosWait_Timer = 15000; - }else InciteChaosWait_Timer -= diff; + // 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; - } - if (InciteChaos_Timer < diff) + if (m_uiInciteChaosTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_INCITE_CHAOS); + // Store the threat list + m_vTargetsGuids.clear(); + m_creature->FillGuidsListFromThreatList(m_vTargetsGuids); - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + if (DoCastSpellIfCan(m_creature, SPELL_INCITE_CHAOS) == CAST_OK) { - Unit* target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (target && target->GetTypeId() == TYPEID_PLAYER) - target->CastSpell(target,SPELL_INCITE_CHAOS_B,true); + m_creature->HandleEmote(EMOTE_STATE_LAUGH); + m_uiInciteChaosTimer = 55000; + m_uiInciteChaosWaitTimer = 16000; + return; } + } + else + m_uiInciteChaosTimer -= uiDiff; - DoResetThreat(); - InciteChaos = true; - InciteChaos_Timer = 40000; - return; - }else InciteChaos_Timer -= diff; - - //Charge_Timer - if (Charge_Timer < diff) + // Charge Timer + if (m_uiChargeTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, SPELL_CHARGE); - Charge_Timer = urand(15000, 25000); - }else Charge_Timer -= diff; + 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; - //Knockback_Timer - if (Knockback_Timer < diff) + // Knockback Timer + if (m_uiKnockbackTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP); - Knockback_Timer = urand(18000, 24000); - }else Knockback_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP) == CAST_OK) + m_uiKnockbackTimer = urand(15000, 30000); + } + else + m_uiKnockbackTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_blackheart_the_inciter(Creature* pCreature) { return new boss_blackheart_the_inciterAI(pCreature); @@ -166,9 +192,10 @@ CreatureAI* GetAI_boss_blackheart_the_inciter(Creature* pCreature) void AddSC_boss_blackheart_the_inciter() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_blackheart_the_inciter"; - newscript->GetAI = &GetAI_boss_blackheart_the_inciter; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_blackheart_the_inciter"; + pNewScript->GetAI = &GetAI_boss_blackheart_the_inciter; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp index 01fb701490..7fb4627659 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,42 +16,61 @@ /* ScriptData SDName: Boss_Grandmaster_Vorpil -SD%Complete: 75 -SDComment: Despawn all summoned on death not implemented. Void Traveler effects not implemented. +SD%Complete: 90 +SDComment: Timers may need adjustments SDCategory: Auchindoun, Shadow Labyrinth EndScriptData */ #include "precompiled.h" #include "shadow_labyrinth.h" -#define SAY_INTRO -1555028 -#define SAY_AGGRO1 -1555029 -#define SAY_AGGRO2 -1555030 -#define SAY_AGGRO3 -1555031 -#define SAY_HELP -1555032 -#define SAY_SLAY1 -1555033 -#define SAY_SLAY2 -1555034 -#define SAY_DEATH -1555035 - -#define SPELL_DRAW_SHADOWS 33563 -#define SPELL_VOID_PORTAL_A 33566 //spell only summon one unit, but we use it for the visual effect and summon the 4 other portals manual way(only one spell exist) -#define SPELL_VOID_PORTAL_VISUAL 33569 -#define SPELL_SHADOW_BOLT_VOLLEY 32963 -#define SPELL_SUMMON_VOIDWALKER_A 33582 -#define SPELL_SUMMON_VOIDWALKER_B 33583 -#define SPELL_SUMMON_VOIDWALKER_C 33584 -#define SPELL_SUMMON_VOIDWALKER_D 33585 -#define SPELL_SUMMON_VOIDWALKER_E 33586 -#define SPELL_RAIN_OF_FIRE 33617 -#define H_SPELL_RAIN_OF_FIRE 39363 -#define H_SPELL_BANISH 38791 - -#define ENTRY_VOID_PORTAL 19224 -#define ENTRY_VOID_TRAVELER 19226 - -#define LOCX -253.06f -#define LOCY -264.02f -#define LOCZ 17.08f +enum +{ + SAY_INTRO = -1555028, + SAY_AGGRO_1 = -1555029, + SAY_AGGRO_2 = -1555030, + SAY_AGGRO_3 = -1555031, + SAY_HELP = -1555032, + SAY_SLAY_1 = -1555033, + SAY_SLAY_2 = -1555034, + SAY_DEATH = -1555035, + + SPELL_DRAW_SHADOWS = 33563, // should trigger spell 33558 which is missing; so we need to hack the teleport + SPELL_VOID_PORTAL_A = 33566, // spell only summon one unit, but we use it for the visual effect and summon the 4 other portals manual way(only one spell exist) + SPELL_SHADOW_BOLT_VOLLEY = 32963, + SPELL_RAIN_OF_FIRE = 33617, + SPELL_RAIN_OF_FIRE_H = 39363, + SPELL_BANISH_H = 38791, + SPELL_SUMMON_VOIDWALKER_A = 33582, // the void travelers are summond at portal locations according to DB coords + SPELL_SUMMON_VOIDWALKER_B = 33583, + SPELL_SUMMON_VOIDWALKER_C = 33584, + SPELL_SUMMON_VOIDWALKER_D = 33585, + SPELL_SUMMON_VOIDWALKER_E = 33586, + + SPELL_VOID_PORTAL_VISUAL = 33569, + + SPELL_EMPOWERING_SHADOWS = 33783, + SPELL_EMPOWERING_SHADOWS_H = 39364, + SPELL_SHADOW_NOVA = 33846, + + NPC_VOID_PORTAL = 19224, + NPC_VOID_TRAVELER = 19226, + + MAX_PORTALS = 4 +}; + +// Summon locations for the void portals +static const LOCATION 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} +}; + +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 { @@ -59,80 +78,81 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Intro = false; + m_bHasDoneIntro = false; Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 ShadowBoltVolley_Timer; - uint32 DrawShadows_Timer; - uint32 Teleport_Timer; - uint32 VoidTraveler_Timer; - uint32 Banish_Timer; - bool Intro; - bool Teleport; + uint32 m_uiShadowBoltVolleyTimer; + uint32 m_uiDrawShadowsTimer; + uint32 m_uiRainOfFireTimer; + uint32 m_uiVoidTravelerTimer; + uint32 m_uiBanishTimer; + bool m_bHasDoneIntro; - void Reset() + void Reset() override { - ShadowBoltVolley_Timer = urand(7000, 14000); - DrawShadows_Timer = 40000; - Teleport_Timer = 1000; - VoidTraveler_Timer = 20000; - Banish_Timer = 25000; - Teleport = false; - - if (m_pInstance) - m_pInstance->SetData(TYPE_VORPIL, NOT_STARTED); + m_uiShadowBoltVolleyTimer = urand(13000, 19000); + m_uiDrawShadowsTimer = urand(38000, 44000); + m_uiRainOfFireTimer = 0; + m_uiVoidTravelerTimer = 5000; + m_uiBanishTimer = urand(12000, 16000); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { - //not sure about right radius - if (!Intro && m_creature->IsWithinDistInMap(who, 50)) + // 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); - Intro = true; + m_bHasDoneIntro = true; } - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit *who) + 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; - case 2: DoScriptText(SAY_AGGRO3, m_creature); break; + case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO_3, m_creature); break; } - DoCastSpellIfCan(m_creature, SPELL_VOID_PORTAL_A,true); - m_creature->SummonCreature(ENTRY_VOID_PORTAL, -262.40f, -229.57f, 17.08f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN,0); - m_creature->SummonCreature(ENTRY_VOID_PORTAL, -260.35f, -297.56f, 17.08f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN,0); - m_creature->SummonCreature(ENTRY_VOID_PORTAL, -292.05f, -270.37f, 12.68f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN,0); - m_creature->SummonCreature(ENTRY_VOID_PORTAL, -301.64f, -255.97f, 12.68f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN,0); + DoCastSpellIfCan(m_creature, SPELL_VOID_PORTAL_A); + + // summon the other 4 portals + for (uint8 i = 0; i < MAX_PORTALS; ++i) + m_creature->SummonCreature(NPC_VOID_PORTAL, aVorpilLocation[i].x, aVorpilLocation[i].y, aVorpilLocation[i].z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); if (m_pInstance) m_pInstance->SetData(TYPE_VORPIL, IN_PROGRESS); } - void KilledUnit(Unit *victim) + void JustReachedHome() override { - DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_VORPIL, FAIL); } - void JustSummoned(Creature *summoned) + void KilledUnit(Unit* /*pVictim*/) override { - if (summoned->GetEntry() == ENTRY_VOID_TRAVELER) - summoned->GetMotionMaster()->MoveFollow(m_creature, 1.0f, 0.0f); + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } - if (summoned->GetEntry() == ENTRY_VOID_PORTAL) - summoned->CastSpell(summoned,SPELL_VOID_PORTAL_VISUAL,true); + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_VOID_TRAVELER) + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0.0f, 0.0f); + + if (pSummoned->GetEntry() == NPC_VOID_PORTAL) + pSummoned->CastSpell(pSummoned, SPELL_VOID_PORTAL_VISUAL, true); } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -140,78 +160,93 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI m_pInstance->SetData(TYPE_VORPIL, DONE); } - void UpdateAI(const uint32 diff) + // Wrapper to teleport all players to the platform - Workaround for missing spell + void DoTeleportToPlatform() { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + m_creature->NearTeleportTo(aVorpilTeleportLoc[0], aVorpilTeleportLoc[1], aVorpilTeleportLoc[2], 0.0f); + + float fX, fY, fZ; - if (Teleport) + GuidVector vGuids; + m_creature->FillGuidsListFromThreatList(vGuids); + for (GuidVector::const_iterator itr = vGuids.begin(); itr != vGuids.end(); ++itr) { - if (Teleport_Timer <= diff) + Unit* pTarget = m_creature->GetMap()->GetUnit(*itr); + + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) { - m_creature->NearTeleportTo(LOCX, LOCY, LOCZ, 0.0f); + pTarget->GetRandomPoint(aVorpilTeleportLoc[0], aVorpilTeleportLoc[1], aVorpilTeleportLoc[2], 4.0f, fX, fY, fZ); + DoTeleportPlayer(pTarget, fX, fY, fZ, m_creature->GetAngle(fX, fY)); + } + } + } - float ranX = LOCX; - float ranY = LOCY; - float ranZ = LOCZ; + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - Unit* target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); + if (m_uiRainOfFireTimer) + { + if (m_uiRainOfFireTimer <= uiDiff) + { + SetCombatMovement(false, true); + DoTeleportToPlatform(); - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - target->GetRandomPoint(LOCX,LOCY,LOCZ,3.0f,ranX,ranY,ranZ); - DoTeleportPlayer(target,ranX,ranY,ranZ,m_creature->GetAngle(m_creature->GetPositionX(),m_creature->GetPositionY())); - } - } - Teleport = false; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_RAIN_OF_FIRE : SPELL_RAIN_OF_FIRE_H, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + m_uiRainOfFireTimer = 0; - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_RAIN_OF_FIRE : H_SPELL_RAIN_OF_FIRE); + SetCombatMovement(true); - Teleport_Timer = 1000; - }else Teleport_Timer -= diff; + return; // Nothing more todo after the players had been teleported + } + else + m_uiRainOfFireTimer -= uiDiff; } - if (ShadowBoltVolley_Timer < diff) + if (m_uiShadowBoltVolleyTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT_VOLLEY); - ShadowBoltVolley_Timer = urand(15000, 30000); - }else ShadowBoltVolley_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_BOLT_VOLLEY) == CAST_OK) + m_uiShadowBoltVolleyTimer = urand(10000, 26000); + } + else + m_uiShadowBoltVolleyTimer -= uiDiff; - if (DrawShadows_Timer < diff) + if (m_uiDrawShadowsTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_DRAW_SHADOWS); - DrawShadows_Timer = 30000; - Teleport = true; - }else DrawShadows_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_DRAW_SHADOWS) == CAST_OK) + { + m_uiDrawShadowsTimer = urand(36000, 44000); + m_uiRainOfFireTimer = 1000; + } + } + else + m_uiDrawShadowsTimer -= uiDiff; - if (VoidTraveler_Timer < diff) + if (m_uiVoidTravelerTimer < uiDiff) { - DoScriptText(SAY_HELP, m_creature); - - switch(urand(0, 4)) + if (DoCastSpellIfCan(m_creature, aTravelerSummonSpells[urand(0, 4)]) == CAST_OK) { - case 0: DoCastSpellIfCan(m_creature, SPELL_SUMMON_VOIDWALKER_A, CAST_TRIGGERED); break; - case 1: DoCastSpellIfCan(m_creature, SPELL_SUMMON_VOIDWALKER_B, CAST_TRIGGERED); break; - case 2: DoCastSpellIfCan(m_creature, SPELL_SUMMON_VOIDWALKER_C, CAST_TRIGGERED); break; - case 3: DoCastSpellIfCan(m_creature, SPELL_SUMMON_VOIDWALKER_D, CAST_TRIGGERED); break; - case 4: DoCastSpellIfCan(m_creature, SPELL_SUMMON_VOIDWALKER_E, CAST_TRIGGERED); break; + DoScriptText(SAY_HELP, m_creature); + m_uiVoidTravelerTimer = urand(10000, 15000); } - //faster rate when below (X) health? - VoidTraveler_Timer = 35000; - }else VoidTraveler_Timer -= diff; + } + else + m_uiVoidTravelerTimer -= uiDiff; if (!m_bIsRegularMode) { - if (Banish_Timer < diff) + if (m_uiBanishTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - DoCastSpellIfCan(target,H_SPELL_BANISH); - Banish_Timer = 35000; - }else Banish_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BANISH_H) == CAST_OK) + m_uiBanishTimer = urand(17000, 23000); + } + } + else + m_uiBanishTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -223,11 +258,73 @@ CreatureAI* GetAI_boss_grandmaster_vorpil(Creature* pCreature) return new boss_grandmaster_vorpilAI(pCreature); } +struct MANGOS_DLL_DECL npc_void_travelerAI : public ScriptedAI +{ + npc_void_travelerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + bool m_bHasExploded; + + uint32 m_uiDeathTimer; + + void Reset() override + { + m_uiDeathTimer = 0; + m_bHasExploded = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasExploded && pWho->GetEntry() == NPC_VORPIL && pWho->IsWithinDistInMap(m_creature, 3.0f)) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_NOVA) == CAST_OK) + { + m_bHasExploded = true; + m_uiDeathTimer = 1000; + } + } + } + + void AttackStart(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDeathTimer) + { + if (m_uiDeathTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_EMPOWERING_SHADOWS : SPELL_EMPOWERING_SHADOWS_H, CAST_TRIGGERED) == CAST_OK) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_uiDeathTimer = 0; + } + } + else + m_uiDeathTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_void_traveler(Creature* pCreature) +{ + return new npc_void_travelerAI(pCreature); +} + void AddSC_boss_grandmaster_vorpil() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_grandmaster_vorpil"; - newscript->GetAI = &GetAI_boss_grandmaster_vorpil; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_grandmaster_vorpil"; + pNewScript->GetAI = &GetAI_boss_grandmaster_vorpil; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_void_traveler"; + pNewScript->GetAI = &GetAI_npc_void_traveler; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp index 6973627659..25010096dd 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 MANGOS_DLL_DECL 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,148 +56,103 @@ 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; - uint64 m_uiPlayerTargetGUID; - - 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_uiPlayerTargetGUID = 0; - - //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 { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - Unit* target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - 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->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + // 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* temp = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SONIC_SHOCK, SELECT_FLAG_IN_MELEE_RANGE)) { - if (temp->GetTypeId() == TYPEID_PLAYER) - { - DoCastSpellIfCan(temp, SPELL_MAGNETIC_PULL); - m_uiPlayerTargetGUID = temp->GetGUID(); - CanShockWave = true; - } - MagneticPull_Timer = 2500; + if (DoCastSpellIfCan(pTarget, SPELL_SONIC_SHOCK) == CAST_OK) + m_uiSonicShockTimer = urand(3000, 10000); } } else - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerTargetGUID)) - pPlayer->CastSpell(pPlayer, SPELL_SHOCKWAVE, true); + m_uiSonicShockTimer -= uiDiff; - MagneticPull_Timer = urand(15000, 30000); - CanShockWave = false; - m_uiPlayerTargetGUID = 0; + if (m_uiThunderingStormTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_THUNDERING_STORM) == CAST_OK) + m_uiThunderingStormTimer = urand(5000, 6000); } - }else MagneticPull_Timer -= diff; + else + m_uiThunderingStormTimer -= uiDiff; + } - //no meele if preparing for sonic boom - if (!CanSonicBoom) - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_murmur(Creature* pCreature) { return new boss_murmurAI(pCreature); @@ -198,9 +160,10 @@ CreatureAI* GetAI_boss_murmur(Creature* pCreature) void AddSC_boss_murmur() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_murmur"; - newscript->GetAI = &GetAI_boss_murmur; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_murmur"; + pNewScript->GetAI = &GetAI_boss_murmur; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp b/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp index f229f688ff..f7bf5bbbf7 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -31,172 +31,154 @@ EndScriptData */ 4 - Murmur event */ -struct MANGOS_DLL_DECL instance_shadow_labyrinth : public ScriptedInstance +instance_shadow_labyrinth::instance_shadow_labyrinth(Map* pMap) : ScriptedInstance(pMap) { - instance_shadow_labyrinth(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiRefectoryDoorGUID; - uint64 m_uiScreamingHallDoorGUID; + Initialize(); +} - uint64 m_uiGrandmasterVorpil; - uint32 m_uiFelOverseerCount; +void instance_shadow_labyrinth::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_shadow_labyrinth::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiRefectoryDoorGUID = 0; - m_uiScreamingHallDoorGUID = 0; - - m_uiGrandmasterVorpil = 0; - m_uiFelOverseerCount = 0; + case GO_REFECTORY_DOOR: + if (m_auiEncounter[2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SCREAMING_HALL_DOOR: + if (m_auiEncounter[3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + + default: + return; } - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; - - return false; - } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) +void instance_shadow_labyrinth::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pGo->GetEntry()) - { - case GO_REFECTORY_DOOR: - m_uiRefectoryDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case GO_SCREAMING_HALL_DOOR: - m_uiScreamingHallDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[3] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - } + case NPC_VORPIL: + case NPC_HELLMAW: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_shadow_labyrinth::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(pCreature->GetEntry()) - { - case 18732: - m_uiGrandmasterVorpil = pCreature->GetGUID(); - break; - case 18796: - if (pCreature->isAlive()) - { - ++m_uiFelOverseerCount; - debug_log("SD2: Shadow Labyrinth: counting %u Fel Overseers.", m_uiFelOverseerCount); - } - break; - } + case TYPE_HELLMAW: + m_auiEncounter[0] = uiData; + break; + + case TYPE_INCITER: + if (uiData == DONE) + DoUseDoorOrButton(GO_REFECTORY_DOOR); + m_auiEncounter[1] = uiData; + break; + + case TYPE_VORPIL: + if (uiData == DONE) + DoUseDoorOrButton(GO_SCREAMING_HALL_DOOR); + m_auiEncounter[2] = uiData; + break; + + case TYPE_MURMUR: + m_auiEncounter[3] = uiData; + break; } - void SetData(uint32 uiType, uint32 uiData) + if (uiData == DONE) { - 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); - else - { - m_auiEncounter[1] = DONE; - debug_log("SD2: Shadow Labyrinth: TYPE_OVERSEER == DONE"); - } - } - break; - - case TYPE_INCITER: - if (uiData == DONE) - DoUseDoorOrButton(m_uiRefectoryDoorGUID); - m_auiEncounter[2] = uiData; - break; - - case TYPE_VORPIL: - if (uiData == DONE) - DoUseDoorOrButton(m_uiScreamingHallDoorGUID); - m_auiEncounter[3] = uiData; - break; - - case TYPE_MURMUR: - m_auiEncounter[4] = uiData; - break; - } + OUT_SAVE_INST_DATA; - if (uiData == DONE) - { - if (uiType == TYPE_OVERSEER && m_uiFelOverseerCount != 0) - return; + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " + << m_auiEncounter[2] << " " << m_auiEncounter[3]; - OUT_SAVE_INST_DATA; + m_strInstData = saveStream.str(); - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " - << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " << m_auiEncounter[4]; + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} - strInstData = saveStream.str(); +uint32 instance_shadow_labyrinth::GetData(uint32 uiType) const +{ + switch (uiType) + { + case TYPE_HELLMAW: return m_auiEncounter[0]; + case TYPE_INCITER: return m_auiEncounter[1]; + case TYPE_VORPIL: return m_auiEncounter[2]; + case TYPE_MURMUR: return m_auiEncounter[3]; - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + default: + return 0; } +} - uint32 GetData(uint32 uiType) +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) { - switch(uiType) + m_sRitualistsAliveGUIDSet.erase(pCreature->GetObjectGuid()); + + if (m_sRitualistsAliveGUIDSet.empty()) { - case TYPE_HELLMAW: - return m_auiEncounter[0]; - case TYPE_OVERSEER: - return m_auiEncounter[1]; + if (Creature* pHellmaw = GetSingleCreatureFromStorage(NPC_HELLMAW)) + { + // yell intro and remove banish aura + DoScriptText(SAY_HELLMAW_INTRO, pHellmaw); + pHellmaw->GetMotionMaster()->MoveWaypoint(); + pHellmaw->RemoveAurasDueToSpell(SPELL_BANISH); + } } - return false; } +} - const char* Save() +void instance_shadow_labyrinth::Load(const char* chrIn) +{ + if (!chrIn) { - return strInstData.c_str(); + OUT_LOAD_INST_DATA_FAIL; + return; } - void Load(const char* in) - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); + OUT_LOAD_INST_DATA(chrIn); - std::istringstream loadStream(in); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; + 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; + 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_shadow_labyrinth(Map* pMap) { @@ -205,9 +187,10 @@ InstanceData* GetInstanceData_instance_shadow_labyrinth(Map* pMap) void AddSC_instance_shadow_labyrinth() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_shadow_labyrinth"; - newscript->GetInstanceData = &GetInstanceData_instance_shadow_labyrinth; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_shadow_labyrinth"; + pNewScript->GetInstanceData = &GetInstanceData_instance_shadow_labyrinth; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h b/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h index 30f5a3b407..2331cc9fb1 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,16 +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, - GO_REFECTORY_DOOR = 183296, //door opened when blackheart the inciter dies - GO_SCREAMING_HALL_DOOR = 183295 //door opened when grandmaster vorpil dies + DATA_CABAL_RITUALIST = 1, // DO NOT CHANGE! Used by Acid. - used to check the Cabal Ritualists alive + + NPC_HELLMAW = 18731, + NPC_VORPIL = 18732, + 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 + + SAY_HELLMAW_INTRO = -1555000, + + SPELL_BANISH = 30231, // spell is handled in creature_template_addon; +}; + +class MANGOS_DLL_DECL instance_shadow_labyrinth : public ScriptedInstance +{ + public: + instance_shadow_labyrinth(Map* pMap); + + 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 SetData64(uint32 uiType, uint64 uiGuid) override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + bool IsHellmawUnbanished() { return m_sRitualistsAliveGUIDSet.empty(); } + + private: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + GuidSet m_sRitualistsAliveGUIDSet; }; #endif diff --git a/scripts/outland/black_temple/black_temple.cpp b/scripts/outland/black_temple/black_temple.cpp index 96fdb6d1ff..3e61b08207 100644 --- a/scripts/outland/black_temple/black_temple.cpp +++ b/scripts/outland/black_temple/black_temple.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -42,11 +42,11 @@ bool GossipHello_npc_spirit_of_olum(Player* pPlayer, Creature* pCreature) if (pInstance && (pInstance->GetData(TYPE_SUPREMUS) >= DONE) && (pInstance->GetData(TYPE_NAJENTUS) >= DONE)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_OLUM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); 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(); @@ -58,11 +58,11 @@ bool GossipSelect_npc_spirit_of_olum(Player* pPlayer, Creature* pCreature, uint3 void AddSC_black_temple() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "npc_spirit_of_olum"; - newscript->pGossipHello = &GossipHello_npc_spirit_of_olum; - newscript->pGossipSelect = &GossipSelect_npc_spirit_of_olum; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_spirit_of_olum"; + pNewScript->pGossipHello = &GossipHello_npc_spirit_of_olum; + pNewScript->pGossipSelect = &GossipSelect_npc_spirit_of_olum; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/black_temple.h b/scripts/outland/black_temple/black_temple.h index 439c9eb9f8..6dc4d18dc6 100644 --- a/scripts/outland/black_temple/black_temple.h +++ b/scripts/outland/black_temple/black_temple.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,39 +7,87 @@ enum { - MAX_ENCOUNTER = 9, - - TYPE_NAJENTUS = 1, - TYPE_SUPREMUS = 2, - TYPE_SHADE = 3, - TYPE_GOREFIEND = 4, - TYPE_BLOODBOIL = 5, - TYPE_RELIQUIARY = 6, - TYPE_SHAHRAZ = 7, - TYPE_COUNCIL = 8, - TYPE_ILLIDAN = 9, - - DATA_HIGHWARLORDNAJENTUS = 10, - DATA_SUPREMUS = 11, - DATA_SHADEOFAKAMA = 12, - DATA_AKAMA_SHADE = 13, - DATA_ILLIDARICOUNCIL = 14, - DATA_BLOOD_ELF_COUNCIL_VOICE = 15, - DATA_LADYMALANDE = 16, - DATA_HIGHNETHERMANCERZEREVOR = 17, - DATA_GATHIOSTHESHATTERER = 18, - DATA_VERASDARKSHADOW = 19, - DATA_AKAMA = 20, - DATA_ILLIDANSTORMRAGE = 21, - - DATA_GAMEOBJECT_NAJENTUS_GATE = 22, - DATA_GAMEOBJECT_SUPREMUS_DOORS = 23, - DATA_GO_PRE_SHAHRAZ_DOOR = 24, - DATA_GO_POST_SHAHRAZ_DOOR = 25, - DATA_GO_COUNCIL_DOOR = 26, - DATA_GAMEOBJECT_ILLIDAN_GATE = 27, - DATA_GAMEOBJECT_ILLIDAN_DOOR_R = 28, - DATA_GAMEOBJECT_ILLIDAN_DOOR_L = 29 + MAX_ENCOUNTER = 9, + + TYPE_NAJENTUS = 0, + TYPE_SUPREMUS = 1, + TYPE_SHADE = 2, + TYPE_GOREFIEND = 3, + TYPE_BLOODBOIL = 4, + TYPE_RELIQUIARY = 5, + TYPE_SHAHRAZ = 6, + TYPE_COUNCIL = 7, + TYPE_ILLIDAN = 8, + + // NPC_WARLORD_NAJENTUS = 22887, + // 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, + NPC_ZEREVOR = 22950, + 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, + GO_COUNCIL_DOOR = 186152, + GO_ILLIDAN_GATE = 185905, + GO_ILLIDAN_DOOR_R = 186261, + GO_ILLIDAN_DOOR_L = 186262, +}; + +class MANGOS_DLL_DECL instance_black_temple : public ScriptedInstance +{ + public: + instance_black_temple(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 GetChannelersGuidList(GuidList& lList) { lList = m_lChannelersGuidList; } + void GetGeneratorGuidVector(GuidVector& vVector) { vVector = m_vCreatureGeneratorGuidVector; } + void GetGlaiveTargetGuidVector(GuidVector& vVector) { vVector = m_vGlaiveTargetGuidVector; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + private: + void DoOpenPreMotherDoor(); + void DoSpawnAkamaIfCan(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + 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 9ded2ef11e..3e0a671f11 100644 --- a/scripts/outland/black_temple/boss_bloodboil.cpp +++ b/scripts/outland/black_temple/boss_bloodboil.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,41 +16,55 @@ /* 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 +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 MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI { @@ -62,67 +76,55 @@ struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint64 TargetGUID; - - float TargetThreat; + 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; - uint32 BloodboilTimer; - uint32 BloodboilCount; - uint32 AcidGeyserTimer; - uint32 AcidicWoundTimer; - uint32 ArcingSmashTimer; - uint32 EnrageTimer; - uint32 FelAcidTimer; - uint32 EjectTimer; - uint32 BewilderingStrikeTimer; - uint32 PhaseChangeTimer; - uint32 m_uiEnrageTimer; + bool m_bIsPhase1; - bool Phase1; - - void Reset() + void Reset() override { - TargetGUID = 0; - - 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 { - m_creature->SetInCombatWithZone(); - DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) 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); @@ -130,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) - { - 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(uint64 guid) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(guid)) + if (m_uiFelAcidTimer < uiDiff) { - 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; } - } + else + m_uiFelAcidTimer -= uiDiff; - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - 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); - TargetGUID = target->GetGUID(); - 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 (TargetGUID) - RevertThreatOnTarget(TargetGUID); - - TargetGUID = 0; - 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; - - //Enrage - if (m_uiEnrageTimer < diff) + } + else + m_uiPhaseChangeTimer -= uiDiff; + + 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(); } @@ -339,9 +295,10 @@ CreatureAI* GetAI_boss_gurtogg_bloodboil(Creature* pCreature) void AddSC_boss_gurtogg_bloodboil() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_gurtogg_bloodboil"; - newscript->GetAI = &GetAI_boss_gurtogg_bloodboil; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_gurtogg_bloodboil"; + pNewScript->GetAI = &GetAI_boss_gurtogg_bloodboil; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/boss_illidan.cpp b/scripts/outland/black_temple/boss_illidan.cpp index 1d1f396b80..f01bd1fb69 100644 --- a/scripts/outland/black_temple/boss_illidan.cpp +++ b/scripts/outland/black_temple/boss_illidan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,2338 +17,1630 @@ /* 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" +#include "escort_ai.h" -/**** Creature Summon and Recognition IDs ****/ -enum CreatureEntry +enum { - 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 ***********************/ + // 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, + + + /************** 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. 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, // 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, // 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_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, }; -/************* Quotes and Sounds ***********************/ -// Gossip for when a player clicks Akama -#define GOSSIP_ITEM "We are ready to face Illidan" - -#define SAY_CONVO_1 -1564097 -#define SAY_CONVO_2 -1564098 -#define SAY_CONVO_3 -1564099 -#define SAY_CONVO_4 -1564100 -#define SAY_CONVO_5 -1564101 -#define SAY_CONVO_6 -1564102 -#define SAY_CONVO_7 -1564103 -#define SAY_CONVO_8 -1564104 -#define SAY_CONVO_9 -1564105 -#define SAY_CONVO_10 -1564106 -#define SAY_CONVO_11 -1564107 -#define SAY_CONVO_12 -1564108 -#define SAY_CONVO_13 -1564109 -#define SAY_CONVO_14 -1564110 -#define SAY_CONVO_15 -1564111 - -#define SAY_TAUNT_1 -1564112 -#define SAY_TAUNT_2 -1564113 -#define SAY_TAUNT_3 -1564114 -#define SAY_TAUNT_4 -1564115 - -#define SAY_MAIEV_TAUNT_1 -1564116 -#define SAY_MAIEV_TAUNT_2 -1564117 -#define SAY_MAIEV_TAUNT_3 -1564118 -#define 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 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 }; -static Yells Conversation[]= +static const DialogueEntry aIntroDialogue[] = { - {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} + {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}, }; -static Yells RandomTaunts[]= +static const DialogueEntry aEventDialogue[] = { - {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} + // 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 Yells MaievTaunts[]= +static const DialogueEntry aEpilogueDialogue[] = { - {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} + {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}, }; -// Yells for/by Akama -#define SAY_AKAMA_BEWARE -1564120 -#define SAY_AKAMA_MINION -1564121 -#define SAY_AKAMA_LEAVE -1564122 - -// Self explanatory -#define SAY_KILL1 -1564123 -#define SAY_KILL2 -1564124 - -// I think I'll fly now and let my subordinates take you on -#define SAY_TAKEOFF -1564125 -#define SAY_SUMMONFLAMES -1564126 - -// When casting Eye Blast. Demon Fire will be appear on places that he casts this -#define SAY_EYE_BLAST -1564127 - -// kk, I go big, dark and demon on you. -#define SAY_MORPH -1564128 - -// I KILL! -#define SAY_ENRAGE -1564129 - -/************** Spells *************/ -// Normal Form -#define SPELL_SHEAR 41032 // Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast -#define SPELL_FLAME_CRASH 40832 // Summons an invis/unselect passive mob that has an aura of flame in a circle around him. -#define SPELL_DRAW_SOUL 40904 // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect) -#define 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) -#define 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 :( -#define SPELL_AGONIZING_FLAMES 40932 // 4k fire damage initial to target and anyone w/i 5 yards. PHASE 3 ONLY -#define SPELL_ENRAGE 40683 // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY -// Flying (Phase 2) -#define SPELL_THROW_GLAIVE 39635 // Throws a glaive on the ground -#define SPELL_THROW_GLAIVE2 39849 // Animation for the above spell -#define SPELL_GLAIVE_RETURNS 39873 // Glaive flies back to Illidan -#define SPELL_FIREBALL 40598 // 2.5k-3.5k damage in 10 yard radius. 2 second cast time. -#define SPELL_DARK_BARRAGE 40585 // 10 second channeled spell, 3k shadow damage per second. -// Demon Form -#define SPELL_DEMON_TRANSFORM_1 40511 // First phase of animations for transforming into Dark Illidan (fall to ground) -#define SPELL_DEMON_TRANSFORM_2 40398 // Second phase of animations (kneel) -#define SPELL_DEMON_TRANSFORM_3 40510 // Final phase of animations (stand up and roar) -#define SPELL_DEMON_FORM 40506 // Transforms into Demon Illidan. Has an Aura of Dread on him. -#define SPELL_SHADOW_BLAST 41078 // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target. -#define SPELL_FLAME_BURST 41126 // Hurls fire at entire raid for ~3.5k damage every 10 seconds. Resistable. (Does not work: Script effect) -#define SPELL_FLAME_BURST_EFFECT 41131 // The actual damage. Handled by core (41126 triggers 41131) -// Other Illidan spells -#define SPELL_KNEEL 39656 // Before beginning encounter, this is how he appears (talking to Wilson). -#define SPELL_SHADOW_PRISON 40647 // Illidan casts this spell to immobilize entire raid when he summons Maiev. -#define SPELL_DEATH 41220 // This spell doesn't do anything except stun Illidan and set him on his knees. -#define SPELL_BERSERK 45078 // Damage increased by 500%, attack speed by 150% - -// Non-Illidan spells -#define SPELL_AKAMA_DOOR_CHANNEL 41268 // Akama's channel spell on the door before the Temple Summit -#define SPELL_DEATHSWORN_DOOR_CHANNEL 41269 // Olum and Udalo's channel spell on the door before the Temple Summit -#define SPELL_AKAMA_DOOR_FAIL 41271 // Not sure where this is really used... -#define SPELL_HEALING_POTION 40535 // Akama uses this to heal himself to full. -#define SPELL_AZZINOTH_CHANNEL 39857 // Glaives cast it on Flames. Not sure if this is the right spell. -#define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons. -#define SPELL_CONSUME_SOUL 41080 // Once the Shadow Demons reach their target, they use this to kill them -#define SPELL_PARALYZE 41083 // Shadow Demons cast this on their target -#define SPELL_PURPLE_BEAM 39123 // Purple Beam connecting Shadow Demon to their target -#define SPELL_CAGE_TRAP_DUMMY 40761 // Put this in DB for cage trap GO. -#define SPELL_EYE_BLAST_TRIGGER 40017 // This summons Demon Form every few seconds and deals ~20k damage in its radius -#define SPELL_EYE_BLAST 39908 // This does the blue flamey animation. -#define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons -#define SPELL_BLAZE_EFFECT 40610 // Green flame on the ground, triggers damage (5k) every few seconds -#define SPELL_BLAZE_SUMMON 40637 // Summons the Blaze creature -#define SPELL_DEMON_FIRE 40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it. -#define SPELL_CAGED 40695 // Caged Trap triggers will cast this on Illidan if he is within 3 yards -#define SPELL_CAGE_TRAP_SUMMON 40694 // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working) -#define SPELL_CAGE_TRAP_BEAM 40713 // 8 Triggers on the ground in an octagon cast spells like this on Illidan 'caging him' -#define SPELL_FLAME_BLAST 40631 // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage. -#define 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. -#define SPELL_TELEPORT_VISUAL 41232 // Teleport visual for Maiev -#define SPELL_SHADOWFIEND_PASSIVE 41913 // Passive aura for shadowfiends - -// Other defines -#define CENTER_X 676.740f -#define CENTER_Y 305.297f -#define CENTER_Z 353.192f - -#define EQUIP_ID_MAIN_HAND 32837 -#define EQUIP_ID_OFF_HAND 32838 - /*** Phase Names ***/ enum Phase { - PHASE_NORMAL = 1, - PHASE_FLIGHT = 2, - PHASE_NORMAL_2 = 3, - PHASE_DEMON = 4, - PHASE_NORMAL_MAIEV = 5, - PHASE_DEMON_SEQUENCE = 6, -}; - -struct Locations -{ - float x, y, z; - uint32 id; -}; - -static Locations GlaivePosition[]= -{ - {695.105f, 305.303f, 354.256f}, - {659.338f, 305.303f, 354.256f}, - {700.105f, 305.303f, 354.256f}, - {664.338f, 305.303f, 354.256f} -}; - -static Locations EyeBlast[]= -{ - {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 Locations AkamaWP[]= +static const LOCATION aCenterLoc[]= { - {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 initial gates. This is where he will fight the minions! -}; -// 755.762, 304.0747, 312.1769 -- This is where Akama should be spawned -static Locations SpiritSpawns[]= -{ - {755.5426f, 309.9156f, 312.2129f, SPIRIT_OF_UDALO}, - {755.5426f, 298.7923f, 312.0834f, SPIRIT_OF_OLUM} + {705.012f, 305.721f, 354.723f}, // front location + {676.740f, 305.297f, 353.192f}, // center location }; -struct WayPoints +static const LOCATION aIllidariElitesPos[MAX_ILLIDARI_ELITES] = { - WayPoints(uint32 _id, float _x, float _y, float _z) - { - id = _id; - x = _x; - y = _y; - z = _z; - } - uint32 id; - float x, y, z; + {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}, }; -struct Animation // For the demon transformation +static const LOCATION aEyeBlastPos[] = { - uint32 aura, unaura, timer, size, displayid, phase; - bool equip; + // 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} }; -static Animation DemonTransformation[]= -{ - {SPELL_DEMON_TRANSFORM_1, 0, 1300, 0, 0, 6, true}, - {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, true}, - {SPELL_DEMON_FORM, 0, 3000, 1073741824, 21322, 6, false}, - {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, 6, false}, - {0, 0, 0, 0, 0, 4, false}, - {SPELL_DEMON_TRANSFORM_1, 0, 1500, 0, 0, 6, false}, - {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, false}, - {0, SPELL_DEMON_FORM, 3000, 1069547520, 21135, 6, false}, - {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, 6, true}, - {0, 0, 0, 0, 0, 8, true} -}; +/*###### +## boss_illidan_stormrage +######*/ -/**** 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 +struct MANGOS_DLL_DECL 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; - - uint64 IllidanGUID; - - bool IsTrigger; - - uint32 CheckTimer; - uint32 DemonFireTimer; - uint32 DespawnTimer; - - void Reset() - { - IllidanGUID = 0; - - IsTrigger = false; - - CheckTimer = 2000; - DemonFireTimer = 0; - DespawnTimer = 45000; - } - - void AttackStart(Unit* who) { } - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 diff) - { - if (IsTrigger) - return; + instance_black_temple* m_pInstance; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Phase m_uiPhase; + uint32 m_uiBerserkTimer; - if (CheckTimer < diff) - { - if (!IllidanGUID && m_pInstance) - { - if (Creature* pIllidan = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_ILLIDANSTORMRAGE))) - { - IllidanGUID = m_pInstance->GetData64(DATA_ILLIDANSTORMRAGE); + bool m_bHasSummonedElites; + float m_fTargetMoveX, m_fTargetMoveY, m_fTargetMoveZ; - if (!pIllidan->HasSplineFlag(SPLINEFLAG_NO_SPLINE)) - m_creature->SetDeathState(JUST_DIED); - } - } - CheckTimer = 2000; - }else CheckTimer -= diff; + uint32 m_uiShearTimer; + uint32 m_uiDrawSoulTimer; + uint32 m_uiFlameCrashTimer; + uint32 m_uiShadowFiendTimer; - if (DemonFireTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_DEMON_FIRE); - DemonFireTimer = 30000; - }else DemonFireTimer -= diff; + 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; - if (DespawnTimer < diff) - m_creature->SetDeathState(JUST_DIED); - else DespawnTimer -= diff; + uint32 m_uiAgonizingFlamesTimer; + uint32 m_uiTransformTimer; - DoMeleeAttackIfReady(); - } -}; + uint32 m_uiShadowBlastTimer; + uint32 m_uiFlameBurstTimer; + uint32 m_uiShadowDemonTimer; + Phase m_uiPrevPhase; // store the previous phase in transition -/******* 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(); - } + uint32 m_uiEnrageTimer; + uint32 m_uiTrapTimer; - /* Instance Data */ - ScriptedInstance* m_pInstance; + GuidList m_lBladesGuidList; - /* Timers */ - uint32 ChannelTimer; - uint32 TalkTimer; - uint32 WalkTimer; - uint32 SummonMinionTimer; - - /* GUIDs */ - uint64 IllidanGUID; - uint64 PlayerGUID; - uint64 SpiritGUID[2]; - uint64 ChannelGUID; - - bool IsTalking; - bool StartChanneling; - bool DoorOpen; - bool FightMinions; - bool IsReturningToIllidan; - bool IsWalking; - uint32 TalkCount; - uint32 ChannelCount; - - std::list WayPointList; - std::list::iterator WayPoint; - - void BeginEvent(uint64 PlayerGUID); - - void Reset() + void Reset() override { - if (m_pInstance) - { - m_pInstance->SetData(TYPE_ILLIDAN, NOT_STARTED); - GameObject* pGate = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_GAMEOBJECT_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(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) - { - if (GameObject* pDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(i))) - pDoor->SetGoState(GO_STATE_ACTIVE); - } - } + m_uiShearTimer = urand(10000, 15000); + m_uiFlameCrashTimer = 30000; + m_uiShadowFiendTimer = 25000; + m_uiDrawSoulTimer = 35000; - IllidanGUID = 0; - PlayerGUID = 0; - ChannelGUID = 0; - for(uint8 i = 0; i < 2; ++i) SpiritGUID[i] = 0; + m_uiFlameAzzinothKilled = 0; + m_uiSummonBladesTimer = 0; + m_uiCenterMoveTimer = 0; + m_uiFireballTimer = 5000; + m_uiDarkBarrageTimer = 45000; + m_uiEyeBlastTimer = 15000; + m_uiLandTimer = 0; + m_uiLandStage = 0; - ChannelTimer = 0; - ChannelCount = 0; - SummonMinionTimer = 2000; + m_uiAgonizingFlamesTimer = 35000; + m_uiTransformTimer = 0; - WalkTimer = 0; - IsWalking = false; + m_uiShadowBlastTimer = urand(1000, 2000); + m_uiFlameBurstTimer = 10000; + m_uiShadowDemonTimer = 30000; - TalkTimer = 0; - TalkCount = 0; + m_uiEnrageTimer = 40000; + m_uiTrapTimer = urand(30000, 40000); - KillAllElites(); + m_lBladesGuidList.clear(); - IsReturningToIllidan = false; - FightMinions = false; - IsTalking = false; - StartChanneling = false; - DoorOpen = 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 { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - 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(); - FightMinions = false; - IsReturningToIllidan = true; - WayPoint = WayPointList.begin(); - m_creature->SetSpeedRate(MOVE_RUN, 2.0f); - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - IsWalking = 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 *done_by, uint32 &damage) + void KilledUnit(Unit* pVictim) override { - if (damage > m_creature->GetHealth() && (done_by->GetGUID() != m_creature->GetGUID())) - { - damage = 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 { - if (!m_pInstance) + if (uiDamage < m_creature->GetHealth()) return; - debug_log("SD2: Akama - Door event initiated by player %s", pPlayer->GetName()); - PlayerGUID = pPlayer->GetGUID(); - - if (GameObject* pGate = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_GAMEOBJECT_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) - { - ChannelGUID = Channel->GetGUID(); + 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(SpiritSpawns[i].id, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); - if (Spirit) - { - Spirit->SetVisibility(VISIBILITY_OFF); - SpiritGUID[i] = Spirit->GetGUID(); - } - } + DoCastSpellIfCan(m_creature, SPELL_DEATH, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TELEPORT_MAIEV, CAST_TRIGGERED); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); - StartChanneling = 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 || !IsWalking) - return; - - if (WayPoint->id != id) - return; - - switch(id) + switch (iEntry) { - case 6: - if (!IsReturningToIllidan) + case NPC_AKAMA: + if (m_pInstance) { - // open the doors that close the summit - for(uint32 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) + 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) + { + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA)) { - if (GameObject* pDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(i))) - pDoor->SetGoState(GO_STATE_ACTIVE); + pAkama->AI()->AttackStart(m_creature); + AttackStart(pAkama); } } break; - case 7: - if (IsReturningToIllidan) + case SAY_AKAMA_LEAVE: + DoResetThreat(); + if (m_pInstance) { - IsWalking = false; - if (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(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->SetUInt64Value(UNIT_FIELD_TARGET, IllidanGUID); - } + pAkama->AI()->EnterEvadeMode(); + m_creature->getThreatManager().modifyThreatPercent(pAkama, -101); } } break; - case 8: - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (!IsReturningToIllidan) + case SPELL_SUMMMON_MAIEV: + DoCastSpellIfCan(m_creature, SPELL_SUMMMON_MAIEV); + break; + case EMOTE_ONESHOT_EXCLAMATION: + if (m_pInstance) + { + if (Creature* pMaiev = m_pInstance->GetSingleCreatureFromStorage(NPC_MAIEV_SHADOWSONG)) + pMaiev->HandleEmote(EMOTE_ONESHOT_EXCLAMATION); + } + break; + case EMOTE_ONESHOT_YES: + if (m_pInstance) { - IsWalking = false; - BeginEvent(PlayerGUID); + if (Creature* pMaiev = m_pInstance->GetSingleCreatureFromStorage(NPC_MAIEV_SHADOWSONG)) + pMaiev->HandleEmote(EMOTE_ONESHOT_YES); } break; - case 12: - IsWalking = false; - FightMinions = true; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + 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; - WalkTimer = 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 (!IllidanGUID) - return; + // Land Illidan if both Flames are killed + ++m_uiFlameAzzinothKilled; + + if (m_uiFlameAzzinothKilled == MAX_FLAME_AZZINOTH) + { + m_uiLandTimer = 5000; + m_uiPhase = PHASE_TRANSITION; + m_creature->InterruptNonMeleeSpells(false); + } + } - // Create a pointer to Illidan - Creature* Illidan = m_creature->GetMap()->GetCreature(IllidanGUID); + // Wrapper to handle the Eye Blast cast + bool DoCastEyeBlastIfCan() + { + if (m_creature->IsNonMeleeSpellCasted(false)) + return false; - // No use to continue if Illidan does not exist - if (!Illidan) - return; + DoScriptText(SAY_EYE_BLAST, m_creature); - ThreatList const& tList = m_creature->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->GetGUID()) - { - (*itr)->removeReference(); // Delete ourself from his threatlist. - return; // 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(); + m_fTargetMoveX = aEyeBlastPos[uiTargetLoc].x; + m_fTargetMoveY = aEyeBlastPos[uiTargetLoc].y; + m_fTargetMoveZ = aEyeBlastPos[uiTargetLoc].z; + m_creature->SummonCreature(NPC_ILLIDAN_TARGET, aEyeBlastPos[uiSpawnLoc].x, aEyeBlastPos[uiSpawnLoc].y, aEyeBlastPos[uiSpawnLoc].z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); + + return true; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (IllidanGUID) - { - if (Creature* Illidan = m_creature->GetMap()->GetCreature(IllidanGUID)) - { - if (Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode()) - EnterEvadeMode(); + DialogueUpdate(uiDiff); - if (Illidan->GetHealthPercent() < 85.0f && m_creature->isInCombat() && !FightMinions) - { - if (TalkTimer < diff) - { - switch(TalkCount) - { - case 0: - DoScriptText(SAY_AKAMA_MINION, Illidan); - TalkTimer = 8000; - TalkCount = 1; - break; - case 1: - DoScriptText(SAY_AKAMA_LEAVE, m_creature); - TalkTimer = 3000; - TalkCount = 2; - break; - case 2: - IsTalking = true; - TalkTimer = 2000; - m_creature->RemoveAllAuras(); - m_creature->CombatStop(true); - m_creature->AttackStop(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - TalkCount = 3; - break; - case 3: - DeleteFromThreatList(); - IsWalking = true; - WayPoint = WayPointList.begin(); - std::advance(WayPoint, 9); - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - break; - } - }else TalkTimer -= diff; - } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - if (Illidan->GetHealthPercent() < 4.0f && !IsReturningToIllidan) - ReturnToIllidan(); - } - }else + // Make Akama evade combat at 85% + if (!m_bHasSummonedElites && m_creature->GetHealthPercent() < 85.0f) { - if (m_pInstance) - IllidanGUID = m_pInstance->GetData64(DATA_ILLIDANSTORMRAGE); + StartNextDialogueText(SAY_ILLIDAN_MINION); + m_bHasSummonedElites = true; } - if (IsWalking && WalkTimer) + // Phase 1 to 2 transition + if (m_uiPhase == PHASE_AKAMA && m_creature->GetHealthPercent() < 65.0f) { - if (WalkTimer <= diff) - { - if (WayPoint == WayPointList.end()) - return; + DoScriptText(SAY_TAKEOFF, m_creature); + m_uiSummonBladesTimer = 10000; + m_uiCenterMoveTimer = 2000; + m_uiPhase = PHASE_BLADES; - m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); - WalkTimer = 0; - }else WalkTimer -= diff; + 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 (StartChanneling) + // Summon Maiev at 30% hp + if (m_uiPhase == PHASE_DUAL_NORMAL && m_creature->GetHealthPercent() <= 30.0f) { - if (ChannelTimer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_PRISON, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - switch(ChannelCount) - { - case 3: - if (!DoorOpen) - { - m_creature->InterruptNonMeleeSpells(true); - - for(uint8 i = 0; i < 2; ++i) - { - if (SpiritGUID[i]) - { - Creature* Spirit = m_creature->GetMap()->GetCreature(SpiritGUID[i]); - if (Spirit) - Spirit->InterruptNonMeleeSpells(true); - } - } + StartNextDialogueText(SAY_ILLIDAN_SPEECH_6); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - if (GameObject* pGate = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE))) - pGate->SetGoState(GO_STATE_ACTIVE); - - ++ChannelCount; - ChannelTimer = 5000; - } - break; - case 4: - m_creature->HandleEmote(EMOTE_ONESHOT_SALUTE); - ChannelTimer = 2000; - ++ChannelCount; - break; - case 5: - DoScriptText(SAY_AKAMA_BEWARE, m_creature); - if (ChannelGUID) - { - Creature* ChannelTarget = m_creature->GetMap()->GetCreature(ChannelGUID); - if (ChannelTarget) - ChannelTarget->SetDeathState(JUST_DIED); - ChannelGUID = 0; - } - for(uint8 i = 0; i < 2; ++i) - { - if (SpiritGUID[i]) - { - Creature* Spirit = m_creature->GetMap()->GetCreature(SpiritGUID[i]); - if (Spirit) - Spirit->SetDeathState(JUST_DIED); - } - } - ChannelTimer = 6000; - ++ChannelCount; - break; - case 6: - StartChanneling = false; - if (WayPointList.empty()) - { - error_log("SD2: Akama has no waypoints to start with!"); - return; - } + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); - WayPoint = WayPointList.begin(); - m_creature->AddSplineFlag(SPLINEFLAG_WALKMODE); - m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y, WayPoint->z); - IsWalking = true; - break; - default: - if (ChannelGUID) - { - Creature* Channel = m_creature->GetMap()->GetCreature(ChannelGUID); - if (Channel) - { - m_creature->InterruptNonMeleeSpells(true); + m_uiPhase = PHASE_TRANSITION; + m_uiTransformTimer = 0; + } + return; + } - for(uint8 i = 0; i < 2; ++i) - { - if (SpiritGUID[i]) - { - Creature* Spirit = m_creature->GetMap()->GetCreature(SpiritGUID[i]); - if (Spirit) - { - Spirit->InterruptNonMeleeSpells(true); - if (ChannelCount%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 (ChannelCount < 3) - ++ChannelCount; - ChannelTimer = 10000; - } - } - break; + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; } - }else ChannelTimer -= diff; + } + else + m_uiBerserkTimer -= uiDiff; } - if (FightMinions) + switch (m_uiPhase) { - if (SummonMinionTimer < diff) - { - if (IllidanGUID) + case PHASE_MAIEV: + + // Phase 5 spell only + if (m_uiEnrageTimer < uiDiff) { - Creature* Illidan = m_creature->GetMap()->GetCreature(IllidanGUID); - if (!Illidan || Illidan->IsInEvadeMode()) + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) { - Reset(); - EnterEvadeMode(); - return; + DoScriptText(SAY_FRENZY, m_creature); + m_uiEnrageTimer = 40000; } } + else + m_uiEnrageTimer -= uiDiff; - 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) + if (m_uiTrapTimer < uiDiff) { - Elite->AI()->AttackStart(m_creature); - Elite->AddThreat(m_creature, 1000000.0f); - AttackStart(Elite); + if (DoCastSpellIfCan(m_creature, SPELL_CAGE_TRAP) == CAST_OK) + m_uiTrapTimer = urand(40000, 50000); } - SummonMinionTimer = urand(10000, 16000); - }else SummonMinionTimer -= diff; - } - - // If we don't have a target, or is talking, or has run away, return - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + 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(); + // Phase 3 and 5 spells + if (m_uiAgonizingFlamesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_AGONIZING_FLAMES) == CAST_OK) + m_uiAgonizingFlamesTimer = 60000; + } + else + m_uiAgonizingFlamesTimer -= uiDiff; - for(uint8 i = 0; i < 2; ++i) - { - FlameGUID[i] = 0; - GlaiveGUID[i] = 0; - } + if (m_uiTransformTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_TRANSFORM_1) == CAST_OK) + { + DoScriptText(SAY_MORPH, m_creature); - AkamaGUID = 0; - MaievGUID = 0; + m_uiPrevPhase = m_uiPhase; + m_uiPhase = PHASE_TRANSITION; + m_uiTransformTimer = 12500; + m_uiFlameBurstTimer = 10000; + m_uiShadowDemonTimer = 30000; - Reset(); - } + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + } + } + else + m_uiTransformTimer -= uiDiff; - /** Instance Data **/ - ScriptedInstance* m_pInstance; + // no break; + case PHASE_AKAMA: - /** Generic **/ - bool IsTalking; - bool HasSummoned; - bool RefaceVictim; - bool InformAkama; - uint32 Phase; - uint32 GlobalTimer; - uint32 TalkCount; - uint32 DemonFormSequence; - - /** GUIDs **/ - uint64 FlameGUID[2]; - uint64 GlaiveGUID[2]; - uint64 AkamaGUID; - uint64 MaievGUID; - - /** Timers **/ - uint32 ShearTimer; - uint32 DrawSoulTimer; - uint32 FlameCrashTimer; - uint32 ParasiticShadowFiendTimer; - uint32 FireballTimer; - uint32 EyeBlastTimer; - uint32 DarkBarrageTimer; - uint32 SummonBladesTimer; // Animate summoning the Blades of Azzinoth in Phase 2 - uint32 SummonFlamesTimer; // Summon Flames of Azzinoth in Phase 2 - uint32 CheckFlamesTimer; // This is used to check the status of the Flames to see if we should begin entering Phase 3 or not. - uint32 RetrieveBladesTimer; // Animate retrieving the Blades of Azzinoth in Phase 2 -> 3 transition - uint32 LandTimer; // This is used at the end of phase 2 to signal Illidan landing after Flames are dead - uint32 AgonizingFlamesTimer; - uint32 ShadowBlastTimer; - uint32 FlameBurstTimer; - uint32 ShadowDemonTimer; - uint32 TalkTimer; - uint32 TransformTimer; - uint32 EnrageTimer; - uint32 CageTimer; - uint32 LayTrapTimer; - uint32 AnimationTimer; - uint32 TauntTimer; // This is used for his random yells - uint32 FaceVictimTimer; - uint32 BerserkTimer; - - void Reset() - { - Phase = PHASE_NORMAL; + if (m_uiShearTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHEAR) == CAST_OK) + m_uiShearTimer = urand(10000, 15000); + } + else + m_uiShearTimer -= uiDiff; - // Check if any flames/glaives are alive/existing. Kill if alive and set GUIDs to 0 - for(uint8 i = 0; i < 2; ++i) - { - if (Creature* Flame = m_creature->GetMap()->GetCreature(FlameGUID[i])) - { - if (Flame->isAlive()) - Flame->SetDeathState(JUST_DIED); + if (m_uiFlameCrashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_CRASH) == CAST_OK) + m_uiFlameCrashTimer = urand(25000, 35000); + } + else + m_uiFlameCrashTimer -= uiDiff; - FlameGUID[i] = 0; - } + if (m_uiShadowFiendTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_PARASITIC_SHADOWFIEND, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_PARASITIC_SHADOWFIEND) == CAST_OK) + m_uiShadowFiendTimer = 40000; + } + } + else + m_uiShadowFiendTimer -= uiDiff; - if (Creature* Glaive = m_creature->GetMap()->GetCreature(GlaiveGUID[i])) - { - if (Glaive->isAlive()) - Glaive->SetDeathState(JUST_DIED); + if (m_uiDrawSoulTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DRAW_SOUL) == CAST_OK) + m_uiDrawSoulTimer = 35000; + } + else + m_uiDrawSoulTimer -= uiDiff; - GlaiveGUID[i] = 0; - } - } + DoMeleeAttackIfReady(); - if (Creature* pAkama = m_creature->GetMap()->GetCreature(AkamaGUID)) - { - if (!pAkama->isAlive()) - pAkama->Respawn(); + break; + case PHASE_BLADES: - pAkama->AI()->EnterEvadeMode(); - } + if (m_uiCenterMoveTimer) + { + if (m_uiCenterMoveTimer <= uiDiff) + { + // 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].x, aCenterLoc[0].y, aCenterLoc[0].z); + m_uiCenterMoveTimer = 0; + } + else + m_uiCenterMoveTimer -= uiDiff; + } - InformAkama = false; - RefaceVictim = false; - HasSummoned = false; - - FaceVictimTimer = 1000; - BerserkTimer = 1500000; - GlobalTimer = 0; - DemonFormSequence = 0; - - /** Normal Form **/ - ShearTimer = urand(20000, 30000); // 20 to 30 seconds - FlameCrashTimer = 30000; // 30 seconds - ParasiticShadowFiendTimer = 25000; // 25 seconds - DrawSoulTimer = 50000; // 50 seconds - - /** Phase 2 **/ - SummonBladesTimer = 10000; - SummonFlamesTimer = 20000; // Phase 2 timers may be incorrect - FireballTimer = 5000; - DarkBarrageTimer = 45000; - EyeBlastTimer = 30000; - CheckFlamesTimer = 5000; - RetrieveBladesTimer = 5000; - LandTimer = 0; - - /** Phase 3+ **/ - AgonizingFlamesTimer = 35000; // Phase 3+ timers may be incorrect - ShadowBlastTimer = 3000; - FlameBurstTimer = 10000; - ShadowDemonTimer = 30000; - TransformTimer = 90000; - EnrageTimer = 40000; - CageTimer = 30000; - LayTrapTimer = CageTimer + 2000; - AnimationTimer = 0; - - TauntTimer = 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); + if (m_uiSummonBladesTimer) + { + if (m_uiSummonBladesTimer <= uiDiff) + { + if (m_pInstance) + { + // Need to provide explicit glaive targets + GuidVector vTargetsVect; + m_pInstance->GetGlaiveTargetGuidVector(vTargetsVect); - // Unequip warglaives if needed - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + Creature* pGlaive1 = m_creature->GetMap()->GetCreature(vTargetsVect[0]); + Creature* pGlaive2 = m_creature->GetMap()->GetCreature(vTargetsVect[1]); + if (!pGlaive1 || !pGlaive2) + return; - m_creature->RemoveSplineFlag(SPLINEFLAG_NO_SPLINE); + // 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; + } + } + } + else + m_uiSummonBladesTimer -= uiDiff; - IsTalking = false; + // no other spells during takeoff + return; + } - TalkCount = 0; - TalkTimer = 0; + if (m_uiFireballTimer < uiDiff) + { + 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_pInstance) - m_pInstance->SetData(TYPE_ILLIDAN, NOT_STARTED); - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void AttackStart(Unit *who) - { - if (!who || IsTalking || Phase == 2 || Phase == 4 || Phase == 6 || m_creature->HasAura(SPELL_KNEEL, EFFECT_INDEX_0)) - return; - - if (who == m_creature) - return; - - if (m_creature->Attack(who, true)) - { - m_creature->AddThreat(who); - m_creature->SetInCombatWith(who); - who->SetInCombatWith(m_creature); - - DoStartMovement(who); - } - } - - void MoveInLineOfSight(Unit *who) - { - if (!who || m_creature->getVictim() || IsTalking || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) - { - if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(who); - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) - { - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - } - } - - void JustDied(Unit *killer) - { - IsTalking = false; - TalkCount = 0; - TalkTimer = 0; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if (!m_pInstance) - return; - - // Completed - m_pInstance->SetData(TYPE_ILLIDAN, DONE); - - for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) - { - // Open Doors - if (GameObject* pDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(i))) - pDoor->SetGoState(GO_STATE_ACTIVE); - } - - } - - void KilledUnit(Unit *victim) - { - if (victim == m_creature) - return; - - DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (damage > m_creature->GetHealth()) // Don't let ourselves be slain before we do our death speech - { - damage = 0; - m_creature->SetHealth(m_creature->GetMaxHealth()/100); - } - } - - void Cast(Unit* victim, uint32 Spell, bool triggered = false) - { - if (!victim) - return; - - RefaceVictim = true; - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); - m_creature->CastSpell(victim, Spell, triggered); - } - - /** This will handle the cast of eye blast **/ - void CastEyeBlast() - { - m_creature->InterruptNonMeleeSpells(false); - - DarkBarrageTimer += 10000; - - DoScriptText(SAY_EYE_BLAST, m_creature); - - uint32 initial = urand(0, 3); - uint32 final = 0; - - if (initial < 3) - final = initial+1; - - float initial_X = EyeBlast[initial].x; - float initial_Y = EyeBlast[initial].y; - float initial_Z = EyeBlast[initial].z; - - float final_X = EyeBlast[final].x; - float final_Y = EyeBlast[final].y; - float final_Z = EyeBlast[final].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->IsTrigger = true; - - pTrigger->GetMotionMaster()->MovePoint(0, final_X, final_Y, final_Z); - - if (!i) - pTrigger->CastSpell(pTrigger, SPELL_EYE_BLAST_TRIGGER, true); - else + if (m_uiDarkBarrageTimer < uiDiff) { - pTrigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, pTrigger->GetGUID()); - DoCastSpellIfCan(pTrigger, SPELL_EYE_BLAST); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DARK_BARRAGE) == CAST_OK) + m_uiDarkBarrageTimer = 45000; + } } - } - } - } - - // 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 (Conversation[count].textId) - text = Conversation[count].textId; - - TalkTimer = Conversation[count].timer; - uint32 emote = Conversation[count].emote; - IsTalking = Conversation[count].Talk; - Creature* pCreature = NULL; - uint64 GUID = 0; + else + m_uiDarkBarrageTimer -= uiDiff; - if (Conversation[count].creature == ILLIDAN_STORMRAGE) - pCreature = m_creature; - else if (Conversation[count].creature == AKAMA) - { - if (!AkamaGUID) - { - if (m_pInstance) + if (m_uiEyeBlastTimer < uiDiff) { - AkamaGUID = m_pInstance->GetData64(DATA_AKAMA); - if (!AkamaGUID) - return; - GUID = AkamaGUID; + if (DoCastEyeBlastIfCan()) + { + m_uiEyeBlastTimer = urand(35000, 45000); + m_uiFireballTimer = 15000; + } } - } - else GUID = AkamaGUID; - } - else if (Conversation[count].creature == MAIEV_SHADOWSONG) - { - if (!MaievGUID) - return; - GUID = MaievGUID; - } - else if (Conversation[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 count) - { - uint32 unaura = DemonTransformation[count].unaura; - uint32 aura = DemonTransformation[count].aura; - uint32 displayid = DemonTransformation[count].displayid; - AnimationTimer = DemonTransformation[count].timer; - uint32 size = DemonTransformation[count].size; - - m_creature->InterruptNonMeleeSpells(false); - - if (DemonTransformation[count].phase != 8) - { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - } - - if (unaura) - m_creature->RemoveAurasDueToSpell(unaura); - - if (aura) - DoCastSpellIfCan(m_creature, aura, CAST_TRIGGERED); - - if (displayid) - // It's morphin time! - m_creature->SetDisplayId(displayid); - /*if (size) - m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); // Let us grow! (or shrink)*/ - - if (DemonTransformation[count].equip) - { - // 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[count].phase != 8) - Phase = DemonTransformation[count].phase; // Set phase properly - else - { - // Refollow and attack our old victim - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - - // Depending on whether we summoned Maiev, we switch to either phase 5 or 3 - if (MaievGUID) Phase = PHASE_NORMAL_MAIEV; - else Phase = PHASE_NORMAL_2; - } - - if (count == 7) - { - DoResetThreat(); - m_creature->RemoveAurasDueToSpell(SPELL_DEMON_FORM); - } - else if (count == 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); - - SummonBladesTimer = 10000; // Summon Glaives when this decrements - SummonFlamesTimer = 20000; // Summon Flames when this decrements - GlobalTimer += 20000; - LandTimer = 0; - Phase = PHASE_FLIGHT; - m_creature->RemoveAllAuras(); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); - - // So players don't shoot us down - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - // We now hover! - m_creature->AddSplineFlag(SPLINEFLAG_NO_SPLINE); - - 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, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - if (Glaive) - { - GlaiveGUID[i] = Glaive->GetGUID(); // 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); - - LandTimer = 0; - RetrieveBladesTimer = 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(GlaiveGUID[i]); - if (Glaive) - { - DoCastSpellIfCan(Glaive, SPELL_THROW_GLAIVE, CAST_TRIGGERED); - Glaive->SetVisibility(VISIBILITY_ON); - } - } - } + else + m_uiEyeBlastTimer -= uiDiff; - void SummonFlamesOfAzzinoth() - { - DoScriptText(SAY_SUMMONFLAMES, m_creature); + break; + case PHASE_DUAL_DEMON: - for(uint8 i = 0; i < 2; ++i) - { - Creature* Flame = NULL; - Creature* Glaive = NULL; - Glaive = m_creature->GetMap()->GetCreature(GlaiveGUID[i]); - if (Glaive) - { - Flame = m_creature->SummonCreature(FLAME_OF_AZZINOTH, GlaivePosition[i+2].x, GlaivePosition[i+2].y, GlaivePosition[i+2].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - if (Flame) + // Handle phase transition at 30% + if (m_uiPrevPhase == PHASE_DUAL_NORMAL && m_creature->GetHealthPercent() <= 30.0f) { - // 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 phase - FlameGUID[i] = Flame->GetGUID(); - - // Glaives do some random Beam type channel on it. - Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, true); + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_TRANSFORM_1) == CAST_OK) + { + m_uiTransformTimer = 12500; + m_uiPhase = PHASE_TRANSITION; - if (m_creature->getVictim()) - Flame->AI()->AttackStart(m_creature->getVictim()); - } - else - { - error_log("SD2: Illidan Stormrage AI: Unable to summon Flame of Azzinoth (entry: 22997), please check your database"); - EnterEvadeMode(); + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } } - } - 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 - HasSummoned = true; - } - - void SummonMaiev() - { - TauntTimer += 4000; - GlobalTimer += 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) - { - 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); - TalkCount = 10; - IsTalking = 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); - MaievGUID = Maiev->GetGUID(); - } - 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); - m_creature->GetMotionMaster()->Clear(false); // No moving! - m_creature->GetMotionMaster()->MoveIdle(); - - if (MaievGUID) - { - if (Creature* Maiev = m_creature->GetMap()->GetCreature(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->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - } - } - IsTalking = true; - ++TalkCount; - } - - void UpdateAI(const uint32 diff) - { - /*** This section will handle the conversations ***/ - if (IsTalking) // Somewhat more efficient using a function rather than a long switch - { - if (TalkTimer < diff) - { - switch(TalkCount) // 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: - if (AkamaGUID) - { - if (Creature* pAkama = m_creature->GetMap()->GetCreature(AkamaGUID)) - { - // Start attacking Akama - AttackStart(pAkama); - - // Akama stop talk and start attack illidan - if (npc_akama_illidanAI* pAkamaAI = dynamic_cast(pAkama->AI())) - pAkamaAI->IsTalking = false; - - pAkama->AI()->AttackStart(m_creature); - pAkama->AddThreat(m_creature, 1000000.0f); - } - } + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_TRANSFORM_1) == CAST_OK) + { + m_uiTransformTimer = 12500; + m_uiPhase = PHASE_TRANSITION; - // 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 (MaievGUID) - { - Creature* Maiev = m_creature->GetMap()->GetCreature(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->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - // Face her, so it's not rude =P - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Maiev->GetGUID()); - } - } - break; - case 14: - if (MaievGUID) - { - Creature* Maiev = m_creature->GetMap()->GetCreature(MaievGUID); - if (Maiev) - { - Maiev->GetMotionMaster()->Clear(false); - Maiev->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 - Maiev->AddThreat(m_creature, 10000000.0f); - // Force Maiev to attack us. - Maiev->AI()->AttackStart(m_creature); - Maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - } - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - IsTalking = false; - FaceVictimTimer = 2000; - RefaceVictim = true; - break; - case 20: - // Kill ourself. - if (MaievGUID) - { - Creature* Maiev = m_creature->GetMap()->GetCreature(MaievGUID); - if (Maiev) - { - // Make Maiev leave - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - Maiev->SetDeathState(JUST_DIED); - } - } - IsTalking = 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; + } } + else + m_uiTransformTimer -= uiDiff; - // This function does most of the talking - Talk(TalkCount); - ++TalkCount; - }else TalkTimer -= diff; - } - - // If we don't have a target, return. - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || IsTalking) - 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. - EnrageTimer = 40000; - CageTimer = 30000; - return; - } - - // Berserk Timer - flat 25 minutes - if (!m_creature->HasAura(SPELL_BERSERK, EFFECT_INDEX_0) && Phase != PHASE_DEMON_SEQUENCE) - { - if (BerserkTimer < diff) - { - DoScriptText(SAY_ENRAGE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); - }else BerserkTimer -= diff; - } - - if (RefaceVictim) - { - if (FaceVictimTimer < diff) - { - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); - FaceVictimTimer = 1000; - RefaceVictim = false; - }else FaceVictimTimer -= diff; - } - - /** Signal to change to phase 2 **/ - if (m_creature->GetHealthPercent() < 65.0f && Phase == PHASE_NORMAL) - EnterPhase2(); - - /** Signal to summon Maiev **/ - if (m_creature->GetHealthPercent() < 30.0f && !MaievGUID && (Phase != PHASE_DEMON || Phase != PHASE_DEMON_SEQUENCE)) - SummonMaiev(); - - /** Time for the death speech **/ - if (m_creature->GetHealthPercent() < 1.0f && !IsTalking && (Phase != PHASE_DEMON || Phase != PHASE_DEMON_SEQUENCE)) - InitializeDeath(); - - /***** Spells for Phase 1, 3 and 5 (Normal Form) ******/ - if (Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV) - { - if (TauntTimer < diff) // His random taunt/yell timer. - { - uint32 random = urand(0, 3); - int32 yell = RandomTaunts[random].textId; - if (yell) - DoScriptText(yell, m_creature); - TauntTimer = 32000; - }else TauntTimer -= diff; - - // Global Timer so that spells do not overlap. - if (GlobalTimer < diff) - { - if (ShearTimer < diff) + if (m_uiShadowDemonTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHEAR); - ShearTimer = urand(25000, 40000); - GlobalTimer += 2000; - }else ShearTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SHADOW_DEMONS) == CAST_OK) + m_uiShadowDemonTimer = 60000; + } + else + m_uiShadowDemonTimer -= uiDiff; - if (FlameCrashTimer < diff) - { - //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); - FlameCrashTimer = 35000; - GlobalTimer += 2000; - }else FlameCrashTimer -= diff; - - if (ParasiticShadowFiendTimer < diff) + if (m_uiShadowBlastTimer < 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_TOPAGGRO, 0)) { - Cast(target, SPELL_PARASITIC_SHADOWFIEND); - ParasiticShadowFiendTimer = 40000; + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_BLAST) == CAST_OK) + m_uiShadowBlastTimer = urand(2000, 3000); } - }else ParasiticShadowFiendTimer -= diff; - - if (DrawSoulTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DRAW_SOUL); - DrawSoulTimer = 55000; - GlobalTimer += 3000; - }else DrawSoulTimer -= diff; - }else GlobalTimer -= diff; - - if (!IsTalking) - DoMeleeAttackIfReady(); - } - - /*** Phase 2 ***/ - if (Phase == PHASE_FLIGHT) - { - // Check if we have summoned or not. - if (!HasSummoned) - { - if (SummonBladesTimer) - if (SummonBladesTimer <= diff) - { - SummonBladesOfAzzinoth(); - SummonBladesTimer = 0; - }else SummonBladesTimer -= diff; + } + else + m_uiShadowBlastTimer -= uiDiff; - if (SummonFlamesTimer < diff) + if (m_uiFlameBurstTimer < uiDiff) { - SummonFlamesOfAzzinoth(); - }else SummonFlamesTimer -= diff; - } + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BURST) == CAST_OK) + m_uiFlameBurstTimer = 20000; + } + else + m_uiFlameBurstTimer -= uiDiff; - if (!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) - m_creature->GetMotionMaster()->Clear(false); + break; + case PHASE_TRANSITION: - if (HasSummoned) - { - if (CheckFlamesTimer) + if (m_uiLandTimer) { - if (CheckFlamesTimer <= diff) + if (m_uiLandTimer <= uiDiff) { - // Check if flames are dead or non-existant. If so, set GUID to 0. - for(uint8 i = 0; i < 2; ++i) + switch (m_uiLandStage) { - if (FlameGUID[i]) - { - Creature* Flame = m_creature->GetMap()->GetCreature(FlameGUID[i]); + 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); - // If the flame dies, or somehow the pointer becomes invalid, reset GUID to 0. - if (!Flame || !Flame->isAlive()) - FlameGUID[i] = 0; - } + 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; } - CheckFlamesTimer = 500; - }else CheckFlamesTimer -= diff; - } - - // If both flames are dead/non-existant, kill glaives and change to phase 3. - if (!FlameGUID[0] && !FlameGUID[1] && CheckFlamesTimer) - { - RetrieveBladesTimer = 5000; // Prepare for re-equipin! - CheckFlamesTimer = 0; + ++m_uiLandStage; + } + else + m_uiLandTimer -= uiDiff; } - if (RetrieveBladesTimer) + if (m_uiTransformTimer) { - if (RetrieveBladesTimer <= diff) // Time to get back our glaives! + if (m_uiTransformTimer <= uiDiff) { - // Interrupt any spells we might be doing *cough* DArk Barrage *cough* - m_creature->InterruptNonMeleeSpells(false); - for(uint8 i = 0; i < 2; ++i) + // Drop the transform time from the spell timers + if (m_creature->HasAura(SPELL_DEMON_FORM)) { - if (GlaiveGUID[i]) - { - Creature* Glaive = m_creature->GetMap()->GetCreature(GlaiveGUID[i]); - if (Glaive) - { - // Make it look like the Glaive flies back up to us - Glaive->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, true); - // Despawn the Glaive - Glaive->SetDeathState(JUST_DIED); - } - GlaiveGUID[i] = 0; - } + DoResetThreat(); + m_uiPhase = PHASE_DUAL_DEMON; + m_uiShadowDemonTimer = 17000; + m_uiFlameBurstTimer = 7000; + m_uiTransformTimer = 47000; } - - // Re-equip our warblades! - SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE); - - // Prepare for landin'! - LandTimer = 5000; - RetrieveBladesTimer = 0; - }else RetrieveBladesTimer -= diff; + else + { + m_uiPhase = m_uiPrevPhase; + m_uiEnrageTimer = 40000; + m_uiTransformTimer = 60000; + m_uiTrapTimer = urand(30000, 40000); + } + } + else + m_uiTransformTimer -= uiDiff; } - if (LandTimer) - { - // Time to land! - if (LandTimer <= diff) - { - DoResetThreat(); - - // anndddd touchdown! - m_creature->HandleEmote(EMOTE_ONESHOT_LAND); - m_creature->RemoveSplineFlag(SPLINEFLAG_NO_SPLINE); - Phase = PHASE_NORMAL_2; + break; + } + } +}; - // We should let the raid fight us =) - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); +/*###### +## npc_akama_illidan +######*/ - // Chase our victim! - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - }else LandTimer -= diff; - return; // Do not continue past this point if LandTimer is not 0 and we are in phase 2. - } - } +struct MANGOS_DLL_DECL 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(); + } - if (GlobalTimer < diff) - { - if (FireballTimer < diff) - { - Cast(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0), SPELL_FIREBALL); - FireballTimer = 5000; - }else FireballTimer -= diff; + ScriptedInstance* m_pInstance; - if (DarkBarrageTimer < diff) - { - m_creature->InterruptNonMeleeSpells(false); + uint32 m_uiSummonMinionTimer; + uint32 m_uiHealDelayTimer; + uint32 m_uiChainLightningTimer; - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_DARK_BARRAGE); + bool m_bFightMinions; + bool m_bIsIntroFinished; - DarkBarrageTimer = 35000; - GlobalTimer += 9000; - }else DarkBarrageTimer -= diff; + void Reset() override + { + m_uiSummonMinionTimer = 2000; + m_uiHealDelayTimer = 0; + m_uiChainLightningTimer = urand(5000, 10000); - if (EyeBlastTimer < diff) - { - CastEyeBlast(); - EyeBlastTimer = 30000; - }else EyeBlastTimer -= diff; - }else GlobalTimer -= diff; + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_bFightMinions = false; + m_bIsIntroFinished = false; } + } - /** Phase 3,5 spells only**/ - if (Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV) - { - if (GlobalTimer < diff) - { - if (AgonizingFlamesTimer < diff) - { - CastAgonizingFlames(); - AgonizingFlamesTimer = 60000; - }else AgonizingFlamesTimer -= diff; - }else GlobalTimer -= diff; + void MoveInLineOfSight(Unit* pWho) override + { + if (HasEscortState(STATE_ESCORT_ESCORTING)) + return; - if (TransformTimer < diff) - { - float CurHealth = m_creature->GetHealthPercent(); - // Prevent Illidan from morphing if less than 32% or 5%, as this may cause issues with the phase transition or death speech - if ((CurHealth < 32.0f && !MaievGUID) || CurHealth < 5.0f) - return; + // Star the event + if (pWho->GetTypeId() == TYPEID_PLAYER && pWho->IsWithinDistInMap(m_creature, 70.0f) && pWho->IsWithinLOSInMap(m_creature)) + Start(true); + } - Phase = PHASE_DEMON_SEQUENCE; // Transform sequence - DemonFormSequence = 0; - AnimationTimer = 0; + void AttackStart(Unit* pWho) override + { + // Don't attack Illidan again + if (m_bIsIntroFinished && pWho->GetEntry() == NPC_ILLIDAN_STORMRAGE) + return; - DoScriptText(SAY_MORPH, m_creature); + npc_escortAI::AttackStart(pWho); + } - TransformTimer = 60000; - FlameBurstTimer = 10000; - ShadowDemonTimer = 30000; - m_creature->GetMotionMaster()->Clear(false);// Stop moving - }else TransformTimer -= diff; + void EnterEvadeMode() override + { + // Called first when evading from Illidan + if (!m_bIsIntroFinished) + { + SetEscortPaused(false); + m_bIsIntroFinished = true; } - /** Phase 4 spells only (Demon Form) **/ - if (Phase == PHASE_DEMON) + // Go back to epilogue position + if (m_pInstance && m_pInstance->GetData(TYPE_ILLIDAN) == DONE) { - // Stop moving if we are by clearing movement generators. - if (!m_creature->GetMotionMaster()->empty()) - m_creature->GetMotionMaster()->Clear(false); + SetEscortPaused(false); + m_bFightMinions = false; + } - if (TransformTimer < diff) - { - Phase = PHASE_DEMON_SEQUENCE; - DemonFormSequence = 5; - AnimationTimer = 100; - TransformTimer = 60000; - }else TransformTimer -= diff; + npc_escortAI::EnterEvadeMode(); + } - if (ShadowDemonTimer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - Creature* ShadowDemon = NULL; - for(uint8 i = 0; i < 4; ++i) + 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) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - - // only on players. - if (target && target->GetTypeId() == TYPEID_PLAYER) + 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)) { - ShadowDemon = m_creature->SummonCreature(SHADOW_DEMON, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000); - if (ShadowDemon) - { - ShadowDemon->AddThreat(target, 5000000.0f); - ShadowDemon->AI()->AttackStart(target); - ShadowDemon->SetInCombatWithZone(); - } + if (boss_illidan_stormrageAI* pIllidanAI = dynamic_cast(pIllidan->AI())) + pIllidanAI->DoStartCombatEvent(); + + m_creature->SetFacingToObject(pIllidan); } } - ShadowDemonTimer = 60000; - }else ShadowDemonTimer -= diff; - - if (GlobalTimer < diff) - { - if (ShadowBlastTimer < diff) + break; + case 24: + SetEscortPaused(true); + m_bFightMinions = true; + break; + case 30: + SetEscortPaused(true); + if (m_pInstance) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0); - if (target && target->isAlive()) + // Move to a close point to Illidan + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) { - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - DoCastSpellIfCan(target, SPELL_SHADOW_BLAST); - ShadowBlastTimer = 4000; - GlobalTimer += 1500; + float fX, fY, fZ; + pIllidan->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(100, fX, fY, fZ); } - if (!m_creature->HasAura(SPELL_DEMON_FORM, EFFECT_INDEX_0)) - DoCastSpellIfCan(m_creature, SPELL_DEMON_FORM, CAST_TRIGGERED); - }else ShadowBlastTimer -= diff; - - if (FlameBurstTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAME_BURST); - FlameBurstTimer = 15000; - }else FlameBurstTimer -= diff; - }else GlobalTimer -= diff; + } + break; } + } - /** Phase 5 timers. Enrage spell **/ - if (Phase == PHASE_NORMAL_MAIEV) - { - if (EnrageTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - EnrageTimer = 40000; - CageTimer = 30000; - TransformTimer += 10000; - }else EnrageTimer -= diff; - - // We'll handle Cage Trap in Illidan's script for simplicity's sake - if (CageTimer < diff) - { - if (MaievGUID) - { - Creature* Maiev = m_creature->GetMap()->GetCreature(MaievGUID); - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (!Maiev || !target || (target->GetTypeId() != TYPEID_PLAYER)) - return; - - float X, Y, Z; - target->GetPosition(X, Y, Z); - Maiev->GetMap()->CreatureRelocation(m_creature, X, Y, Z, Maiev->GetOrientation()); + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + npc_escortAI::MovementInform(uiMoveType, uiPointId); - // Make it look like she 'teleported' - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - // summon the trap! - Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false); - } - CageTimer = 15000; - }else CageTimer -= diff; - } + if (uiMoveType != POINT_MOTION_TYPE || uiPointId != 100) + return; - if (Phase == PHASE_DEMON_SEQUENCE) // Demonic Transformation + // Do outro + if (m_pInstance) { - if (AnimationTimer < diff) - { - HandleDemonTransformAnimation(DemonFormSequence); - ++DemonFormSequence; - }else AnimationTimer -= diff; + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + m_creature->SetFacingToObject(pIllidan); } - } -}; -/*********************** End of Illidan AI ******************************************/ - -void npc_akama_illidanAI::BeginEvent(uint64 PlayerGUID) -{ - debug_log("SD2: Akama - Illidan Introduction started. Illidan event properly begun."); - if (m_pInstance) - { - IllidanGUID = m_pInstance->GetData64(DATA_ILLIDANSTORMRAGE); - m_pInstance->SetData(TYPE_ILLIDAN, IN_PROGRESS); + DoScriptText(SAY_AKAMA_EPILOGUE_5, m_creature); + m_creature->ForcedDespawn(10000); } - if (m_pInstance) + void JustDidDialogueStep(int32 iEntry) override { - for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) + switch (iEntry) { - if (GameObject* pDoor = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(i))) - pDoor->SetGoState(GO_STATE_READY); + 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; } } - if (IllidanGUID) + void JustSummoned(Creature* pSummoned) override { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (Creature* pIllidan = m_creature->GetMap()->GetCreature(IllidanGUID)) + switch (pSummoned->GetEntry()) { - 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->TalkCount = 0; + 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; + } + } - // Begin Talking - pIllidanAI->IsTalking = true; - pIllidanAI->AkamaGUID = m_creature->GetGUID(); + // Wrapper to handle event resume + void DoResumeEvent() + { + SetEscortPaused(false); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, pIllidan->GetGUID()); - pIllidan->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); - IsTalking = true; // Prevent Akama from starting to attack him - // Prevent players from talking again + if (m_bFightMinions) + { + if (m_uiSummonMinionTimer < uiDiff) + { + for (uint8 i = 0; i < MAX_ILLIDARI_ELITES; ++i) + m_creature->SummonCreature(NPC_ILLIDARI_ELITE, aIllidariElitesPos[i].x, aIllidariElitesPos[i].y, aIllidariElitesPos[i].z, 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) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(10465, pCreature->GetGUID()); + // 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 MANGOS_DLL_DECL 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(); }; - uint32 TauntTimer; - uint64 IllidanGUID; - ScriptedInstance* m_pInstance; - void Reset() + uint32 m_uiTauntTimer; + uint32 m_uiShadowStriketimer; + uint32 m_uiThrowDaggerTimer; + + bool m_bHasYelledTrap; + + void Reset() override + { + 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 { - TauntTimer = 12000; - IllidanGUID = 0; + // Dummy function - used to start the epilogue + if (pVictim->GetEntry() == NPC_ILLIDAN_STORMRAGE) + StartNextDialogueText(SAY_MAIEV_EPILOGUE_1); } - void UpdateAI(const uint32 diff) + // Custom evade - don't allow her to return to home position + void EnterEvadeMode() override { - if (!IllidanGUID) - { - if (m_pInstance) - IllidanGUID = m_pInstance->GetData64(DATA_ILLIDANSTORMRAGE); - }else + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + // Attack only by script + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) { - Creature* Illidan = m_creature->GetMap()->GetCreature(IllidanGUID); + 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; + } + } - if (!Illidan || !Illidan->isAlive() || Illidan->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 (Illidan && Illidan->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 (TauntTimer < diff) + if (m_uiTauntTimer < uiDiff) { - uint32 random = urand(0, 3); - int32 text = MaievTaunts[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; - TauntTimer = urand(22000, 42000); - }else TauntTimer -= diff; + if (m_uiThrowDaggerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_THROW_DAGGER) == CAST_OK) + m_uiThrowDaggerTimer = urand(6000, 10000); + } + else + m_uiThrowDaggerTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL cage_trap_triggerAI : public ScriptedAI -{ - cage_trap_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint64 IllidanGUID; - uint64 CageTrapGUID; +/*###### +## npc_cage_trap_trigger +######*/ - uint32 DespawnTimer; +struct MANGOS_DLL_DECL npc_cage_trap_triggerAI : public ScriptedAI +{ + npc_cage_trap_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool Active; - bool SummonedBeams; + bool m_bActive; - void Reset() + void Reset() override { - IllidanGUID = 0; - CageTrapGUID = 0; - - Active = false; - SummonedBeams = false; - - DespawnTimer = 0; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_bActive = false; } - void MoveInLineOfSight(Unit *who) - { - if (!Active) - return; - - if (who && (who->GetTypeId() != TYPEID_PLAYER)) - { - if (who->GetEntry() == ILLIDAN_STORMRAGE) // Check if who is Illidan - { - if (!IllidanGUID && m_creature->IsWithinDistInMap(who, 3) && !who->HasAura(SPELL_CAGED, EFFECT_INDEX_0)) - { - IllidanGUID = who->GetGUID(); - who->CastSpell(who, SPELL_CAGED, true); - DespawnTimer = 5000; - - // Dispel his enrage - if (who->HasAura(SPELL_ENRAGE, EFFECT_INDEX_0)) - who->RemoveAurasDueToSpell(SPELL_ENRAGE); - - if (GameObject* pCageTrap = m_creature->GetMap()->GetGameObject(CageTrapGUID)) - pCageTrap->SetLootState(GO_JUST_DEACTIVATED); - } - } - } - } + void AttackStart(Unit* /*pWho*/) override { } - void UpdateAI(const uint32 diff) + void MoveInLineOfSight(Unit* pWho) override { - if (DespawnTimer) + if (!m_bActive && pWho->GetEntry() == NPC_ILLIDAN_STORMRAGE && m_creature->IsWithinDistInMap(pWho, 3.0f)) { - if (DespawnTimer <= diff) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - else DespawnTimer -= diff; - } + pWho->CastSpell(pWho, SPELL_CAGED, true); - //if (IllidanGUID && !SummonedBeams) - //{ - // if (Creature* pIllidan = m_creature->GetMap()->GetCreature(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 GOHello_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->Active = 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 MANGOS_DLL_DECL npc_flame_of_azzinothAI : public ScriptedAI { - flame_of_azzinothAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_flame_of_azzinothAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 FlameBlastTimer; - uint32 SummonBlazeTimer; - uint32 ChargeTimer; + uint32 m_uiFlameBlastTimer; + uint32 m_uiSummonBlazeTimer; + uint32 m_uiChargeTimer; + uint32 m_uiWrathCheckTimer; - void Reset() + void Reset() override { - FlameBlastTimer = urand(15000, 30000); - SummonBlazeTimer = urand(10000, 30000); - ChargeTimer = 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(); + if (pSummoned->GetEntry() == NPC_BLAZE) + pSummoned->CastSpell(pSummoned, SPELL_BLAZE_EFFECT, false); + } - // He doesn't have anyone in his threatlist, useless to continue - if (tList.empty()) + void UpdateAI(const uint32 uiDiff) override + { + 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_uiFlameBlastTimer < 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->getVictim(), SPELL_FLAME_BLAST) == CAST_OK) + { + m_uiFlameBlastTimer = 10000; + m_uiSummonBlazeTimer = 3000; + } } + else + m_uiFlameBlastTimer -= uiDiff; - //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))) + if (m_uiSummonBlazeTimer) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_TRIGGERED); - DoCastSpellIfCan(target, SPELL_CHARGE); + if (m_uiSummonBlazeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLAZE) == CAST_OK) + m_uiSummonBlazeTimer = 0; + } + else + m_uiSummonBlazeTimer -= uiDiff; } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - if (FlameBlastTimer < diff) + // 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) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BLAST); - FlameBlastTimer = 30000; - }else FlameBlastTimer -= diff; + 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; + } - if (SummonBlazeTimer < diff) + // Try to find a suitable target to charge + if (m_uiChargeTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BLAZE_SUMMON); - SummonBlazeTimer = urand(30000, 50000); - }else SummonBlazeTimer -= diff; + std::vector suitableTargets; + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); - if (ChargeTimer < diff) - { - Charge(); - ChargeTimer = 5000; - }else ChargeTimer -= diff; + 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 -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL shadow_demonAI : public ScriptedAI -{ - shadow_demonAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} +/*###### +## npc_shadow_demon +######*/ - uint64 TargetGUID; +struct MANGOS_DLL_DECL npc_shadow_demonAI : public ScriptedAI +{ + npc_shadow_demonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() { TargetGUID = 0; } + ObjectGuid m_targetGuid; - void JustDied(Unit *killer) - { - if (TargetGUID) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(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)) - { - TargetGUID = m_creature->getVictim()->GetGUID(); - 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 FlameCrashTimer; - uint32 DespawnTimer; + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + void JustDied(Unit* /*pKiller*/) override { - FlameCrashTimer = urand(3000, 8000); - DespawnTimer = 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 (FlameCrashTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAME_CRASH_EFFECT); - FlameCrashTimer = 15000; - }else FlameCrashTimer -= diff; + if (uiMovementType != POINT_MOTION_TYPE || !uiPointId) + return; - if (DespawnTimer < 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); - }else DespawnTimer -= diff; + if (DoCastSpellIfCan(pPlayer, SPELL_CONSUME_SOUL) == CAST_OK) + m_creature->ForcedDespawn(1000); + } } + + void UpdateAI(const uint32 /*uiDiff*/) override { } }; -// Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap -struct MANGOS_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI +/*###### +## npc_blade_of_azzinoth +######*/ + +struct MANGOS_DLL_DECL 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->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - //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 BlazeTimer; - uint32 DespawnTimer; + // Do-Nothing-But-Stand-There + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + void JustSummoned(Creature* pSummoned) override { - BlazeTimer = 2000; - DespawnTimer = 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 (BlazeTimer < diff) + // Inform Illidan when a flame is killed + if (pSummoned->GetEntry() == NPC_FLAME_OF_AZZINOTH) { - DoCastSpellIfCan(m_creature, SPELL_BLAZE_EFFECT); - BlazeTimer = 15000; - }else BlazeTimer -= diff; + if (!m_pInstance) + return; - if (DespawnTimer < diff) - { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - }else DespawnTimer -= diff; + // 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(); + } + } } -}; - -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) @@ -2356,14 +1648,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, AkamaWP[i].x, AkamaWP[i].y, AkamaWP[i].z); - - return ((CreatureAI*)Akama_AI); + return new npc_akama_illidanAI(pCreature); } CreatureAI* GetAI_boss_maiev(Creature* pCreature) @@ -2373,107 +1660,62 @@ 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); } -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() { - Script* newscript; - - newscript = new Script; - newscript->Name = "boss_illidan_stormrage"; - newscript->GetAI = &GetAI_boss_illidan_stormrage; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_akama_illidan"; - newscript->GetAI = &GetAI_npc_akama_at_illidan; - newscript->pGossipHello = &GossipHello_npc_akama_at_illidan; - newscript->pGossipSelect = &GossipSelect_npc_akama_at_illidan; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_maiev_shadowsong"; - newscript->GetAI = &GetAI_boss_maiev; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_flame_of_azzinoth"; - newscript->GetAI = &GetAI_mob_flame_of_azzinoth; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_blade_of_azzinoth"; - newscript->GetAI = &GetAI_blade_of_azzinoth; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "gameobject_cage_trap"; - newscript->pGOHello = &GOHello_cage_trap; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_cage_trap_trigger"; - newscript->GetAI = &GetAI_cage_trap_trigger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_shadow_demon"; - newscript->GetAI = &GetAI_shadow_demon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_flame_crash"; - newscript->GetAI = &GetAI_flamecrash; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_demon_fire"; - newscript->GetAI = &GetAI_demonfire; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_blaze"; - newscript->GetAI = &GetAI_blaze; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_parasitic_shadowfiend"; - newscript->GetAI = &GetAI_parasitic_shadowfiend; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_illidan_stormrage"; + pNewScript->GetAI = &GetAI_boss_illidan_stormrage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_akama_illidan"; + pNewScript->GetAI = &GetAI_npc_akama_illidan; + pNewScript->pGossipHello = &GossipHello_npc_akama_illidan; + pNewScript->pGossipSelect = &GossipSelect_npc_akama_illidan; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_maiev_shadowsong"; + pNewScript->GetAI = &GetAI_boss_maiev; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_flame_of_azzinoth"; + pNewScript->GetAI = &GetAI_mob_flame_of_azzinoth; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_blade_of_azzinoth"; + pNewScript->GetAI = &GetAI_npc_blade_of_azzinoth; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_cage_trap_trigger"; + pNewScript->GetAI = &GetAI_npc_cage_trap_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_shadow_demon"; + 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 ec1eaac7d9..f5e92c7ba3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,87 +61,63 @@ uint32 PrismaticAuras[]= 40897, // Holy }; -struct Locations -{ - float x,y,z; -}; - -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} -}; +static const uint32 aPeriodicBeams[] = {SPELL_SINFUL_PERIODIC, SPELL_SINISTER_PERIODIC, SPELL_VILE_PERIODIC, SPELL_WICKED_PERIODIC}; struct MANGOS_DLL_DECL 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; - uint64 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) - TargetGUID[i] = 0; - - 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); - m_creature->SetInCombatWithZone(); - 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); @@ -148,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)) - { - TargetGUID[i] = pUnit->GetGUID(); - 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 (TargetGUID[i]) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(TargetGUID[i])) - pPlayer->CastSpell(pPlayer, SPELL_ATTRACTION, true); - - TargetGUID[i] = 0; - } + 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(); } @@ -300,9 +225,10 @@ CreatureAI* GetAI_boss_shahraz(Creature* pCreature) void AddSC_boss_mother_shahraz() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_mother_shahraz"; - newscript->GetAI = &GetAI_boss_shahraz; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_mother_shahraz"; + pNewScript->GetAI = &GetAI_boss_shahraz; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/boss_reliquary_of_souls.cpp b/scripts/outland/black_temple/boss_reliquary_of_souls.cpp index bde3a38b51..b4a3e5198c 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,714 +24,450 @@ 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 MANGOS_DLL_DECL boss_reliquary_of_soulsAI : public Scripted_NoMovementAI { - npc_enslaved_soulAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint64 ReliquaryGUID; - - void Reset() + boss_reliquary_of_soulsAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - ReliquaryGUID = 0; - } - - 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) - { - SufferingGUID = 0; - DesireGUID = 0; - AngerGUID = 0; m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } ScriptedInstance* m_pInstance; - uint64 SufferingGUID; - uint64 DesireGUID; - uint64 AngerGUID; + uint8 m_uiPhase; + uint8 m_uiSoulSummonedCount; + uint8 m_uiSoulDeathCount; - 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; + uint32 m_uiSummonEssenceTimer; + uint32 m_uiSummonSoulTimer; + uint32 m_uiAnimationTimer; + uint32 m_uiAnimResetTimer; - bool IsDead; - bool EndingPhase; - - void Reset() + void Reset() override { - DespawnEssences(); - - SoulDeathCount = 0; - Phase = 0; - SummonEssenceTimer = 8000; - DespawnEssenceTimer = 2000; - SoulCount = 0; - SummonSoulTimer = 1000; - AnimationTimer = 8000; + m_uiPhase = PHASE_0_NOT_BEGUN; + m_uiSoulDeathCount = 0; + m_uiSoulSummonedCount = 0; - IsDead = false; - EndingPhase = false; + m_uiSummonSoulTimer = 1000; + m_uiAnimationTimer = 0; + m_uiAnimResetTimer = 0; + m_uiSummonEssenceTimer = 0; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); - 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 (SufferingGUID) - pEssence = m_creature->GetMap()->GetCreature(SufferingGUID); - else if (DesireGUID) - pEssence = m_creature->GetMap()->GetCreature(DesireGUID); - else if (AngerGUID) - pEssence = m_creature->GetMap()->GetCreature(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->SetUInt32Value(UNIT_NPC_EMOTESTATE,375); - 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->ReliquaryGUID = m_creature->GetGUID(); - - 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->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); - AnimationTimer = 8300; - }else AnimationTimer -= diff; - - if (SummonEssenceTimer < diff) - { - // Ribs: open - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); + // 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); + } - SufferingGUID = EssenceSuffering->GetGUID(); - } + // 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 (SufferingGUID) + if (m_uiAnimationTimer <= uiDiff) { - Creature* EssenceSuffering = m_creature->GetMap()->GetCreature(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->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (DespawnEssenceTimer < diff) - { - DoScriptText(SUFF_SAY_AFTER, EssenceSuffering); - - EssenceSuffering->DeleteThreatList(); - EssenceSuffering->SetDisplayId(11686); - EssenceSuffering->setFaction(35); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); - SummonEssenceTimer = 20000; //60000; - AnimationTimer = 18200; //58100; - SoulDeathCount = 0; - SoulCount = 0; - SummonSoulTimer = 1000; - EndingPhase = false; - Phase = 3; - SufferingGUID = 0; - }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->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (SummonEssenceTimer < diff) - { - // Ribs: open - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); - - 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); - } - - DesireGUID = EssenceDesire->GetGUID(); - 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 (DesireGUID) + if (m_uiSummonEssenceTimer <= uiDiff) { - Creature* EssenceDesire = m_creature->GetMap()->GetCreature(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->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (DespawnEssenceTimer < diff) - { - EssenceDesire->DeleteThreatList(); - EssenceDesire->setFaction(35); - - DoScriptText(DESI_SAY_AFTER, EssenceDesire); - - EssenceDesire->SetDisplayId(11686); - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); - SummonEssenceTimer = 20000; - AnimationTimer = 18200; - SoulDeathCount = 0; - SoulCount = 0; - SummonSoulTimer = 1000; - EndingPhase = false; - Phase = 5; - DesireGUID = 0; - }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->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (SummonEssenceTimer < diff) - { - // Ribs: open - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); - - 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; } - - AngerGUID = EssenceAnger->GetGUID(); - DoScriptText(ANGER_SAY_FREED, EssenceAnger); - SoulDeathCount = 0; - } - - Phase = 6; - }else SummonEssenceTimer -= diff; - } - } - - if (Phase == 6) - { - if (AngerGUID) - { - Creature* EssenceAnger = m_creature->GetMap()->GetCreature(AngerGUID); - - if (!EssenceAnger) - EnterEvadeMode(); - - if (m_creature->isAlive() && EssenceAnger) - { - if (!EssenceAnger->isAlive()) - { - AngerGUID = 0; - 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 +/*###### +## essence_base_AI +######*/ + +struct MANGOS_DLL_DECL essence_base_AI : public ScriptedAI { - boss_essence_of_sufferingAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + essence_base_AI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsPhaseFinished = false; + } - uint64 StatAuraGUID; + ScriptedInstance* m_pInstance; - uint32 AggroYellTimer; - uint32 FixateTimer; - uint32 EnrageTimer; - uint32 SoulDrainTimer; + bool m_bIsPhaseFinished; - void Reset() - { - StatAuraGUID = 0; + virtual void OnPhaseFinished() {} - AggroYellTimer = 5000; - FixateTimer = 5000; - EnrageTimer = 30000; - SoulDrainTimer = 150000; - } - - 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 (StatAuraGUID) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(StatAuraGUID)) - pPlayer->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); - } + if (Creature* pReliquary = m_pInstance->GetSingleCreatureFromStorage(NPC_RELIQUARY_OF_SOULS)) + pReliquary->AI()->EnterEvadeMode(); } - } - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - 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 MANGOS_DLL_DECL 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 (StatAuraGUID) + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(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_desireAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 AggroYellTimer; - uint32 RuneShieldTimer; - uint32 DeadenTimer; - uint32 SoulShockTimer; +/*###### +## boss_essence_of_desire +######*/ - void Reset() - { - AggroYellTimer = 5000; - RuneShieldTimer = 60000; - DeadenTimer = 15000; - SoulShockTimer = 40000; - } +struct MANGOS_DLL_DECL boss_essence_of_desireAI : public essence_base_AI +{ + boss_essence_of_desireAI(Creature* pCreature) : essence_base_AI(pCreature) { Reset(); } - 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); - } - } + uint32 m_uiRuneShieldTimer; + uint32 m_uiDeadenTimer; + uint32 m_uiSoulShockTimer; - void Aggro(Unit* pWho) + void Reset() override { - m_creature->SetInCombatWithZone(); + m_uiRuneShieldTimer = urand(10000, 15000); + m_uiDeadenTimer = 15000; + m_uiSoulShockTimer = urand(5000, 10000); + + 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; @@ -739,193 +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(); } }; +/*###### +## boss_essence_of_anger +######*/ + struct MANGOS_DLL_DECL boss_essence_of_angerAI : public ScriptedAI { - boss_essence_of_angerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint64 AggroTargetGUID; - - uint32 AggroYellTimer; - uint32 CheckTankTimer; - uint32 SoulScreamTimer; - uint32 SpiteTimer; - - bool CheckedAggro; - - void Reset() + boss_essence_of_angerAI(Creature* pCreature) : ScriptedAI(pCreature) { - AggroTargetGUID = 0; + 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 { - m_creature->SetInCombatWithZone(); - 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) { - AggroTargetGUID = m_creature->getVictim()->GetGUID(); - 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()->GetGUID() != 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); - AggroTargetGUID = m_creature->getVictim()->GetGUID(); + 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 MANGOS_DLL_DECL 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 (ReliquaryGUID) + void JustReachedHome() override { - if (Creature* pReliquary = m_creature->GetMap()->GetCreature(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) { @@ -954,29 +683,30 @@ CreatureAI* GetAI_npc_enslaved_soul(Creature* pCreature) void AddSC_boss_reliquary_of_souls() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_reliquary_of_souls"; - newscript->GetAI = &GetAI_boss_reliquary_of_souls; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_essence_of_suffering"; - newscript->GetAI = &GetAI_boss_essence_of_suffering; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_essence_of_desire"; - newscript->GetAI = &GetAI_boss_essence_of_desire; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_essence_of_anger"; - newscript->GetAI = &GetAI_boss_essence_of_anger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_enslaved_soul"; - newscript->GetAI = &GetAI_npc_enslaved_soul; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_reliquary_of_souls"; + pNewScript->GetAI = &GetAI_boss_reliquary_of_souls; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_essence_of_suffering"; + pNewScript->GetAI = &GetAI_boss_essence_of_suffering; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_essence_of_desire"; + pNewScript->GetAI = &GetAI_boss_essence_of_desire; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_essence_of_anger"; + pNewScript->GetAI = &GetAI_boss_essence_of_anger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_enslaved_soul"; + pNewScript->GetAI = &GetAI_npc_enslaved_soul; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/boss_shade_of_akama.cpp b/scripts/outland/black_temple/boss_shade_of_akama.cpp index 25c64d1bc2..d297fbc447 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,688 +16,468 @@ /* 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? -*/ - #include "precompiled.h" #include "black_temple.h" -#define GOSSIP_ITEM "We are ready to fight alongside you, Akama" - -// Spells enum { + // 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_AKAMA = 22990, - 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 (used as point id's) - //PHASE_CHANNEL = 1, - //PHASE_BELOW_PLATFORM = 2, - //PHASE_ON_PLATFORM = 3 + // akama's phases + PHASE_CHANNEL = 1, + PHASE_COMBAT = 2, + PHASE_EPILOGUE = 3, + + MAX_CHANNELERS = 6, }; -const uint32 m_auiRandSpawnEntry[]= +static const uint32 auiRandSpawnEntry[] = { NPC_ASH_ELEMENTAL, NPC_ASH_ROGUE, NPC_ASH_SPIRITBIND }; -const float LOC_RAND_TO_CENTER_X = 482.793182f; -const float LOC_RAND_TO_CENTER_Y = 401.270172f; -const float LOC_RAND_TO_CENTER_Z = 112.783928f; - -const float LOC_PLATFORM_Z = 118.537f; -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}, }; -Location m_afSpawnLoc[]= +static const LOCATION afAkamaWP[] = { - {498.652740f, 461.728119f, LOC_LOW_Z, 0.0f}, - {498.505003f, 339.619324f, LOC_LOW_Z, 0.0f} + {516.885193f, 400.836060f, 112.784f}, + {469.597443f, 402.264404f, 118.537f} }; -Location m_afAkamaWP[]= +static const LOCATION afBrokenSpawnLoc[] = { - //{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} + {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 }; -Location m_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 -}; +/*###### +## npc_akama +######*/ -Location m_afBrokenWP[]= +struct MANGOS_DLL_DECL npc_akamaAI : public ScriptedAI, private DialogueHelper { - {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} -}; - -struct MANGOS_DLL_DECL boss_shade_of_akamaAI : public ScriptedAI -{ - boss_shade_of_akamaAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_akamaAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aOutroDialogue) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_lChannelersGUIDList.clear(); - m_lSorcerersGUIDList.clear(); + m_pInstance = (instance_black_temple*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); } - ScriptedInstance* m_pInstance; - - std::list m_lChannelersGUIDList; - std::list m_lSorcerersGUIDList; - - uint64 m_uiAkamaGUID; + instance_black_temple* m_pInstance; - uint32 m_uiSorcererCount; - uint32 m_uiDeathCount; + 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_uiSorcererCount = 0; - m_uiDeathCount = 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->SetUInt32Value(UNIT_NPC_EMOTESTATE, 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); } - void IncrementDeathCount(uint64 uiGuid = 0) // If guid is set, will remove it from list of sorcerer + void AttackedBy(Unit* pAttacker) override { - debug_log("SD2: Increasing Death Count for Shade of Akama encounter"); - ++m_uiDeathCount; - - 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 " UI64FMTD " from Sorcerers list but list is already empty", uiGuid); - 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 = sizeof(m_afSpawnLoc)/sizeof(Location); - - // max of 6 sorcerers can be summoned - if (!urand(0, 2) && (m_uiDeathCount > 0) && (m_uiSorcererCount < 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, - m_afSpawnLoc[uiRand].m_fX, m_afSpawnLoc[uiRand].m_fY, m_afSpawnLoc[uiRand].m_fZ, m_afSpawnLoc[uiRand].m_fO, - TEMPSUMMON_DEAD_DESPAWN, 0)) - { - pSorcerer->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - pSorcerer->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - pSorcerer->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); + case NPC_SHADE_OF_AKAMA: + m_uiPhase = PHASE_EPILOGUE; - m_lSorcerersGUIDList.push_back(pSorcerer->GetGUID()); + m_creature->GetMotionMaster()->MovePoint(PHASE_EPILOGUE, afAkamaWP[1].x, afAkamaWP[1].y, afAkamaWP[1].z); + break; + case NPC_ASH_SORCERER: + // Decrease the sorcerer counter + m_lSorcerersGUIDList.remove(pVictim->GetObjectGuid()); + break; + case NPC_ASH_CHANNELER: - --m_uiDeathCount; - ++m_uiSorcererCount; - } - } - else - { - int iSize = (sizeof(m_auiRandSpawnEntry) / sizeof(uint32)); + ++m_uiChannelersDead; - for(uint8 i = 0; i < iSize; ++i) - { - if (Creature* pSpawn = m_creature->SummonCreature(m_auiRandSpawnEntry[i], - m_afSpawnLoc[uiRand].m_fX, m_afSpawnLoc[uiRand].m_fY, m_afSpawnLoc[uiRand].m_fZ, m_afSpawnLoc[uiRand].m_fO, - TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000)) + // 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->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - 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 { - if (!m_lSorcerersGUIDList.empty() && m_pInstance) + DoScriptText(SAY_DEATH, m_creature); + m_creature->SetCorpseDelay(30); + + if (m_pInstance) { - for(std::list::iterator itr = m_lSorcerersGUIDList.begin(); itr != m_lSorcerersGUIDList.end(); ++itr) - { - if (Creature* pSorcerer = m_pInstance->instance->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 { - if (!m_lChannelersGUIDList.empty() && m_pInstance) - { - for(std::list::iterator itr = m_lChannelersGUIDList.begin(); itr != m_lChannelersGUIDList.end(); ++itr) - { - if (Creature* pChanneler = m_pInstance->instance->GetCreature(*itr)) - { - if (!pChanneler->isAlive()) - pChanneler->Respawn(); - else - pChanneler->AI()->EnterEvadeMode(); - } - } - } - else - error_log("SD2: boss_shade_of_akamaAI not able to respawn channelers, list is empty."); + // 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)->GetGUID()); - debug_log("SD2: boss_shade_of_akamaAI found channeler " UI64FMTD ". Adding to list", (*itr)->GetGUID()); + 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 = sizeof(m_afSpawnLoc)/sizeof(Location); - - if (Creature* pDefender = m_creature->SummonCreature(NPC_ASH_DEFENDER, - m_afSpawnLoc[uiRand].m_fX, m_afSpawnLoc[uiRand].m_fY, m_afSpawnLoc[uiRand].m_fZ, m_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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_AKAMA_SHADE))) - pDefender->AI()->AttackStart(pAkama); - } - - m_uiDefenderTimer = 15000; - } - else - m_uiDefenderTimer -= uiDiff; + m_uiPhase = PHASE_CHANNEL; - if (m_uiSummonTimer < uiDiff) - { - SummonCreature(); - m_uiSummonTimer = 35000; - } - else - m_uiSummonTimer -= uiDiff; + GuidList m_lChannelersList; + m_pInstance->GetChannelersGuidList(m_lChannelersList); - if (m_uiDeathCount >= 6) - { - if (Creature* pAkama = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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; - - std::list 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].x, afAkamaWP[0].y, afAkamaWP[0].z); + } - 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->instance->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) - { - 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); + float fX, fY, fZ; - pShade->AddThreat(m_creature, 1000000.0f); - pShade->SetInCombatWith(m_creature); - m_creature->SetInCombatWith(pShade); - - pShade->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - pShade->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - - 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].x; + fY = afBrokenSpawnLoc[i].y + (j * 7); + fZ = afBrokenSpawnLoc[i].z; - 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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) + 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) + void UpdateAI(const uint32 uiDiff) override { - DoScriptText(SAY_DEATH, m_creature); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_bIsEventBegun || !m_pInstance) - return; - - if (!m_bCanStartCombat) + switch (m_uiPhase) { - if (Creature* pShade = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) - { - 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, m_afAkamaWP[1].m_fX, m_afAkamaWP[1].m_fY, m_afAkamaWP[1].m_fZ); - ++m_uiWayPointId; - } - - if (!m_bIsShadeDead && m_bCanStartCombat) - { - if (m_uiCheckTimer < uiDiff) - { - if (Creature* pShade = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) + if (m_uiSummonPackTimer < uiDiff) { - if (!pShade->isAlive()) - { - m_bIsShadeDead = true; - m_uiWayPointId = 0; - m_creature->AddSplineFlag(SPLINEFLAG_WALKMODE); - m_creature->GetMotionMaster()->MovePoint(m_uiWayPointId, m_afAkamaWP[0].m_fX, m_afAkamaWP[0].m_fY, m_afAkamaWP[0].m_fZ); - } + DoSummonAshtongue(); + m_uiSummonPackTimer = 35000; } - m_uiCheckTimer = 5000; - } - else - m_uiCheckTimer -= uiDiff; - } - - if (m_uiSummonBrokenTimer && m_uiBrokenSummonIndex < 4) - { - if (m_uiSummonBrokenTimer <= uiDiff) - { - for(uint8 i = 0; i < 4; ++i) - { - float x = m_afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fX + (i*5); - float y = m_afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fY + (1*5); - float z = m_afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fZ; - float o = m_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 = m_afBrokenWP[m_uiBrokenSummonIndex].m_fX + (i*5); - float wy = m_afBrokenWP[m_uiBrokenSummonIndex].m_fY + (i*5); - float wz = m_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->GetGUID()); - } + 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(std::list::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: - if (!m_lBrokenGUIDList.empty()) - { - for(std::list::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: - if (!m_lBrokenGUIDList.empty()) - { - for(std::list::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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) - { - 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(); } }; @@ -706,29 +486,33 @@ bool GossipHello_npc_akama(Player* pPlayer, Creature* pCreature) if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) { if (pInstance->GetData(TYPE_SHADE) != DONE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START_ENCOUNTER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); } - pPlayer->SEND_GOSSIP_MENU(907, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_AKAMA, pCreature->GetObjectGuid()); 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 MANGOS_DLL_DECL 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(); @@ -736,55 +520,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->instance->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) + // 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->instance->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) - m_creature->CastSpell(pShade, SPELL_SHADE_SOUL_CHANNEL, false); - } + DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI +/*###### +## mob_ashtongue_channeler +######*/ + +struct MANGOS_DLL_DECL 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(); @@ -792,71 +594,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->instance->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA))) + // 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->GetGUID()); - 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; } } +}; + +/*###### +## mob_ashtongue_sorcerer +######*/ - void UpdateAI(const uint32 uiDiff) +struct MANGOS_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI +{ + mob_ashtongue_sorcererAI(Creature* pCreature) : ScriptedAI(pCreature) { - if (m_bStartBanishing || !m_pInstance) - return; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } - if (m_uiCheckTimer < uiDiff) - { - Creature* pShade = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SHADEOFAKAMA)); + ScriptedInstance* m_pInstance; - 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 Reset() override {} - DoCastSpellIfCan(pShade, SPELL_SHADE_SOUL_CHANNEL, CAST_TRIGGERED); + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} - m_bStartBanishing = true; - } - } - m_uiCheckTimer = 2000; + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + // Inform Akama that one sorcerer is dead + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) + pAkama->AI()->KilledUnit(m_creature); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // 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) @@ -871,26 +698,27 @@ CreatureAI* GetAI_mob_ashtongue_sorcerer(Creature* pCreature) void AddSC_boss_shade_of_akama() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_shade_of_akama"; - newscript->GetAI = &GetAI_boss_shade_of_akama; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_akama_shade"; - newscript->GetAI = &GetAI_npc_akama_shade; - newscript->pGossipHello = &GossipHello_npc_akama; - newscript->pGossipSelect = &GossipSelect_npc_akama; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_ashtongue_channeler"; - newscript->GetAI = &GetAI_mob_ashtongue_channeler; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_ashtongue_sorcerer"; - newscript->GetAI = &GetAI_mob_ashtongue_sorcerer; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_akama_shade"; + pNewScript->GetAI = &GetAI_npc_akama_shade; + pNewScript->pGossipHello = &GossipHello_npc_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; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_ashtongue_sorcerer"; + pNewScript->GetAI = &GetAI_mob_ashtongue_sorcerer; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/boss_supremus.cpp b/scripts/outland/black_temple/boss_supremus.cpp index 5f05a156d4..2de77e7977 100644 --- a/scripts/outland/black_temple/boss_supremus.cpp +++ b/scripts/outland/black_temple/boss_supremus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,136 +16,69 @@ /* ScriptData SDName: Boss_Supremus -SD%Complete: 95 -SDComment: Need to implement molten punch +SD%Complete: 90 +SDComment: Unknown if other speed-changes happen, remove AI for trigger mobs in next step SDCategory: Black Temple EndScriptData */ #include "precompiled.h" #include "black_temple.h" -#define EMOTE_NEW_TARGET -1564010 -#define EMOTE_PUNCH_GROUND -1564011 //DoScriptText(EMOTE_PUNCH_GROUND, m_creature); -#define EMOTE_GROUND_CRACK -1564012 - -//Spells -#define SPELL_HURTFUL_STRIKE 41926 -#define SPELL_DEMON_FIRE 40029 -#define SPELL_MOLTEN_FLAME 40253 -#define SPELL_VOLCANIC_ERUPTION 40276 -#define SPELL_VOLCANIC_FIREBALL 40118 -#define SPELL_VOLCANIC_GEYSER 42055 -#define SPELL_MOLTEN_PUNCH 40126 -#define SPELL_BERSERK 45078 - -#define CREATURE_VOLCANO 23085 -#define CREATURE_STALKER 23095 - -struct MANGOS_DLL_DECL molten_flameAI : public ScriptedAI +enum { - molten_flameAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - uint64 SupremusGUID; - bool TargetLocked; - uint32 CheckTimer; - - void Reset() - { - SupremusGUID = 0; - TargetLocked = false; - - CheckTimer = 1000; - } - - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit *who) - { - if (TargetLocked) - return; - - // stop it from aggroing players who move in LOS if we have a target. - if (who && (who != m_creature) && (m_creature->IsWithinDistInMap(who, 10))) - StalkTarget(who); - } + EMOTE_NEW_TARGET = -1564010, + EMOTE_PUNCH_GROUND = -1564011, + EMOTE_GROUND_CRACK = -1564012, + + // Spells + SPELL_HATEFUL_STRIKE = 41926, + SPELL_CHARGE = 41581, + SPELL_MOLTEN_FLAME = 40980, + SPELL_VOLCANIC_ERUPTION_BOSS = 40276, + SPELL_VOLCANIC_ERUPTION_VOLCANO = 40117, + SPELL_MOLTEN_PUNCH = 40126, + SPELL_BERSERK = 45078, + SPELL_SLOW_SELF = 41922, + + NPC_VOLCANO = 23085, + NPC_STALKER = 23095, +}; - void SetSupremusGUID(uint64 GUID) { SupremusGUID = GUID; } +/* Non existed spells that were used in 3.2 + * Stalker: 40257 41930 + * Supremus: 33420 41582 41925 41951 + */ - void StalkTarget(Unit* target) - { - if (!target) - return; +const float RANGE_MOLTEN_PUNCH = 40.0; - m_creature->AddThreat(target, 50000000.0f); - m_creature->GetMotionMaster()->MoveChase(target); - DoCastSpellIfCan(m_creature, SPELL_DEMON_FIRE, CAST_TRIGGERED); - // DoCastSpellIfCan(m_creature, SPELL_MOLTEN_FLAME, CAST_TRIGGERED); // This spell damages self, so disabled for now - TargetLocked = true; - } +/* These floats are related to the speed-hack near end of script; + * Statet at wowwiki: "If the gaze target is further away than 40 yards, he dashes at about five times the normal run speed until the range is about 20 yards." + * TODO But this is currently not confirmed otherwise to be actually happening + * const float RANGE_MIN_DASHING = 20.0; + * const float SPEED_DASHING = 5.0; + * const float SPEED_CHASE = 0.9f; + */ - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget()) - return; +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct MANGOS_DLL_DECL molten_flameAI : public Scripted_NoMovementAI +{ + molten_flameAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - if (m_creature->getVictim() && m_creature->isAlive()) - { - if (CheckTimer < diff) - { - if (SupremusGUID) - { - Unit* Supremus = m_creature->GetMap()->GetCreature(SupremusGUID); - if (Supremus && (!Supremus->isAlive())) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), 0, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - CheckTimer = 2000; - }else CheckTimer -= diff; - } - } + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} }; -struct MANGOS_DLL_DECL npc_volcanoAI : public ScriptedAI +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct MANGOS_DLL_DECL npc_volcanoAI : public Scripted_NoMovementAI { - npc_volcanoAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_volcanoAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - uint32 CheckTimer; - uint64 SupremusGUID; - uint32 FireballTimer; - uint32 GeyserTimer; - - void Reset() - { - CheckTimer = 1000; - SupremusGUID = 0; - FireballTimer = 500; - GeyserTimer = 0; - } - - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void SetSupremusGUID(uint64 guid) { SupremusGUID = guid; } - - void UpdateAI(const uint32 diff) - { - if (CheckTimer < diff) - { - if (SupremusGUID) - { - Unit* Supremus = m_creature->GetMap()->GetCreature(SupremusGUID); - if (Supremus && (!Supremus->isAlive())) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), 0, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - CheckTimer = 2000; - }else CheckTimer -= diff; - - if (GeyserTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_VOLCANIC_GEYSER); - GeyserTimer = 18000; - }else GeyserTimer -= diff; - } + 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 @@ -158,204 +91,209 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 SummonFlameTimer; - uint32 SwitchTargetTimer; - uint32 PhaseSwitchTimer; - uint32 SummonVolcanoTimer; - uint32 HurtfulStrikeTimer; - uint32 BerserkTimer; + uint32 m_uiSummonFlameTimer; + uint32 m_uiSwitchTargetTimer; + uint32 m_uiPhaseSwitchTimer; + uint32 m_uiSummonVolcanoTimer; + uint32 m_uiHatefulStrikeTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiMoltenPunchTimer; - bool Phase1; + bool m_bTankPhase; - void Reset() + GuidList m_lSummonedGUIDs; + + void Reset() override { - HurtfulStrikeTimer = 5000; - SummonFlameTimer = 20000; - SwitchTargetTimer = 90000; - PhaseSwitchTimer = 60000; - SummonVolcanoTimer = 5000; - BerserkTimer = 900000; // 15 minute enrage - - Phase1 = true; + m_uiHatefulStrikeTimer = 5000; + m_uiSummonFlameTimer = 20000; + m_uiPhaseSwitchTimer = 60000; + m_uiMoltenPunchTimer = 8000; + 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 { - m_creature->SetInCombatWithZone(); - if (m_pInstance) m_pInstance->SetData(TYPE_SUPREMUS, IN_PROGRESS); } - void JustDied(Unit *killer) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SUPREMUS, DONE); - } - - float CalculateRandomCoord(float initial) - { - float coord = 0; - switch(urand(0, 1)) + for (GuidList::const_iterator itr = m_lSummonedGUIDs.begin(); itr != m_lSummonedGUIDs.end(); ++itr) { - case 0: coord = initial + 20 + rand()%20; break; - case 1: coord = initial - 20 - rand()%20; break; + if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) + pSummoned->ForcedDespawn(); } - - return coord; } - Creature* SummonCreature(uint32 entry, Unit* target) + void JustSummoned(Creature* pSummoned) override { - if (target && entry) + if (pSummoned->GetEntry() == NPC_STALKER) { - Creature* Summon = m_creature->SummonCreature(entry, CalculateRandomCoord(target->GetPositionX()), CalculateRandomCoord(target->GetPositionY()), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 20000); - if (Summon) + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); + + if (pTarget) { - Summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Summon->setFaction(m_creature->getFaction()); - return Summon; + pSummoned->GetMotionMaster()->Clear(); + pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0.0f, 0.0f); + pSummoned->CastSpell(pSummoned, SPELL_MOLTEN_FLAME, false, NULL, NULL, m_creature->GetObjectGuid()); } } - return NULL; + + else if (pSummoned->GetEntry() == NPC_VOLCANO) + pSummoned->CastSpell(pSummoned, SPELL_VOLCANIC_ERUPTION_VOLCANO, false, NULL, NULL, m_creature->GetObjectGuid()); } - Unit* CalculateHurtfulStrikeTarget() + Unit* GetHatefulStrikeTarget() { - uint32 health = 0; - Unit* target = NULL; + uint32 uiHealth = 0; + Unit* pTarget = NULL; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + for (ThreatList::const_iterator iter = tList.begin(); iter != tList.end(); ++iter) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); + Unit* pUnit = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid()); - if (pUnit && m_creature->IsWithinDistInMap(pUnit, ATTACK_DISTANCE)) + if (pUnit && m_creature->CanReachWithMeleeAttack(pUnit)) { - if (pUnit->GetHealth() > health) + if (pUnit->GetHealth() > uiHealth) { - health = pUnit->GetHealth(); - target = pUnit; + uiHealth = pUnit->GetHealth(); + pTarget = pUnit; } } } - return target; + return pTarget; + } + + void KilledUnit(Unit* pKilled) override + { + // 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!m_creature->HasAura(SPELL_BERSERK, EFFECT_INDEX_0)) + if (m_uiBerserkTimer) { - if (BerserkTimer < diff) - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - else BerserkTimer -= diff; + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; } - if (SummonFlameTimer < diff) + if (m_uiSummonFlameTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - - if (!target) // someone is trying to solo, set target as current victim. - target = m_creature->getVictim(); + // This currently is entirely screwed, because the npc is summoned somewhere far away as of big bounding box of supremus + if (DoCastSpellIfCan(m_creature, SPELL_MOLTEN_PUNCH) == CAST_OK) + m_uiSummonFlameTimer = 20000; + } + else + m_uiSummonFlameTimer -= uiDiff; - if (target) + if (m_uiPhaseSwitchTimer < uiDiff) + { + if (!m_bTankPhase) { - if (Creature* pMoltenFlame = SummonCreature(CREATURE_STALKER, target)) - { - // Invisible model - pMoltenFlame->SetDisplayId(11686); - - if (molten_flameAI* pMoltenAI = dynamic_cast(pMoltenFlame->AI())) - { - pMoltenAI->SetSupremusGUID(m_creature->GetGUID()); - pMoltenAI->StalkTarget(target); - } + m_bTankPhase = true; + m_creature->RemoveAurasDueToSpell(SPELL_SLOW_SELF); + m_creature->FixateTarget(NULL); + } + else + { + m_bTankPhase = false; + m_uiSwitchTargetTimer = 0; + m_uiSummonVolcanoTimer = 2000; - SummonFlameTimer = 20000; - } + DoCastSpellIfCan(m_creature, SPELL_SLOW_SELF, CAST_INTERRUPT_PREVIOUS); } - }else SummonFlameTimer -= diff; - if (Phase1) + m_uiPhaseSwitchTimer = MINUTE * IN_MILLISECONDS; + } + else + m_uiPhaseSwitchTimer -= uiDiff; + + if (m_bTankPhase) { - if (HurtfulStrikeTimer < diff) + if (m_uiHatefulStrikeTimer < uiDiff) { - Unit* target = CalculateHurtfulStrikeTarget(); - if (target) + if (Unit* pTarget = GetHatefulStrikeTarget()) { - DoCastSpellIfCan(target, SPELL_HURTFUL_STRIKE); - HurtfulStrikeTimer = 5000; + if (DoCastSpellIfCan(pTarget, SPELL_HATEFUL_STRIKE) == CAST_OK) + m_uiHatefulStrikeTimer = 5000; } - }else HurtfulStrikeTimer -= diff; + } + else + m_uiHatefulStrikeTimer -= uiDiff; } - - if (!Phase1) + else // !m_bTankPhase { - if (SwitchTargetTimer < diff) + if (m_uiSwitchTargetTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoResetThreat(); - m_creature->AddThreat(target, 5000000.0f); + m_creature->FixateTarget(pTarget); DoScriptText(EMOTE_NEW_TARGET, m_creature); - SwitchTargetTimer = 10000; + m_uiSwitchTargetTimer = 10000; } - }else SwitchTargetTimer -= diff; + } + else + m_uiSwitchTargetTimer -= uiDiff; - if (SummonVolcanoTimer < diff) + if (m_uiSummonVolcanoTimer < uiDiff) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (!target) - target = m_creature->getVictim(); - - if (target) + if (DoCastSpellIfCan(pTarget ? pTarget : m_creature->getVictim(), SPELL_VOLCANIC_ERUPTION_BOSS) == CAST_OK) { - if (Creature* pVolcano = SummonCreature(CREATURE_VOLCANO, target)) - { - DoCastSpellIfCan(target, SPELL_VOLCANIC_ERUPTION); - - if (npc_volcanoAI* pVolcanoAI = dynamic_cast(pVolcano->AI())) - pVolcanoAI->SetSupremusGUID(m_creature->GetGUID()); - } - DoScriptText(EMOTE_GROUND_CRACK, m_creature); - SummonVolcanoTimer = 10000; + m_uiSummonVolcanoTimer = 10000; } - }else SummonVolcanoTimer -= diff; - } - - if (PhaseSwitchTimer < diff) - { - if (!Phase1) - { - Phase1 = true; - DoResetThreat(); - PhaseSwitchTimer = 60000; - m_creature->SetSpeedRate(MOVE_RUN, 1.0f); } else + m_uiSummonVolcanoTimer -= uiDiff; + + if (m_uiMoltenPunchTimer < uiDiff) { - Phase1 = false; - DoResetThreat(); - SwitchTargetTimer = 10000; - SummonVolcanoTimer = 2000; - PhaseSwitchTimer = 60000; - m_creature->SetSpeedRate(MOVE_RUN, 0.9f); + if (m_creature->GetCombatDistance(m_creature->getVictim()) < RANGE_MOLTEN_PUNCH) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHARGE); + DoScriptText(EMOTE_PUNCH_GROUND, m_creature); + } + m_uiMoltenPunchTimer = 8000; // might be better with small timer and some sort of cast-chance } - }else PhaseSwitchTimer -= diff; + else + m_uiMoltenPunchTimer -= uiDiff; + + /* Not understood how this really must work + * if (m_creature->GetSpeedRate(MOVE_RUN) > SPEED_CHASE && m_creature->GetCombatDistance(m_creature->getVictim()) < RANGE_MIN_DASHING) + * m_creature->SetSpeedRate(MOVE_RUN, SPEED_CHASE); + * else if (m_creature->GetCombatDistance(m_creature->getVictim()) > RANGE_MOLTEN_PUNCH) + * m_creature->SetSpeedRate(MOVE_RUN, SPEED_DASHING); + */ + } DoMeleeAttackIfReady(); } @@ -378,19 +316,20 @@ CreatureAI* GetAI_npc_volcano(Creature* pCreature) void AddSC_boss_supremus() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_supremus"; - newscript->GetAI = &GetAI_boss_supremus; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "molten_flame"; - newscript->GetAI = &GetAI_molten_flame; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_volcano"; - newscript->GetAI = &GetAI_npc_volcano; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_supremus"; + pNewScript->GetAI = &GetAI_boss_supremus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "molten_flame"; + pNewScript->GetAI = &GetAI_molten_flame; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_volcano"; + pNewScript->GetAI = &GetAI_npc_volcano; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/boss_teron_gorefiend.cpp b/scripts/outland/black_temple/boss_teron_gorefiend.cpp index 6a9043a78d..caa03e7c81 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,7 +26,7 @@ EndScriptData */ enum { - //Speech'n'sound + // Speech'n'sound SAY_INTRO = -1564037, SAY_AGGRO = -1564038, SAY_SLAY1 = -1564039, @@ -38,162 +38,27 @@ 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; - uint64 m_uiTeronGUID; - - void Reset() - { - m_uiCheckTeronTimer = 5000; - m_uiShadowBoltTimer = 12000; - m_uiTeronGUID = 0; - } - - void AttackStart(Unit* pWho) { } - void MoveInLineOfSight(Unit* pWho) { } - - void UpdateAI(const uint32 uiDiff) - { - if (m_uiCheckTeronTimer < uiDiff) - { - if (m_uiTeronGUID) - { - m_creature->SetInCombatWithZone(); - - Creature* pTeron = m_creature->GetMap()->GetCreature(m_uiTeronGUID); - 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(uint64 uiGUID){ m_uiTeronGUID = uiGUID; } -}; - -struct MANGOS_DLL_DECL mob_shadowy_constructAI : public ScriptedAI -{ - mob_shadowy_constructAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - uint64 m_uiGhostGUID; - uint64 m_uiTeronGUID; - - uint32 m_uiCheckPlayerTimer; - uint32 m_uiCheckTeronTimer; - - void Reset() - { - m_uiGhostGUID = 0; - m_uiTeronGUID = 0; - - m_uiCheckPlayerTimer = 2000; - m_uiCheckTeronTimer = 5000; - } - - void MoveInLineOfSight(Unit* pWho) - { - if (!pWho || !pWho->isAlive() || pWho->GetGUID() == m_uiGhostGUID) - 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->GetGUID() != m_uiGhostGUID) - 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_uiTeronGUID); - 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 @@ -201,6 +66,7 @@ struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI boss_teron_gorefiendAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIntroDone = false; Reset(); } @@ -208,211 +74,81 @@ 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; - - uint64 m_uiAggroTargetGUID; - uint64 m_uiGhostGUID; // 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_uiAggroTargetGUID = 0; - 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->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); - m_uiAggroTargetGUID = pWho->GetGUID(); - 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); 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_uiGhostGUID) - pGhost = m_creature->GetMap()->GetPlayer(m_uiGhostGUID); - - 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_uiGhostGUID = m_uiGhostGUID; - - 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->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - m_bIntro = false; - if (m_uiAggroTargetGUID) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiAggroTargetGUID)) - 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->GetGUID()); - - SetThreatList(pDoomBlossom); - } + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SPELL1 : SAY_SPELL2, m_creature); m_uiSummonDoomBlossomTimer = 35000; } @@ -422,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_uiGhostGUID = pTarget->GetGUID(); - 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,19 +218,10 @@ CreatureAI* GetAI_boss_teron_gorefiend(Creature* pCreature) void AddSC_boss_teron_gorefiend() { - Script *newscript; - newscript = new Script; - newscript->Name = "mob_doom_blossom"; - newscript->GetAI = &GetAI_mob_doom_blossom; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_shadowy_construct"; - newscript->GetAI = &GetAI_mob_shadowy_construct; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_teron_gorefiend"; - newscript->GetAI = &GetAI_boss_teron_gorefiend; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_teron_gorefiend"; + pNewScript->GetAI = &GetAI_boss_teron_gorefiend; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/boss_warlord_najentus.cpp b/scripts/outland/black_temple/boss_warlord_najentus.cpp index e7dbf6229c..c986b411f4 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Warlord_Najentus SD%Complete: 90 -SDComment: Does the GO need script? Uncomment code to test. +SDComment: Core spell support for Needle Spine (spells 39992, 39835) missing, no change from SD2 needed SDCategory: Black Temple EndScriptData */ @@ -33,15 +33,14 @@ 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, SPELL_CRASHINGWAVE = 40100, - SPELL_NEEDLE_SPINE = 39835, - SPELL_NEEDLE_AOE = 39968, + SPELL_NEEDLE_SPINE = 39992, SPELL_TIDAL_BURST = 39878, - SPELL_TIDAL_SHIELD = 39872, // Not going to use this since Hurl Spine doesn't dispel it. + SPELL_TIDAL_SHIELD = 39872, SPELL_IMPALING_SPINE = 39837, SPELL_CREATE_NAJENTUS_SPINE = 39956, SPELL_HURL_SPINE = 39948, @@ -66,29 +65,31 @@ 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; + + SetCombatMovement(true); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NAJENTUS, NOT_STARTED); } - 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_NAJENTUS, DONE); @@ -96,104 +97,106 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - if (m_bIsShielded) + if (m_bIsShielded && pSpell->Id == SPELL_HURL_SPINE) { - if (spell->Id == SPELL_HURL_SPINE) - { - if (m_creature->HasAura(SPELL_TIDAL_SHIELD, EFFECT_INDEX_0)) - m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); + if (m_creature->HasAura(SPELL_TIDAL_SHIELD)) + m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TIDAL_BURST); - m_bIsShielded = false; - } + DoCastSpellIfCan(m_creature, SPELL_TIDAL_BURST); + m_bIsShielded = false; + + SetCombatMovement(true); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NAJENTUS, IN_PROGRESS); DoScriptText(SAY_AGGRO, m_creature); - - m_creature->SetInCombatWithZone(); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiEnrageTimer < diff) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(SAY_ENRAGE2, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - m_uiEnrageTimer = MINUTE*8*IN_MILLISECONDS; - }else m_uiEnrageTimer -= diff; - - if (m_bIsShielded) + // If shield expired after 45s, attack again + if (m_bIsShielded && m_uiTidalShieldTimer < 16000 && !m_creature->HasAura(SPELL_TIDAL_SHIELD)) { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); + m_bIsShielded = false; - return; // Don't cast or do anything while Shielded + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } - // Needle - if (m_uiNeedleSpineTimer < diff) + if (m_uiEnrageTimer < uiDiff) { - for(uint8 i = 0; i < 3; ++i) + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - - if (!target) - target = m_creature->getVictim(); - - DoCastSpellIfCan(target, SPELL_NEEDLE_SPINE); - target->CastSpell(target, SPELL_NEEDLE_AOE, false); + m_uiEnrageTimer = MINUTE * 8 * IN_MILLISECONDS; + DoScriptText(SAY_ENRAGE2, m_creature); } + } + else + m_uiEnrageTimer -= uiDiff; - m_uiNeedleSpineTimer = 3000; - }else m_uiNeedleSpineTimer -= diff; - - if (m_uiSpecialYellTimer < diff) + if (m_uiSpecialYellTimer < uiDiff) { DoScriptText(urand(0, 1) ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); m_uiSpecialYellTimer = urand(25000, 100000); - }else m_uiSpecialYellTimer -= diff; + } + else + m_uiSpecialYellTimer -= uiDiff; - if (m_uiImpalingSpineTimer < diff) + if (m_uiImpalingSpineTimer < uiDiff) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_IMPALING_SPINE, SELECT_FLAG_PLAYER); - if (!target) - target = m_creature->getVictim(); + if (!pTarget) + pTarget = m_creature->getVictim(); - if (target && (target->GetTypeId() == TYPEID_PLAYER)) + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) { - DoCastSpellIfCan(target, SPELL_IMPALING_SPINE); + DoCastSpellIfCan(pTarget, SPELL_IMPALING_SPINE); m_uiImpalingSpineTimer = 20000; DoScriptText(urand(0, 1) ? SAY_NEEDLE1 : SAY_NEEDLE2, m_creature); } - }else m_uiImpalingSpineTimer -= diff; + } + else + m_uiImpalingSpineTimer -= uiDiff; - if (m_uiTidalShieldTimer < diff) + if (m_uiTidalShieldTimer < uiDiff) { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature, SPELL_TIDAL_SHIELD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TIDAL_SHIELD, CAST_INTERRUPT_PREVIOUS | CAST_TRIGGERED); m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); + SetCombatMovement(false); m_bIsShielded = true; m_uiTidalShieldTimer = 60000; - }else m_uiTidalShieldTimer -= diff; + + // Skip needle splines for 10s + m_uiNeedleSpineTimer += 10000; + } + else + m_uiTidalShieldTimer -= uiDiff; + + // Needle + if (m_uiNeedleSpineTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NEEDLE_SPINE) == CAST_OK) + m_uiNeedleSpineTimer = 3000; + } + else + m_uiNeedleSpineTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -206,9 +209,10 @@ CreatureAI* GetAI_boss_najentus(Creature* pCreature) void AddSC_boss_najentus() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_najentus"; - newscript->GetAI = &GetAI_boss_najentus; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_najentus"; + pNewScript->GetAI = &GetAI_boss_najentus; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/illidari_council.cpp b/scripts/outland/black_temple/illidari_council.cpp index 0aa9fd5714..0e0eed216e 100644 --- a/scripts/outland/black_temple/illidari_council.cpp +++ b/scripts/outland/black_temple/illidari_council.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,782 +16,732 @@ /* 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 */ #include "precompiled.h" #include "black_temple.h" -//Speech'n'Sounds -#define SAY_GATH_SLAY -1564085 -#define SAY_GATH_SLAY_COMNT -1564089 -#define SAY_GATH_DEATH -1564093 -#define SAY_GATH_SPECIAL1 -1564077 -#define SAY_GATH_SPECIAL2 -1564081 - -#define SAY_VERA_SLAY -1564086 -#define SAY_VERA_COMNT -1564089 -#define SAY_VERA_DEATH -1564094 -#define SAY_VERA_SPECIAL1 -1564078 -#define SAY_VERA_SPECIAL2 -1564082 - -#define SAY_MALA_SLAY -1564087 -#define SAY_MALA_COMNT -1564090 -#define SAY_MALA_DEATH -1564095 -#define SAY_MALA_SPECIAL1 -1564079 -#define SAY_MALA_SPECIAL2 -1564083 - -#define SAY_ZERE_SLAY -1564088 -#define SAY_ZERE_COMNT -1564091 -#define SAY_ZERE_DEATH -1564096 -#define SAY_ZERE_SPECIAL1 -1564080 -#define SAY_ZERE_SPECIAL2 -1564084 - -#define ERROR_INST_DATA "SD2 ERROR: Instance Data for Black Temple not set properly; Illidari Council event will not function properly." - -struct CouncilYells +enum { - int32 entry; - uint32 timer; + // 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, + SAY_ZERE_BERSERK = -1564076, + + // High Nethermancer Zerevor's spells + SPELL_FLAMESTRIKE = 41481, + SPELL_BLIZZARD = 41482, + SPELL_ARCANE_BOLT = 41483, + SPELL_ARCANE_EXPLOSION = 41524, + SPELL_DAMPEN_MAGIC = 41478, + + // Lady Malande's spells + SPELL_EMPOWERED_SMITE = 41471, + SPELL_CIRCLE_OF_HEALING = 41455, + SPELL_REFLECTIVE_SHIELD = 41475, + SPELL_DIVINE_WRATH = 41472, + + // Gathios the Shatterer's spells + SPELL_BLESS_PROTECTION = 41450, + SPELL_BLESS_SPELLWARD = 41451, + SPELL_CONSECRATION = 41541, + SPELL_HAMMER_OF_JUSTICE = 41468, + SPELL_SEAL_OF_COMMAND = 41469, + 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_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 CouncilYells CouncilAggro[]= +static const DialogueEntry aCouncilDialogue[] = { - {-1564069, 5000}, // Gathios - {-1564070, 5500}, // Veras - {-1564071, 5000}, // Malande - {-1564072, 0}, // Zerevor + {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}, }; -// Need to get proper timers for this later -static CouncilYells CouncilEnrage[]= -{ - {-1564073, 2000}, // Gathios - {-1564074, 6000}, // Veras - {-1564075, 5000}, // Malande - {-1564076, 0}, // Zerevor -}; +static const uint32 aCouncilMember[] = {NPC_GATHIOS, NPC_VERAS, NPC_LADY_MALANDE, NPC_ZEREVOR}; -// High Nethermancer Zerevor's spells -#define SPELL_FLAMESTRIKE 41481 -#define SPELL_BLIZZARD 41482 -#define SPELL_ARCANE_BOLT 41483 -#define SPELL_ARCANE_EXPLOSION 41524 -#define SPELL_DAMPEN_MAGIC 41478 - -// Lady Malande's spells -#define SPELL_EMPOWERED_SMITE 41471 -#define SPELL_CIRCLE_OF_HEALING 41455 -#define SPELL_REFLECTIVE_SHIELD 41475 -#define SPELL_DIVINE_WRATH 41472 -#define SPELL_HEAL_VISUAL 24171 - -// Gathios the Shatterer's spells -#define SPELL_BLESS_PROTECTION 41450 -#define SPELL_BLESS_SPELLWARD 41451 -#define SPELL_CONSECRATION 41541 -#define SPELL_HAMMER_OF_JUSTICE 41468 -#define SPELL_SEAL_OF_COMMAND 41469 -#define SPELL_SEAL_OF_BLOOD 41459 -#define SPELL_CHROMATIC_AURA 41453 -#define SPELL_DEVOTION_AURA 41452 - -// Veras Darkshadow's spells -#define SPELL_DEADLY_POISON 41485 -#define SPELL_ENVENOM 41487 -#define SPELL_VANISH 41479 - -#define SPELL_BERSERK 45078 +/*###### +## mob_blood_elf_council_voice_trigger +######*/ struct MANGOS_DLL_DECL 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) { - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; + m_pInstance = (ScriptedInstance*)(m_creature->GetInstanceData()); + m_councilDialogue.InitializeDialogueHelper(m_pInstance); Reset(); } - uint64 Council[4]; - - uint32 EnrageTimer; - uint32 AggroYellTimer; - - uint8 YellCounter; // Serves as the counter for both the aggro and enrage yells + ScriptedInstance* m_pInstance; + DialogueHelper m_councilDialogue; - bool EventStarted; + uint32 m_uiEnrageTimer; + uint32 m_uiAggroYellTimer; - void Reset() + void Reset() override { - EnrageTimer = 900000; // 15 minutes - AggroYellTimer = 500; - YellCounter = 0; - - EventStarted = false; + m_uiEnrageTimer = 0; + m_uiAggroYellTimer = 0; } - // finds and stores the GUIDs for each Council member using instance data system. - void LoadCouncilGUIDs() + void StartVoiceEvent() { - if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) - { - Council[0] = pInstance->GetData64(DATA_GATHIOSTHESHATTERER); - Council[1] = pInstance->GetData64(DATA_VERASDARKSHADOW); - Council[2] = pInstance->GetData64(DATA_LADYMALANDE); - Council[3] = pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); - }else error_log(ERROR_INST_DATA); + m_uiAggroYellTimer = 500; + m_uiEnrageTimer = 15 * MINUTE * IN_MILLISECONDS; } - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!EventStarted) - return; - - if (YellCounter > 3) - return; + m_councilDialogue.DialogueUpdate(uiDiff); - if (AggroYellTimer) + if (m_uiAggroYellTimer) { - if (AggroYellTimer <= diff) + if (m_uiAggroYellTimer <= uiDiff) { - if (Creature* pMember = m_creature->GetMap()->GetCreature(Council[YellCounter])) - { - DoScriptText(CouncilAggro[YellCounter].entry, pMember); - AggroYellTimer = CouncilAggro[YellCounter].timer; - } - ++YellCounter; - - if (YellCounter > 3) - YellCounter = 0; // Reuse for Enrage Yells - }else AggroYellTimer -= diff; + // Start yells + m_councilDialogue.StartNextDialogueText(SAY_GATH_AGGRO); + m_uiAggroYellTimer = 0; + } + else + m_uiAggroYellTimer -= uiDiff; } - if (EnrageTimer) + if (m_uiEnrageTimer) { - if (EnrageTimer <= diff) + if (m_uiEnrageTimer <= uiDiff) { - if (Creature* pMember = m_creature->GetMap()->GetCreature(Council[YellCounter])) + // Cast berserk on all members + for (uint8 i = 0; i < 4; ++i) { - pMember->CastSpell(pMember, SPELL_BERSERK, true); - DoScriptText(CouncilEnrage[YellCounter].entry, pMember); - EnrageTimer = CouncilEnrage[YellCounter].timer; + if (Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) + pMember->CastSpell(pMember, SPELL_BERSERK, true); } - ++YellCounter; - }else EnrageTimer -= diff; + // Start yells + m_councilDialogue.StartNextDialogueText(SAY_GATH_BERSERK); + m_uiEnrageTimer = 0; + } + else + m_uiEnrageTimer -= uiDiff; } } }; +/*###### +## mob_illidari_council +######*/ + struct MANGOS_DLL_DECL mob_illidari_councilAI : public ScriptedAI { mob_illidari_councilAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; - Reset(); } ScriptedInstance* m_pInstance; - uint64 Council[4]; - - uint32 CheckTimer; - uint32 EndEventTimer; + uint32 m_uiEquivalencyTimer; - uint8 DeathCount; + bool m_bEventBegun; + bool m_bEventEnd; - bool EventBegun; - - void Reset() + void Reset() override { - CheckTimer = 2000; - EndEventTimer = 0; - - DeathCount = 0; + m_bEventBegun = false; + m_bEventEnd = false; - for(uint8 i = 0; i < 4; ++i) - { - if (Creature* pMember = m_creature->GetMap()->GetCreature(Council[i])) - { - if (!pMember->isAlive()) - { - pMember->RemoveCorpse(); - pMember->Respawn(); - } - pMember->AI()->EnterEvadeMode(); - } - } + m_uiEquivalencyTimer = urand(2000, 3000); + } - EventBegun = false; + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetDisplayId(11686); + void JustDied(Unit* /*pKiller*/) override + { + DoEndEvent(); if (m_pInstance) - { - //if already done, not do anything - if (m_pInstance->GetData(TYPE_COUNCIL) == DONE) - return; - - if (Creature* VoiceTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE))) - VoiceTrigger->AI()->EnterEvadeMode(); - - m_pInstance->SetData(TYPE_COUNCIL, NOT_STARTED); - } + m_pInstance->SetData(TYPE_COUNCIL, DONE); } - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - - void StartEvent(Unit *target) + void DoStartEvent() { - if (!m_pInstance) + if (!m_pInstance || m_bEventBegun) return; - if (target && target->isAlive() && !EventBegun) - { - Council[0] = m_pInstance->GetData64(DATA_GATHIOSTHESHATTERER); - Council[1] = m_pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); - Council[2] = m_pInstance->GetData64(DATA_LADYMALANDE); - Council[3] = m_pInstance->GetData64(DATA_VERASDARKSHADOW); - - // Start the event for the Voice Trigger - if (Creature* pVoiceTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE))) - { - if (mob_blood_elf_council_voice_triggerAI* pVoiceAI = dynamic_cast(pVoiceTrigger->AI())) - { - pVoiceAI->LoadCouncilGUIDs(); - pVoiceAI->EventStarted = true; - } - } - - for(uint8 i = 0; i < 4; ++i) - { - if (Council[i]) - { - Creature* pMember = m_creature->GetMap()->GetCreature(Council[i]); - if (pMember && pMember->isAlive()) - pMember->AI()->AttackStart(target); - } - } - - m_pInstance->SetData(TYPE_COUNCIL, IN_PROGRESS); + // Prevent further handling for next council uiMember aggroing + m_bEventBegun = true; - EventBegun = 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(); } + + DoCastSpellIfCan(m_creature, SPELL_EMPYREAL_BALANCE); } - void UpdateAI(const uint32 diff) + void DoEndEvent() { - if (!EventBegun) + if (!m_pInstance || m_bEventEnd) return; - if (EndEventTimer) + // Prevent further handling for next council uiMember death + m_bEventEnd = true; + + // Kill all the other council members + for (uint8 i = 0; i < 4; ++i) { - if (EndEventTimer <= diff) - { - if (DeathCount > 3) - { - if (m_pInstance) - { - if (Creature* VoiceTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_BLOOD_ELF_COUNCIL_VOICE))) - VoiceTrigger->DealDamage(VoiceTrigger, VoiceTrigger->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - m_pInstance->SetData(TYPE_COUNCIL, DONE); - } - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - return; - } + 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_creature->GetMap()->GetCreature(Council[DeathCount]); - 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); - ++DeathCount; - EndEventTimer = 1500; - }else EndEventTimer -= diff; - } + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } - if (CheckTimer) + void UpdateAI(const uint32 uiDiff) override + { + // Make the council members health equal every 2-3 secs + if (m_bEventBegun && !m_bEventEnd) { - if (CheckTimer <= diff) + if (m_uiEquivalencyTimer < uiDiff) { - uint8 EvadeCheck = 0; - for(uint8 i = 0; i < 4; ++i) - { - if (Council[i]) - { - if (Creature* Member = m_creature->GetMap()->GetCreature(Council[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 member dies, kill the rest, set instance data, and kill self. - { - EndEventTimer = 1000; - CheckTimer = 0; - return; - } - } - } - } - - if (EvadeCheck > 3) - Reset(); - - CheckTimer = 2000; - }else CheckTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_EMPYREAL_EQUIVALENCY) == CAST_OK) + m_uiEquivalencyTimer = urand(2000, 3000); + } + else + m_uiEquivalencyTimer -= uiDiff; } } }; +/*###### +## boss_illidari_council +######*/ + struct MANGOS_DLL_DECL boss_illidari_councilAI : public ScriptedAI { boss_illidari_councilAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - - for(uint8 i = 0; i < 4; ++i) - Council[i] = 0; - - LoadedGUIDs = false; } ScriptedInstance* m_pInstance; - uint64 Council[4]; - - bool LoadedGUIDs; - - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) { - if (Creature* pController = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_ILLIDARICOUNCIL))) + // 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(); } - } - else - { - error_log(ERROR_INST_DATA); - EnterEvadeMode(); - } - - m_creature->SetInCombatWithZone(); - // Load GUIDs on first aggro because the creature guids are only set as the creatures are created in world- - // this means that for each creature, it will attempt to LoadGUIDs even though some of the other creatures are - // not in world, and thus have no GUID set in the instance data system. Putting it in aggro ensures that all the creatures - // have been loaded and have their GUIDs set in the instance data system. - if (!LoadedGUIDs) - LoadGUIDs(); + m_pInstance->SetData(TYPE_COUNCIL, IN_PROGRESS); + } } - void DamageTaken(Unit* done_by, uint32 &damage) + void JustDied(Unit* /*pKiller*/) override { - if (done_by == m_creature) - return; - - damage /= 4; - for(uint8 i = 0; i < 4; ++i) + if (m_pInstance) { - if (Creature* pCouncil = m_creature->GetMap()->GetCreature(Council[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 LoadGUIDs() + void JustReachedHome() override { - if (!m_pInstance) + if (m_pInstance) { - error_log(ERROR_INST_DATA); - return; + // 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); } + } - Council[0] = m_pInstance->GetData64(DATA_LADYMALANDE); - Council[1] = m_pInstance->GetData64(DATA_HIGHNETHERMANCERZEREVOR); - Council[2] = m_pInstance->GetData64(DATA_GATHIOSTHESHATTERER); - Council[3] = m_pInstance->GetData64(DATA_VERASDARKSHADOW); + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + int32 uiDamageTaken = (int32)uiDamage; + m_creature->CastCustomSpell(m_creature, SPELL_SHARED_RULE_DAM, &uiDamageTaken, NULL, NULL, true); + } - LoadedGUIDs = 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); } }; +/*###### +## boss_gathios_the_shatterer +######*/ + struct MANGOS_DLL_DECL boss_gathios_the_shattererAI : public boss_illidari_councilAI { boss_gathios_the_shattererAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } - uint32 ConsecrationTimer; - uint32 HammerOfJusticeTimer; - uint32 SealTimer; - uint32 AuraTimer; - uint32 BlessingTimer; + uint32 m_uiConsecrationTimer; + uint32 m_uiHammerOfJusticeTimer; + uint32 m_uiSealTimer; + uint32 m_uiAuraTimer; + uint32 m_uiBlessingTimer; + uint32 m_uiJudgmentTimer; - void Reset() + void Reset() override { - ConsecrationTimer = 40000; - HammerOfJusticeTimer = 10000; - SealTimer = 40000; - AuraTimer = 90000; - BlessingTimer = 60000; + m_uiConsecrationTimer = 40000; + m_uiHammerOfJusticeTimer = 10000; + m_uiSealTimer = 40000; + m_uiAuraTimer = 90000; + m_uiBlessingTimer = 60000; + m_uiJudgmentTimer = 0; } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_GATH_SLAY, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_GATH_DEATH, m_creature); - } - - Unit* SelectCouncilMember() - { - Unit* pUnit = m_creature; - uint32 member = 0; // He chooses Lady Malande most often - if (!urand(0, 9)) // But there is a chance he picks someone else. - member = urand(1, 3); - - if (member != 2) // No need to create another pointer - pUnit = m_creature->GetMap()->GetCreature(Council[member]); - - return pUnit; + boss_illidari_councilAI::JustDied(pKiller); } - void CastAuraOnCouncil() - { - uint32 spellid = 0; - switch(urand(0, 1)) - { - case 0: spellid = SPELL_DEVOTION_AURA; break; - case 1: spellid = SPELL_CHROMATIC_AURA; break; - } - for(uint8 i = 0; i < 4; ++i) - { - if (Creature* pCouncil = m_creature->GetMap()->GetCreature(Council[i])) - pCouncil->CastSpell(pCouncil, spellid, true, NULL, NULL, m_creature->GetGUID()); - } - } - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (BlessingTimer < diff) + if (m_uiBlessingTimer < uiDiff) { - if (Unit* pUnit = SelectCouncilMember()) - DoCastSpellIfCan(pUnit, urand(0, 1) ? SPELL_BLESS_SPELLWARD : SPELL_BLESS_PROTECTION); + 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; - BlessingTimer = 60000; - }else BlessingTimer -= diff; + if (m_uiConsecrationTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CONSECRATION) == CAST_OK) + m_uiConsecrationTimer = urand(10000, 15000); + } + else + m_uiConsecrationTimer -= uiDiff; - if (ConsecrationTimer < diff) + if (m_uiHammerOfJusticeTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_CONSECRATION); - ConsecrationTimer = 40000; - }else ConsecrationTimer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_HAMMER_OF_JUSTICE, SELECT_FLAG_PLAYER | SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HAMMER_OF_JUSTICE) == CAST_OK) + m_uiHammerOfJusticeTimer = 20000; + } + } + else + m_uiHammerOfJusticeTimer -= uiDiff; - if (HammerOfJusticeTimer < diff) + if (m_uiSealTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SEAL_OF_COMMAND : SPELL_SEAL_OF_BLOOD) == CAST_OK) { - // is in ~10-40 yd range - if (m_creature->IsInRange(target, 10.0f, 40.0f, false)) - { - DoCastSpellIfCan(target, SPELL_HAMMER_OF_JUSTICE); - HammerOfJusticeTimer = 20000; - } + m_uiSealTimer = 40000; + + if (urand(0, 1)) + m_uiJudgmentTimer = urand(4000, 7000); } - }else HammerOfJusticeTimer -= diff; + } + else + m_uiSealTimer -= uiDiff; - if (SealTimer < diff) + if (m_uiAuraTimer < uiDiff) { - DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SEAL_OF_COMMAND : SPELL_SEAL_OF_BLOOD); - SealTimer = 40000; - }else SealTimer -= diff; + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_DEVOTION_AURA : SPELL_CHROMATIC_AURA) == CAST_OK) + m_uiAuraTimer = 90000; + } + else + m_uiAuraTimer -= uiDiff; - if (AuraTimer < diff) + if (m_uiJudgmentTimer) { - CastAuraOnCouncil(); - AuraTimer = 90000; - }else AuraTimer -= diff; + if (m_uiJudgmentTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_JUDGMENT) == CAST_OK) + m_uiJudgmentTimer = 0; + } + else + m_uiJudgmentTimer -= uiDiff; + } DoMeleeAttackIfReady(); } }; +/*###### +## boss_high_nethermancer_zerevor +######*/ + struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_councilAI { boss_high_nethermancer_zerevorAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } - uint32 BlizzardTimer; - uint32 FlamestrikeTimer; - uint32 ArcaneBoltTimer; - uint32 DampenMagicTimer; - uint32 Cooldown; - uint32 ArcaneExplosionTimer; + uint32 m_uiBlizzardTimer; + uint32 m_uiFlamestrikeTimer; + uint32 m_uiArcaneBoltTimer; + uint32 m_uiDampenMagicTimer; + uint32 m_uiArcaneExplosionTimer; - void Reset() + void Reset() override { - BlizzardTimer = urand(30000, 90000); - FlamestrikeTimer = urand(30000, 90000); - ArcaneBoltTimer = 10000; - DampenMagicTimer = 2000; - ArcaneExplosionTimer = 14000; - Cooldown = 0; + m_uiBlizzardTimer = urand(10000, 20000); + m_uiFlamestrikeTimer = urand(10000, 20000); + m_uiArcaneBoltTimer = 3000; + m_uiDampenMagicTimer = 2000; + m_uiArcaneExplosionTimer = 13000; } - void KilledUnit(Unit *victim) + 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_ZERE_SLAY, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_ZERE_DEATH, m_creature); + + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Cooldown) + if (m_uiDampenMagicTimer < uiDiff) { - if (Cooldown < diff) - Cooldown = 0; - else - { - Cooldown -= diff; - return; // Don't cast any other spells if global cooldown is still ticking - } + if (DoCastSpellIfCan(m_creature, SPELL_DAMPEN_MAGIC) == CAST_OK) + m_uiDampenMagicTimer = 110000; // Almost 2 minutes } + else + m_uiDampenMagicTimer -= uiDiff; - if (DampenMagicTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_DAMPEN_MAGIC); - Cooldown = 1000; - DampenMagicTimer = 110000; // almost 2 minutes - ArcaneBoltTimer += 1000; // Give the Mage some time to spellsteal Dampen. - }else DampenMagicTimer -= diff; - - if (ArcaneExplosionTimer < diff) + if (m_uiArcaneExplosionTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - Cooldown = 1000; - ArcaneExplosionTimer = 14000; - }else ArcaneExplosionTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = urand(5000, 15000); + } + else + m_uiArcaneExplosionTimer -= uiDiff; - if (ArcaneBoltTimer < diff) + if (m_uiArcaneBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BOLT); - ArcaneBoltTimer = 3000; - Cooldown = 2000; - }else ArcaneBoltTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BOLT) == CAST_OK) + m_uiArcaneBoltTimer = 3000; + } + else + m_uiArcaneBoltTimer -= uiDiff; - if (BlizzardTimer < diff) + 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); - BlizzardTimer = urand(45000, 90000); - FlamestrikeTimer += 10000; - Cooldown = 1000; + if (DoCastSpellIfCan(pTarget, SPELL_BLIZZARD) == CAST_OK) + { + m_uiBlizzardTimer = urand(5000, 15000); + m_uiFlamestrikeTimer += 5000; + } } - }else BlizzardTimer -= diff; + } + else + m_uiBlizzardTimer -= uiDiff; - if (FlamestrikeTimer < diff) + 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); - FlamestrikeTimer = urand(55000, 100000); - BlizzardTimer += 10000; - Cooldown = 2000; + if (DoCastSpellIfCan(pTarget, SPELL_FLAMESTRIKE) == CAST_OK) + { + m_uiFlamestrikeTimer = urand(5000, 15000); + m_uiBlizzardTimer += 5000; + } } - }else FlamestrikeTimer -= diff; + } + else + m_uiFlamestrikeTimer -= uiDiff; } }; +/*###### +## boss_lady_malande +######*/ + struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI { boss_lady_malandeAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } - uint32 EmpoweredSmiteTimer; - uint32 CircleOfHealingTimer; - uint32 DivineWrathTimer; - uint32 ReflectiveShieldTimer; + uint32 m_uiEmpoweredSmiteTimer; + uint32 m_uiCircleOfHealingTimer; + uint32 m_uiDivineWrathTimer; + uint32 m_uiReflectiveShieldTimer; - void Reset() + void Reset() override { - EmpoweredSmiteTimer = 38000; - CircleOfHealingTimer = 20000; - DivineWrathTimer = 40000; - ReflectiveShieldTimer = 0; + m_uiEmpoweredSmiteTimer = 10000; + m_uiCircleOfHealingTimer = 20000; + m_uiDivineWrathTimer = 5000; + m_uiReflectiveShieldTimer = 0; } - void KilledUnit(Unit *victim) + 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 *victim) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_MALA_DEATH, m_creature); + + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (EmpoweredSmiteTimer < diff) + if (m_uiEmpoweredSmiteTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target, SPELL_EMPOWERED_SMITE); - EmpoweredSmiteTimer = 38000; + if (DoCastSpellIfCan(pTarget, SPELL_EMPOWERED_SMITE) == CAST_OK) + m_uiEmpoweredSmiteTimer = urand(5000, 15000); } - }else EmpoweredSmiteTimer -= diff; + } + else + m_uiEmpoweredSmiteTimer -= uiDiff; - if (CircleOfHealingTimer < diff) + 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); - CircleOfHealingTimer = 60000; - }else CircleOfHealingTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_CIRCLE_OF_HEALING) == CAST_OK) + m_uiCircleOfHealingTimer = 20000; + } + else + m_uiCircleOfHealingTimer -= uiDiff; - if (DivineWrathTimer < diff) + 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); - DivineWrathTimer = urand(40000, 80000); + if (DoCastSpellIfCan(pTarget, SPELL_DIVINE_WRATH) == CAST_OK) + m_uiDivineWrathTimer = urand(2000, 5000); } - }else DivineWrathTimer -= diff; + } + else + m_uiDivineWrathTimer -= uiDiff; - if (ReflectiveShieldTimer < diff) + if (m_uiReflectiveShieldTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_REFLECTIVE_SHIELD); - ReflectiveShieldTimer = 65000; - }else ReflectiveShieldTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_REFLECTIVE_SHIELD) == CAST_OK) + m_uiReflectiveShieldTimer = urand(30000, 40000); + } + else + m_uiReflectiveShieldTimer -= uiDiff; DoMeleeAttackIfReady(); } }; +/*###### +## boss_veras_darkshadow +######*/ + struct MANGOS_DLL_DECL boss_veras_darkshadowAI : public boss_illidari_councilAI { boss_veras_darkshadowAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } - uint64 EnvenomTargetGUID; + uint32 m_uiDeadlyPoisonTimer; + uint32 m_uiVanishTimer; + uint32 m_uiVanishEndtimer; + uint32 m_uiEnvenomTimer; - uint32 DeadlyPoisonTimer; - uint32 VanishTimer; - uint32 AppearEnvenomTimer; - - bool HasVanished; - - void Reset() + void Reset() override { - EnvenomTargetGUID = 0; - - DeadlyPoisonTimer = 20000; - VanishTimer = urand(60000, 120000); - AppearEnvenomTimer = 150000; - - HasVanished = 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 *victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_VERA_SLAY, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_VERA_DEATH, m_creature); + + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 diff) + void EnterEvadeMode() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_uiVanishEndtimer) return; - if (!HasVanished) - { - if (DeadlyPoisonTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEADLY_POISON); - DeadlyPoisonTimer = urand(15000, 45000); - }else DeadlyPoisonTimer -= diff; + ScriptedAI::EnterEvadeMode(); + } - if (AppearEnvenomTimer < diff) // Cast Envenom. This is cast 4 seconds after Vanish is over - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENVENOM); - AppearEnvenomTimer = 90000; - }else AppearEnvenomTimer -= diff; + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - if (VanishTimer < diff) // Disappear and stop attacking, but follow a random unit + if (m_uiVanishEndtimer) + { + if (m_uiVanishEndtimer <= uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(m_creature, SPELL_VANISH_TELEPORT) == CAST_OK) { - VanishTimer = 30000; - AppearEnvenomTimer= 28000; - HasVanished = 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(target, 500000.0f); - m_creature->GetMotionMaster()->MoveChase(target); + m_uiVanishEndtimer = 0; } - }else VanishTimer -= diff; + } + else + 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 (VanishTimer < diff) // 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 target for a while, he will cast Envenom 4 seconds after. - DeadlyPoisonTimer += 6000; - VanishTimer = 90000; - AppearEnvenomTimer = 4000; - HasVanished = false; - }else VanishTimer -= diff; - - if (AppearEnvenomTimer < diff) // Appear 2 seconds before becoming attackable (Shifting out of vanish) + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENVENOM) == CAST_OK) + m_uiEnvenomTimer = 5000; + } + else + m_uiEnvenomTimer -= uiDiff; + + 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); - AppearEnvenomTimer = 6000; - }else AppearEnvenomTimer -= diff; + m_uiVanishTimer = urand(30000, 40000); + m_uiVanishEndtimer = 1000; + } } + else + m_uiVanishTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; @@ -827,35 +777,35 @@ CreatureAI* GetAI_boss_high_nethermancer_zerevor(Creature* pCreature) void AddSC_boss_illidari_council() { - Script *newscript; - - newscript = new Script; - newscript->Name = "mob_illidari_council"; - newscript->GetAI = &GetAI_mob_illidari_council; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_blood_elf_council_voice_trigger"; - newscript->GetAI = &GetAI_mob_blood_elf_council_voice_trigger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_gathios_the_shatterer"; - newscript->GetAI = &GetAI_boss_gathios_the_shatterer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lady_malande"; - newscript->GetAI = &GetAI_boss_lady_malande; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_veras_darkshadow"; - newscript->GetAI = &GetAI_boss_veras_darkshadow; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_high_nethermancer_zerevor"; - newscript->GetAI = &GetAI_boss_high_nethermancer_zerevor; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_illidari_council"; + pNewScript->GetAI = &GetAI_mob_illidari_council; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_blood_elf_council_voice_trigger"; + pNewScript->GetAI = &GetAI_mob_blood_elf_council_voice_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_gathios_the_shatterer"; + pNewScript->GetAI = &GetAI_boss_gathios_the_shatterer; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_lady_malande"; + pNewScript->GetAI = &GetAI_boss_lady_malande; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_veras_darkshadow"; + pNewScript->GetAI = &GetAI_boss_veras_darkshadow; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_high_nethermancer_zerevor"; + pNewScript->GetAI = &GetAI_boss_high_nethermancer_zerevor; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/black_temple/instance_black_temple.cpp b/scripts/outland/black_temple/instance_black_temple.cpp index 7d101ef149..f5e7d97fa4 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -36,286 +36,258 @@ EndScriptData */ 8 - Illidan Stormrage Event */ -struct MANGOS_DLL_DECL instance_black_temple : public ScriptedInstance +instance_black_temple::instance_black_temple(Map* pMap) : ScriptedInstance(pMap) { - instance_black_temple(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiNajentusGUID; - uint64 m_uiAkamaGUID; // This is the Akama that starts the Illidan encounter. - uint64 m_uiAkama_ShadeGUID; // This is the Akama that starts the Shade of Akama encounter. - uint64 m_uiShadeOfAkamaGUID; - uint64 m_uiSupremusGUID; - uint64 m_uiLadyMalandeGUID; - uint64 m_uiGathiosTheShattererGUID; - uint64 m_uiHighNethermancerZerevorGUID; - uint64 m_uiVerasDarkshadowGUID; - uint64 m_uiIllidariCouncilGUID; - uint64 m_uiBloodElfCouncilVoiceGUID; - uint64 m_uiIllidanStormrageGUID; - - uint64 m_uiNajentusGateGUID; - uint64 m_uiMainTempleDoorsGUID; - uint64 m_uiShadeAkamaDoorGUID; - uint64 m_uiIllidanGateGUID; - uint64 m_uiIllidanDoorGUID[2]; - uint64 m_uiShahrazPreDoorGUID; - uint64 m_uiShahrazPostDoorGUID; - uint64 m_uiCouncilDoorGUID; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + Initialize(); +}; - m_uiNajentusGUID = 0; - m_uiAkamaGUID = 0; - m_uiAkama_ShadeGUID = 0; - m_uiShadeOfAkamaGUID = 0; - m_uiSupremusGUID = 0; - m_uiLadyMalandeGUID = 0; - m_uiGathiosTheShattererGUID = 0; - m_uiHighNethermancerZerevorGUID = 0; - m_uiVerasDarkshadowGUID = 0; - m_uiIllidariCouncilGUID = 0; - m_uiBloodElfCouncilVoiceGUID = 0; - m_uiIllidanStormrageGUID = 0; +void instance_black_temple::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - m_uiNajentusGateGUID = 0; - m_uiMainTempleDoorsGUID = 0; - m_uiShadeAkamaDoorGUID = 0; - m_uiIllidanGateGUID = 0; - m_uiIllidanDoorGUID[0] = 0; - m_uiIllidanDoorGUID[1] = 0; - m_uiShahrazPreDoorGUID = 0; - m_uiShahrazPostDoorGUID = 0; - m_uiCouncilDoorGUID = 0; - } +void instance_black_temple::OnPlayerEnter(Player* /*pPlayer*/) +{ + DoSpawnAkamaIfCan(); +} - bool IsEncounterInProgress() const +bool instance_black_temple::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; + if (m_auiEncounter[i] == IN_PROGRESS) + return true; } - void OnCreatureCreate(Creature* pCreature) - { - switch(pCreature->GetEntry()) - { - case 22887: m_uiNajentusGUID = pCreature->GetGUID(); break; - case 23089: m_uiAkamaGUID = pCreature->GetGUID(); break; - case 22990: m_uiAkama_ShadeGUID = pCreature->GetGUID(); break; - case 22841: m_uiShadeOfAkamaGUID = pCreature->GetGUID(); break; - case 22898: m_uiSupremusGUID = pCreature->GetGUID(); break; - case 22917: m_uiIllidanStormrageGUID = pCreature->GetGUID(); break; - case 22949: m_uiGathiosTheShattererGUID = pCreature->GetGUID(); break; - case 22950: m_uiHighNethermancerZerevorGUID = pCreature->GetGUID(); break; - case 22951: m_uiLadyMalandeGUID = pCreature->GetGUID(); break; - case 22952: m_uiVerasDarkshadowGUID = pCreature->GetGUID(); break; - case 23426: m_uiIllidariCouncilGUID = pCreature->GetGUID(); break; - case 23499: m_uiBloodElfCouncilVoiceGUID = pCreature->GetGUID(); break; - } - } + return false; +} - void OnObjectCreate(GameObject* pGo) +void instance_black_temple::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pGo->GetEntry()) - { - case 185483: // Gate past Naj'entus (at the entrance to Supermoose's courtyards) - m_uiNajentusGateGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 185882: // Main Temple Doors - right past Supermoose (Supremus) - m_uiMainTempleDoorsGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 185478: - m_uiShadeAkamaDoorGUID = pGo->GetGUID(); // Door close during encounter - break; - case 185479: // Door leading to Mother Shahraz - m_uiShahrazPreDoorGUID = pGo->GetGUID(); - if (CanPreMotherDoorOpen()) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 185481: // Door leading to the Council (grand promenade) - m_uiCouncilDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[6] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 185482: // Door after shahraz - m_uiShahrazPostDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[6] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; - case 185905: // Gate leading to Temple Summit - m_uiIllidanGateGUID = pGo->GetGUID(); - break; - case 186261: // Right door at Temple Summit - m_uiIllidanDoorGUID[0] = pGo->GetGUID(); - break; - case 186262: // Left door at Temple Summit - m_uiIllidanDoorGUID[1] = pGo->GetGUID(); + 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; } +} - bool CanPreMotherDoorOpen() +void instance_black_temple::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - if (m_auiEncounter[2] == DONE && m_auiEncounter[3] == DONE && m_auiEncounter[4] == DONE && m_auiEncounter[5] == 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; + case GO_NAJENTUS_GATE: // Gate past Naj'entus (at the entrance to Supermoose's courtyards) + if (m_auiEncounter[TYPE_NAJENTUS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SUPREMUS_DOORS: // Main Temple Doors - right past Supermoose (Supremus) + if (m_auiEncounter[TYPE_SUPREMUS] == DONE) + 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 (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[TYPE_SHAHRAZ] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_PRE_COUNCIL_DOOR: // Door leading to the Council (grand promenade) + case GO_COUNCIL_DOOR: // Door leading to the Council (inside) + case GO_ILLIDAN_GATE: // Gate leading to Temple Summit + case GO_ILLIDAN_DOOR_R: // Right door at Temple Summit + case GO_ILLIDAN_DOOR_L: // Left door at Temple Summit + break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void SetData(uint32 uiType, uint32 uiData) +void instance_black_temple::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - debug_log("SD2: Instance Black Temple: SetData received for type %u with data %u",uiType,uiData); - - switch(uiType) - { - case TYPE_NAJENTUS: - m_auiEncounter[0] = uiData; - if (uiData == DONE) - DoUseDoorOrButton(m_uiNajentusGateGUID); - break; - case TYPE_SUPREMUS: - m_auiEncounter[1] = uiData; - if (uiData == DONE) - DoUseDoorOrButton(m_uiMainTempleDoorsGUID); - break; - case TYPE_SHADE: - m_auiEncounter[2] = uiData; - if (uiData == DONE && CanPreMotherDoorOpen()) - DoUseDoorOrButton(m_uiShahrazPreDoorGUID); - break; - case TYPE_GOREFIEND: - m_auiEncounter[3] = uiData; - if (uiData == DONE && CanPreMotherDoorOpen()) - DoUseDoorOrButton(m_uiShahrazPreDoorGUID); - break; - case TYPE_BLOODBOIL: - m_auiEncounter[4] = uiData; - if (uiData == DONE && CanPreMotherDoorOpen()) - DoUseDoorOrButton(m_uiShahrazPreDoorGUID); - break; - case TYPE_RELIQUIARY: - m_auiEncounter[5] = uiData; - if (uiData == DONE && CanPreMotherDoorOpen()) - DoUseDoorOrButton(m_uiShahrazPreDoorGUID); - break; - case TYPE_SHAHRAZ: - if (uiData == DONE) + case TYPE_NAJENTUS: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoUseDoorOrButton(GO_NAJENTUS_GATE); + break; + case TYPE_SUPREMUS: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + 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) { - DoUseDoorOrButton(m_uiCouncilDoorGUID); - DoUseDoorOrButton(m_uiShahrazPostDoorGUID); + if (Creature* pChanneler = instance->GetCreature(*itr)) + { + if (!pChanneler->isAlive()) + pChanneler->Respawn(); + else + pChanneler->AI()->EnterEvadeMode(); + } } - m_auiEncounter[6] = uiData; - break; - case TYPE_COUNCIL: m_auiEncounter[7] = uiData; break; - case TYPE_ILLIDAN: m_auiEncounter[8] = uiData; break; - default: - error_log("SD2: Instance Black Temple: ERROR SetData = %u for type %u does not exist/not implemented.",uiType,uiData); - break; - } + } + 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) + DoOpenPreMotherDoor(); + break; + case TYPE_SHAHRAZ: + if (uiData == DONE) + DoUseDoorOrButton(GO_POST_SHAHRAZ_DOOR); + 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; + default: + script_error_log("Instance Black Temple: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; + } - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; + 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]; + 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]; - strInstData = saveStream.str(); + m_strInstData = saveStream.str(); - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_NAJENTUS: return m_auiEncounter[0]; - case TYPE_SUPREMUS: return m_auiEncounter[1]; - case TYPE_SHADE: return m_auiEncounter[2]; - case TYPE_GOREFIEND: return m_auiEncounter[3]; - case TYPE_BLOODBOIL: return m_auiEncounter[4]; - case TYPE_RELIQUIARY: return m_auiEncounter[5]; - case TYPE_SHAHRAZ: return m_auiEncounter[6]; - case TYPE_COUNCIL: return m_auiEncounter[7]; - case TYPE_ILLIDAN: return m_auiEncounter[8]; - } +uint32 instance_black_temple::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - return 0; - } + return 0; +} - uint64 GetData64(uint32 uiData) - { - switch(uiData) - { - case DATA_HIGHWARLORDNAJENTUS: return m_uiNajentusGUID; - case DATA_AKAMA: return m_uiAkamaGUID; - case DATA_AKAMA_SHADE: return m_uiAkama_ShadeGUID; - case DATA_SHADEOFAKAMA: return m_uiShadeOfAkamaGUID; - case DATA_SUPREMUS: return m_uiSupremusGUID; - case DATA_ILLIDANSTORMRAGE: return m_uiIllidanStormrageGUID; - case DATA_GATHIOSTHESHATTERER: return m_uiGathiosTheShattererGUID; - case DATA_HIGHNETHERMANCERZEREVOR: return m_uiHighNethermancerZerevorGUID; - case DATA_LADYMALANDE: return m_uiLadyMalandeGUID; - case DATA_VERASDARKSHADOW: return m_uiVerasDarkshadowGUID; - case DATA_ILLIDARICOUNCIL: return m_uiIllidariCouncilGUID; - case DATA_GAMEOBJECT_NAJENTUS_GATE: return m_uiNajentusGateGUID; - case DATA_GAMEOBJECT_ILLIDAN_GATE: return m_uiIllidanGateGUID; - case DATA_GAMEOBJECT_ILLIDAN_DOOR_R: return m_uiIllidanDoorGUID[0]; - case DATA_GAMEOBJECT_ILLIDAN_DOOR_L: return m_uiIllidanDoorGUID[1]; - case DATA_GAMEOBJECT_SUPREMUS_DOORS: return m_uiMainTempleDoorsGUID; - case DATA_BLOOD_ELF_COUNCIL_VOICE: return m_uiBloodElfCouncilVoiceGUID; - case DATA_GO_PRE_SHAHRAZ_DOOR: return m_uiShahrazPreDoorGUID; - case DATA_GO_POST_SHAHRAZ_DOOR: return m_uiShahrazPostDoorGUID; - case DATA_GO_COUNCIL_DOOR: return m_uiCouncilDoorGUID; - } +void instance_black_temple::DoOpenPreMotherDoor() +{ + if (GetData(TYPE_SHADE) == DONE && GetData(TYPE_GOREFIEND) == DONE && GetData(TYPE_BLOODBOIL) == DONE && GetData(TYPE_RELIQUIARY) == DONE) + DoUseDoorOrButton(GO_PRE_SHAHRAZ_DOOR); +} - return 0; - } +void instance_black_temple::DoSpawnAkamaIfCan() +{ + if (GetData(TYPE_ILLIDAN) == DONE || GetData(TYPE_COUNCIL) != DONE) + return; - const char* Save() - { - return strInstData.c_str(); - } + // If already spawned return + if (GetSingleCreatureFromStorage(NPC_AKAMA, true)) + return; - void Load(const char* chrIn) - { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - 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); +} - OUT_LOAD_INST_DATA(chrIn); +void instance_black_temple::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - 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]; + OUT_LOAD_INST_DATA(chrIn); - 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; + 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]; - OUT_LOAD_INST_DATA_COMPLETE; + 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; +} InstanceData* GetInstanceData_instance_black_temple(Map* pMap) { @@ -324,9 +296,10 @@ InstanceData* GetInstanceData_instance_black_temple(Map* pMap) void AddSC_instance_black_temple() { - Script* newscript; - newscript = new Script; - newscript->Name = "instance_black_temple"; - newscript->GetInstanceData = &GetInstanceData_instance_black_temple; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_black_temple"; + pNewScript->GetInstanceData = &GetInstanceData_instance_black_temple; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/blades_edge_mountains.cpp b/scripts/outland/blades_edge_mountains.cpp index bad14bd43a..e241fc0ce3 100644 --- a/scripts/outland/blades_edge_mountains.cpp +++ b/scripts/outland/blades_edge_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,204 +17,190 @@ /* ScriptData SDName: Blades_Edge_Mountains SD%Complete: 90 -SDComment: Quest support: 10503, 10504, 10556, 10609, 10682, 10980. Ogri'la->Skettis Flight. (npc_daranelle needs bit more work before consider complete) +SDComment: Quest support: 10503, 10504, 10512, 10545, 10556, 10609, 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_overseer_nuaar -npc_saikkal_the_elder -npc_skyguard_handler_irena +npc_bloodmaul_stout_trigger +npc_simon_game_bunny 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 -{ - mobs_bladespire_ogreAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() { } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mobs_bladespire_ogre(Creature* pCreature) +enum { - return new mobs_bladespire_ogreAI(pCreature); -} + SAY_NIHIL_1 = -1000169, + SAY_NIHIL_2 = -1000170, + SAY_NIHIL_3 = -1000171, + SAY_NIHIL_4 = -1000172, + SAY_NIHIL_INTERRUPT = -1000173, -/*###### -## mobs_nether_drake -######*/ + MAX_ENTRIES = 4, -#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 + NPC_PROTO = 21821, + NPC_ADOLESCENT = 21817, + NPC_MATURE = 21820, + NPC_NIHIL = 21823, -#define ENTRY_WHELP 20021 -#define ENTRY_PROTO 21821 -#define ENTRY_ADOLE 21817 -#define ENTRY_MATUR 21820 -#define ENTRY_NIHIL 21823 + SPELL_T_PHASE_MODULATOR = 37573, -#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 { 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + 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(); } @@ -240,9 +226,9 @@ struct MANGOS_DLL_DECL 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) { @@ -250,8 +236,8 @@ 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 - ((Player*)pWho)->KilledMonsterCredit(NPC_KALIRI_AURA_DISPEL, m_creature->GetGUID()); + // 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); } } @@ -266,126 +252,571 @@ CreatureAI* GetAI_npc_daranelle(Creature* pCreature) } /*###### -## npc_overseer_nuaar +## npc_bloodmaul_stout_trigger ######*/ -bool GossipHello_npc_overseer_nuaar(Player* pPlayer, Creature* pCreature) +enum { - if (pPlayer->GetQuestStatus(10682) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Overseer, I am here to negotiate on behalf of the Cenarion Expedition.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + SAY_BREW_1 = -1000156, + SAY_BREW_2 = -1000207, + SAY_BREW_3 = -1000208, - pPlayer->SEND_GOSSIP_MENU(10532, pCreature->GetGUID()); + SPELL_INTOXICATION = 35240, + SPELL_INTOXICATION_VISUAL = 35777, +}; - return true; -} +static const uint32 aOgreEntries[] = {19995, 19998, 20334, 20723, 20726, 20730, 20731, 20732, 21296}; -bool GossipSelect_npc_overseer_nuaar(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +struct MANGOS_DLL_DECL npc_bloodmaul_stout_triggerAI : public ScriptedAI { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + 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 { - pPlayer->SEND_GOSSIP_MENU(10533, pCreature->GetGUID()); - pPlayer->AreaExploredOrEventHappens(10682); + 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; + } } - return true; +}; + +CreatureAI* GetAI_npc_bloodmaul_stout_trigger(Creature* pCreature) +{ + return new npc_bloodmaul_stout_triggerAI(pCreature); } /*###### -## npc_saikkal_the_elder +## npc_simon_game_bunny ######*/ -bool GossipHello_npc_saikkal_the_elder(Player* pPlayer, Creature* pCreature) +enum { - if (pPlayer->GetQuestStatus(10980) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Yes... yes, it's me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + // 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 +}; - pPlayer->SEND_GOSSIP_MENU(10794, pCreature->GetGUID()); +struct SimonGame +{ + uint8 m_uiColor; + uint32 m_uiVisual, m_uiIntrospection, m_uiSoundId; +}; - return true; -} +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} +}; -bool GossipSelect_npc_saikkal_the_elder(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +struct MANGOS_DLL_DECL npc_simon_game_bunnyAI : public ScriptedAI { - switch(uiAction) + 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 { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Yes elder. Tell me more of the book.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(10795, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetGUID()); - pPlayer->SEND_GOSSIP_MENU(10796, pCreature->GetGUID()); - break; + m_uiGamePhase = PHASE_LEVEL_PREPARE; + m_bIsEventStarted = false; + + m_uiLevelCount = 0; + m_uiLevelStage = 0; + m_uiPlayerStage = 0; } - return true; -} -/*###### -## npc_skyguard_handler_irena -######*/ + 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; + } -#define GOSSIP_SKYGUARD "Fly me to Skettis please" + // 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); -bool GossipHello_npc_skyguard_handler_irena(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + m_vColors.clear(); + ++m_uiLevelCount; + } - if (pPlayer->GetReputationRank(1031) >= REP_HONORED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SKYGUARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + // 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); + } + } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // cleanup event after quest is finished + DoCastSpellIfCan(m_creature, SPELL_SWITCHED_OFF, CAST_TRIGGERED); + DoPlaySoundToSet(m_creature, SOUND_ID_DISABLE_NODE); + m_creature->ForcedDespawn(); + } - return true; + // 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 GossipSelect_npc_skyguard_handler_irena(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool EffectDummyCreature_npc_simon_game_bunny(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + 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) { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer,41278,true); //TaxiPath 706 + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, pCaster, pCreatureTarget); + return true; } - return true; + + return false; } -/*###### -## AddSC -######*/ +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; +} void AddSC_blades_edge_mountains() { - Script *newscript; - - newscript = new Script; - newscript->Name = "mobs_bladespire_ogre"; - newscript->GetAI = &GetAI_mobs_bladespire_ogre; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mobs_nether_drake"; - newscript->GetAI = &GetAI_mobs_nether_drake; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_daranelle"; - newscript->GetAI = &GetAI_npc_daranelle; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_overseer_nuaar"; - newscript->pGossipHello = &GossipHello_npc_overseer_nuaar; - newscript->pGossipSelect = &GossipSelect_npc_overseer_nuaar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_saikkal_the_elder"; - newscript->pGossipHello = &GossipHello_npc_saikkal_the_elder; - newscript->pGossipSelect = &GossipSelect_npc_saikkal_the_elder; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_skyguard_handler_irena"; - newscript->pGossipHello = &GossipHello_npc_skyguard_handler_irena; - newscript->pGossipSelect = &GossipSelect_npc_skyguard_handler_irena; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mobs_nether_drake"; + pNewScript->GetAI = &GetAI_mobs_nether_drake; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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(); } diff --git a/scripts/outland/boss_doomlord_kazzak.cpp b/scripts/outland/boss_doomlord_kazzak.cpp index eae350ae7f..af1ba568f4 100644 --- a/scripts/outland/boss_doomlord_kazzak.cpp +++ b/scripts/outland/boss_doomlord_kazzak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Doomlord_Kazzak -SD%Complete: 70 -SDComment: Using incorrect spell for Mark of Kazzak +SD%Complete: 90 +SDComment: Timers SDCategory: Hellfire Peninsula EndScriptData */ @@ -38,58 +38,60 @@ enum SAY_RAND1 = -1000157, SAY_RAND2 = -1000158, - SPELL_SHADOWVOLLEY = 32963, + SPELL_SHADOW_VOLLEY = 32963, SPELL_CLEAVE = 31779, SPELL_THUNDERCLAP = 36706, - SPELL_VOIDBOLT = 39329, - SPELL_MARKOFKAZZAK = 32960, - SPELL_ENRAGE = 32964, - SPELL_CAPTURESOUL = 32966, - SPELL_TWISTEDREFLECTION = 21063 + SPELL_VOID_BOLT = 39329, + SPELL_MARK_OF_KAZZAK = 32960, + SPELL_FRENZY = 32964, // triggers 32963 + SPELL_CAPTURE_SOUL = 48473, // procs 32966 on player kill + SPELL_TWISTED_REFLECTION = 21063, + SPELL_BERSERK = 32965, // triggers 32963 }; struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI { - boss_doomlordkazzakAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowVolley_Timer; - uint32 Cleave_Timer; - uint32 ThunderClap_Timer; - uint32 VoidBolt_Timer; - uint32 MarkOfKazzak_Timer; - uint32 Enrage_Timer; - uint32 Twisted_Reflection_Timer; - - void Reset() + boss_doomlordkazzakAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiShadowVolleyTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiThunderClapTimer; + uint32 m_uiVoidBoltTimer; + uint32 m_uiMarkOfKazzakTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiGreatEnrageTimer; + uint32 m_uiTwistedReflectionTimer; + + void Reset() override { - ShadowVolley_Timer = urand(6000, 10000); - Cleave_Timer = 7000; - ThunderClap_Timer = urand(14000, 18000); - VoidBolt_Timer = 30000; - MarkOfKazzak_Timer = 25000; - Enrage_Timer = 60000; - Twisted_Reflection_Timer = 33000; // Timer may be incorrect + m_uiShadowVolleyTimer = urand(6000, 10000); + m_uiCleaveTimer = 7000; + m_uiThunderClapTimer = urand(14000, 18000); + m_uiVoidBoltTimer = 30000; + m_uiMarkOfKazzakTimer = 25000; + m_uiEnrageTimer = 60000; + 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 *who) + 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* victim) + void KilledUnit(Unit* pVictim) override { // When Kazzak kills a player (not pets/totems), he regens some health - if (victim->GetTypeId() != TYPEID_PLAYER) + if (pVictim->GetTypeId() != TYPEID_PLAYER) return; - DoCastSpellIfCan(m_creature,SPELL_CAPTURESOUL); - - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL1, m_creature); break; case 1: DoScriptText(SAY_KILL2, m_creature); break; @@ -97,75 +99,106 @@ struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI } } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - 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; - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) + // ShadowVolley_Timer + if (m_uiShadowVolleyTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWVOLLEY); - ShadowVolley_Timer = urand(4000, 6000); - }else ShadowVolley_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_VOLLEY) == CAST_OK) + m_uiShadowVolleyTimer = urand(10000, 30000); + } + else + m_uiShadowVolleyTimer -= uiDiff; - //Cleave_Timer - if (Cleave_Timer < diff) + // Cleave_Timer + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = urand(8000, 12000); - }else Cleave_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(8000, 12000); + } + else + m_uiCleaveTimer -= uiDiff; - //ThunderClap_Timer - if (ThunderClap_Timer < diff) + // ThunderClap_Timer + if (m_uiThunderClapTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_THUNDERCLAP); - ThunderClap_Timer = urand(10000, 14000); - }else ThunderClap_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_THUNDERCLAP) == CAST_OK) + m_uiThunderClapTimer = urand(10000, 14000); + } + else + m_uiThunderClapTimer -= uiDiff; - //VoidBolt_Timer - if (VoidBolt_Timer < diff) + // VoidBolt_Timer + if (m_uiVoidBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_VOIDBOLT); - VoidBolt_Timer = urand(15000, 18000); - }else VoidBolt_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_VOID_BOLT) == CAST_OK) + m_uiVoidBoltTimer = urand(15000, 18000); + } + } + else + m_uiVoidBoltTimer -= uiDiff; - //MarkOfKazzak_Timer - if (MarkOfKazzak_Timer < diff) + // MarkOfKazzak_Timer + if (m_uiMarkOfKazzakTimer < uiDiff) { - Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (victim->GetPower(POWER_MANA)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MARK_OF_KAZZAK, SELECT_FLAG_POWER_MANA)) { - DoCastSpellIfCan(victim, SPELL_MARKOFKAZZAK); - MarkOfKazzak_Timer = 20000; + if (DoCastSpellIfCan(pTarget, SPELL_MARK_OF_KAZZAK) == CAST_OK) + m_uiMarkOfKazzakTimer = 20000; } - }else MarkOfKazzak_Timer -= diff; + } + else + m_uiMarkOfKazzakTimer -= uiDiff; - //Enrage_Timer - if (Enrage_Timer < diff) + // Enrage_Timer + if (m_uiEnrageTimer < uiDiff) { - DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); - DoCastSpellIfCan(m_creature,SPELL_ENRAGE); - Enrage_Timer = 30000; - }else Enrage_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); + m_uiEnrageTimer = 60000; + } + } + else + m_uiEnrageTimer -= uiDiff; - if (Twisted_Reflection_Timer < diff) + // Great_Enrage_Timer + if (m_uiGreatEnrageTimer) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_TWISTEDREFLECTION); + if (m_uiGreatEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiGreatEnrageTimer = 0; + } + else + m_uiGreatEnrageTimer -= uiDiff; + } - Twisted_Reflection_Timer = 15000; - }else Twisted_Reflection_Timer -= diff; + // Twisted Reflection + if (m_uiTwistedReflectionTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_TWISTED_REFLECTION) == CAST_OK) + m_uiTwistedReflectionTimer = 15000; + } + } + else + m_uiTwistedReflectionTimer -= uiDiff; DoMeleeAttackIfReady(); } - }; CreatureAI* GetAI_boss_doomlordkazzak(Creature* pCreature) @@ -175,9 +208,10 @@ CreatureAI* GetAI_boss_doomlordkazzak(Creature* pCreature) void AddSC_boss_doomlordkazzak() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_doomlord_kazzak"; - newscript->GetAI = &GetAI_boss_doomlordkazzak; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_doomlord_kazzak"; + pNewScript->GetAI = &GetAI_boss_doomlordkazzak; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/boss_doomwalker.cpp b/scripts/outland/boss_doomwalker.cpp index f98a4e85eb..de57edf164 100644 --- a/scripts/outland/boss_doomwalker.cpp +++ b/scripts/outland/boss_doomwalker.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,147 +23,137 @@ EndScriptData */ #include "precompiled.h" -#define SAY_AGGRO -1000159 -#define SAY_EARTHQUAKE_1 -1000160 -#define SAY_EARTHQUAKE_2 -1000161 -#define SAY_OVERRUN_1 -1000162 -#define SAY_OVERRUN_2 -1000163 -#define SAY_SLAY_1 -1000164 -#define SAY_SLAY_2 -1000165 -#define SAY_SLAY_3 -1000166 -#define SAY_DEATH -1000167 - -#define SPELL_EARTHQUAKE 32686 -#define SPELL_SUNDER_ARMOR 33661 -#define SPELL_CHAIN_LIGHTNING 33665 -#define SPELL_OVERRUN 32636 -#define SPELL_ENRAGE 33653 -#define SPELL_MARK_DEATH 37128 -#define SPELL_AURA_DEATH 37131 +enum +{ + SAY_AGGRO = -1000159, + SAY_EARTHQUAKE_1 = -1000160, + SAY_EARTHQUAKE_2 = -1000161, + SAY_OVERRUN_1 = -1000162, + SAY_OVERRUN_2 = -1000163, + SAY_SLAY_1 = -1000164, + SAY_SLAY_2 = -1000165, + SAY_SLAY_3 = -1000166, + SAY_DEATH = -1000167, + + SPELL_EARTHQUAKE = 32686, + SPELL_CRUSH_ARMOR = 33661, + SPELL_LIGHTNING_WRATH = 33665, + SPELL_OVERRUN = 32636, + SPELL_ENRAGE = 33653, + SPELL_MARK_OF_DEATH_PLAYER = 37128, + SPELL_MARK_OF_DEATH_AURA = 37125, // triggers 37131 on target if it has aura 37128 +}; struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI { - boss_doomwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_doomwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 Chain_Timer; - uint32 Enrage_Timer; - uint32 Overrun_Timer; - uint32 Quake_Timer; - uint32 Armor_Timer; + uint32 m_uiChainTimer; + uint32 m_uiOverrunTimer; + uint32 m_uiQuakeTimer; + uint32 m_uiArmorTimer; - bool InEnrage; + bool m_bHasEnrage; - void Reset() + void Reset() override { - Enrage_Timer = 0; - Armor_Timer = urand(5000, 13000); - Chain_Timer = urand(10000, 30000); - Quake_Timer = urand(25000, 35000); - Overrun_Timer = urand(30000, 45000); + m_uiArmorTimer = urand(5000, 13000); + m_uiChainTimer = urand(10000, 30000); + m_uiQuakeTimer = urand(25000, 35000); + m_uiOverrunTimer = urand(30000, 45000); - InEnrage = false; + m_bHasEnrage = false; } - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* pVictim) override { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; - Victim->CastSpell(Victim,SPELL_MARK_DEATH,0); + pVictim->CastSpell(pVictim, SPELL_MARK_OF_DEATH_PLAYER, true, NULL, NULL, m_creature->GetObjectGuid()); if (urand(0, 4)) return; - 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; } - } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { + DoCastSpellIfCan(m_creature, SPELL_MARK_OF_DEATH_AURA, CAST_TRIGGERED); DoScriptText(SAY_AGGRO, m_creature); } - - void MoveInLineOfSight(Unit *who) - { - if (who && who->GetTypeId() == TYPEID_PLAYER && m_creature->IsHostileTo(who)) - { - if (who->HasAura(SPELL_MARK_DEATH, EFFECT_INDEX_0)) - { - who->CastSpell(who,SPELL_AURA_DEATH,true); - } - } - } - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Spell Enrage, when hp <= 20% gain enrage - if (m_creature->GetHealthPercent() <= 20.0f) + // Spell Enrage, when hp <= 20% gain enrage + if (m_creature->GetHealthPercent() <= 20.0f && !m_bHasEnrage) { - if (Enrage_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_ENRAGE); - Enrage_Timer = 6000; - InEnrage = true; - }else Enrage_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bHasEnrage = true; } - //Spell Overrun - if (Overrun_Timer < diff) + // Spell Overrun + if (m_uiOverrunTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_OVERRUN_1 : SAY_OVERRUN_2, m_creature); - DoCastSpellIfCan(m_creature->getVictim(),SPELL_OVERRUN); - Overrun_Timer = urand(25000, 40000); - }else Overrun_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_OVERRUN) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_OVERRUN_1 : SAY_OVERRUN_2, m_creature); + m_uiOverrunTimer = urand(25000, 40000); + } + } + else + m_uiOverrunTimer -= uiDiff; - //Spell Earthquake - if (Quake_Timer < diff) + // Spell Earthquake + if (m_uiQuakeTimer < uiDiff) { - if (urand(0, 1)) - return; - - DoScriptText(urand(0, 1) ? SAY_EARTHQUAKE_1 : SAY_EARTHQUAKE_2, m_creature); - - //remove enrage before casting earthquake because enrage + earthquake = 16000dmg over 8sec and all dead - if (InEnrage) - m_creature->RemoveAurasDueToSpell(SPELL_ENRAGE); - - DoCastSpellIfCan(m_creature,SPELL_EARTHQUAKE); - Quake_Timer = urand(30000, 55000); - }else Quake_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_EARTHQUAKE) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_EARTHQUAKE_1 : SAY_EARTHQUAKE_2, m_creature); + m_uiQuakeTimer = urand(30000, 55000); + } + } + else + m_uiQuakeTimer -= uiDiff; - //Spell Chain Lightning - if (Chain_Timer < diff) + // Spell Chain Lightning + if (m_uiChainTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - if (!target) - target = m_creature->getVictim(); - - if (target) - DoCastSpellIfCan(target,SPELL_CHAIN_LIGHTNING); - - Chain_Timer = urand(7000, 27000); - }else Chain_Timer -= diff; + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, SPELL_LIGHTNING_WRATH) == CAST_OK) + m_uiChainTimer = urand(7000, 27000); + } + } + else + m_uiChainTimer -= uiDiff; - //Spell Sunder Armor - if (Armor_Timer < diff) + // Spell Sunder Armor + if (m_uiArmorTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SUNDER_ARMOR); - Armor_Timer = urand(10000, 25000); - }else Armor_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSH_ARMOR) == CAST_OK) + m_uiArmorTimer = urand(10000, 25000); + } + else + m_uiArmorTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -176,9 +166,10 @@ CreatureAI* GetAI_boss_doomwalker(Creature* pCreature) void AddSC_boss_doomwalker() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_doomwalker"; - newscript->GetAI = &GetAI_boss_doomwalker; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_doomwalker"; + pNewScript->GetAI = &GetAI_boss_doomwalker; + pNewScript->RegisterSelf(); } 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 933e9307ca..1ed3eb2a9b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,146 +36,104 @@ 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 = 38353, // triggers 38357 - SPELL_HEAL = 38330, + SPELL_TIDAL_SURGE = 38358, // triggers 38353 which then triggers 38357 + 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}; + +/*###### +## boss_fathomlord_karathress +######*/ -//Fathom-Lord Karathress AI struct MANGOS_DLL_DECL boss_fathomlord_karathressAI : public ScriptedAI { boss_fathomlord_karathressAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - memset(&m_auiAdvisorsGUID, 0, sizeof(m_auiAdvisorsGUID)); Reset(); } ScriptedInstance* m_pInstance; - // timers - uint32 m_uiCataclysmicBolt_Timer; - uint32 m_uiEnrage_Timer; + uint32 m_uiCataclysmicBoltTimer; + uint32 m_uiSearingNovaTimer; + uint32 m_uiEnrageTimer; - bool m_bBlessingOfTides_MobsChecked; + bool m_bBlessingOfTides; - uint64 m_auiAdvisorsGUID[MAX_ADVISORS]; // the GUIDs from the advisors - - void Reset() + void Reset() override { - m_uiCataclysmicBolt_Timer = 10000; - m_uiEnrage_Timer = 600000; - m_bBlessingOfTides_MobsChecked = false; - - for(uint8 i = 0; i < MAX_ADVISORS; ++i) - { - if (Creature* pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorsGUID[i])) - { - if (pAdvisor->getVictim()) - pAdvisor->AI()->EnterEvadeMode(); - else if (!pAdvisor->isAlive()) - pAdvisor->Respawn(); - } - } - - if (m_pInstance) - m_pInstance->SetData(TYPE_KARATHRESS_EVENT, NOT_STARTED); + m_uiCataclysmicBoltTimer = 10000; + m_uiSearingNovaTimer = urand(20000, 30000); + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + m_bBlessingOfTides = false; } - // select the spell and the text based on the advisor which died - void EventAdvisorDeath(uint8 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 DATA_SHARKKIS: - iSayGainAbility = SAY_GAIN_ABILITY1; - uiSpell = SPELL_POWER_OF_SHARKKIS; + case SPELL_POWER_OF_SHARKKIS: + DoScriptText(SAY_GAIN_ABILITY1, m_creature); break; - case DATA_TIDALVESS: - iSayGainAbility = SAY_GAIN_ABILITY2; - uiSpell = SPELL_POWER_OF_TIDALVESS; + case SPELL_POWER_OF_TIDALVESS: + DoScriptText(SAY_GAIN_ABILITY1, m_creature); break; - case DATA_CARIBDIS: - iSayGainAbility = SAY_GAIN_ABILITY3; - uiSpell = SPELL_POWER_OF_CARIBDIS; - break; - default: - error_log("SD2: invalid advisor (id %u) for karathress!", uiAdvisor); + case SPELL_POWER_OF_CARIBDIS: + DoScriptText(SAY_GAIN_ABILITY3, m_creature); break; } - - DoScriptText(iSayGainAbility, m_creature); - DoCastSpellIfCan(m_creature, uiSpell); - } - - void GetAdvisors() - { - if (!m_pInstance) - return; - - m_auiAdvisorsGUID[0] = m_pInstance->GetData64(DATA_SHARKKIS); - m_auiAdvisorsGUID[1] = m_pInstance->GetData64(DATA_TIDALVESS); - m_auiAdvisorsGUID[2] = m_pInstance->GetData64(DATA_CARIBDIS); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (!m_pInstance) - return; - - GetAdvisors(); + if (m_pInstance) + m_pInstance->SetData(TYPE_KARATHRESS_EVENT, IN_PROGRESS); DoScriptText(SAY_AGGRO, m_creature); - - if (Player* pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself()) - { - m_pInstance->SetData64(DATA_KARATHRESS_STARTER, pPlayer->GetGUID()); - 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; @@ -183,385 +141,328 @@ 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 UpdateAI(const uint32 uiDiff) + void JustReachedHome() override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetData64(DATA_KARATHRESS_STARTER))) - { - AttackStart(pTarget); - GetAdvisors(); - } - } - return; - } + if (m_pInstance) + m_pInstance->SetData(TYPE_KARATHRESS_EVENT, FAIL); + } - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == NOT_STARTED) - { - EnterEvadeMode(); + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - } - //m_uiCataclysmicBolt_Timer - if (m_uiCataclysmicBolt_Timer < uiDiff) + 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(); - m_creature->CastSpell(pTarget, SPELL_CATACLYSMIC_BOLT, false); - - m_uiCataclysmicBolt_Timer = 10000; - }else m_uiCataclysmicBolt_Timer -= uiDiff; + 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_creature->GetMap()->GetCreature(m_auiAdvisorsGUID[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; + } + + if (m_uiSearingNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SEAR_NOVA) == CAST_OK) + m_uiSearingNovaTimer = urand(20000, 30000); } + else + m_uiSearingNovaTimer -= uiDiff; - //m_uiEnrage_Timer - if (m_uiEnrage_Timer < uiDiff) + if (m_uiEnrageTimer) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - m_uiEnrage_Timer = 90000; - }else m_uiEnrage_Timer -= uiDiff; + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_uiEnrageTimer = 0; + } + else + m_uiEnrageTimer -= uiDiff; + } DoMeleeAttackIfReady(); } }; -// Base AI for every advisor -struct MANGOS_DLL_DECL Advisor_Base_AI : public ScriptedAI +/*###### +## boss_fathomguard_sharkkis +######*/ + +struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public ScriptedAI { - Advisor_Base_AI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - } - protected: - uint8 m_uiAdvisor; + boss_fathomguard_sharkkisAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - public: - ScriptedInstance* m_pInstance; + uint32 m_uiHurlTridentTimer; + uint32 m_uiLeechingThrowTimer; + uint32 m_uiTheBeastWithinTimer; + uint32 m_uiMultiTossTimer; + uint32 m_uiPetTimer; - void JustReachedHome() + void Reset() override { - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_KARATHRESS_EVENT, NOT_STARTED); + m_uiHurlTridentTimer = 2500; + m_uiLeechingThrowTimer = 20000; + m_uiTheBeastWithinTimer = 30000; + m_uiMultiTossTimer = urand(7000, 11000); + if (!m_creature->GetPet()) + m_uiPetTimer = 10000; } - void Aggro(Unit *pWho) + void JustDied(Unit* /*pKiller*/) override { - if (!m_pInstance) - return; - - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == NOT_STARTED) - m_pInstance->SetData(TYPE_KARATHRESS_EVENT, IN_PROGRESS); - - if (Player* pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself()) - m_pInstance->SetData64(DATA_KARATHRESS_STARTER, pPlayer->GetGUID()); + DoCastSpellIfCan(m_creature, SPELL_POWER_OF_SHARKKIS, CAST_TRIGGERED); } - void JustDied(Unit* pVictim) + void JustSummoned(Creature* pSummoned) override { - if (!m_pInstance) - return; - - if (Creature* pKarathress = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_KARATHRESS))) - { - if (boss_fathomlord_karathressAI* pKaraAI = dynamic_cast(pKarathress->AI())) - pKaraAI->EventAdvisorDeath(m_uiAdvisor); - } + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } -}; -//Fathom-Guard Sharkkis AI -struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public Advisor_Base_AI -{ - boss_fathomguard_sharkkisAI(Creature* pCreature) : Advisor_Base_AI(pCreature) + void SummonedCreatureJustDied(Creature* pSummoned) override { - Reset(); - m_uiAdvisor = DATA_SHARKKIS; - } - - // timers - uint32 m_uiHurlTrident_Timer; - uint32 m_uiLeechingThrow_Timer; - uint32 m_uiTheBeastWithin_Timer; - uint32 m_uiPet_Timer; - - bool m_bIsPetCheckNeeded; - - void Reset() - { - m_uiHurlTrident_Timer = 2500; - m_uiLeechingThrow_Timer = 20000; - m_uiTheBeastWithin_Timer = 30000; - m_uiPet_Timer = 10000; - - m_bIsPetCheckNeeded = true; + // resummon the pet in 10 secs + if (pSummoned->IsPet()) + m_uiPetTimer = 10000; } - void AttackStart(Unit* pWho) + void UpdateAI(const uint32 uiDiff) override { - if (!pWho) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->Attack(pWho, false)) + if (m_uiPetTimer) { - 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); + if (m_uiPetTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SUMMON_FATHOM_LURKER : SPELL_SUMMON_FATHOM_SPOREBAT) == CAST_OK) + m_uiPetTimer = 0; + } + else + m_uiPetTimer -= uiDiff; } - } - void JustSummoned(Creature* pSummoned) - { - if (pSummoned->IsPet()) + if (m_uiHurlTridentTimer < uiDiff) { - m_uiPet_Timer = 10000; - m_bIsPetCheckNeeded = false; - } - } - - void SummonedCreatureDespawn(Creature* pDespawned) - { - if (pDespawned->IsPet()) - m_bIsPetCheckNeeded = true; - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_HURL_TRIDENT, 0)) { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetData64(DATA_KARATHRESS_STARTER))) - AttackStart(pTarget); + if (DoCastSpellIfCan(pTarget, SPELL_HURL_TRIDENT) == CAST_OK) + m_uiHurlTridentTimer = 5000; } - return; } + else + m_uiHurlTridentTimer -= uiDiff; - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == NOT_STARTED) + if (m_uiLeechingThrowTimer < uiDiff) { - EnterEvadeMode(); - return; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_LEECHING_THROW) == CAST_OK) + m_uiLeechingThrowTimer = 20000; } + else + m_uiLeechingThrowTimer -= uiDiff; - //after 10 seconds: spawn pet if not exist - if (m_bIsPetCheckNeeded) + if (m_uiTheBeastWithinTimer < uiDiff) { - if (m_uiPet_Timer < uiDiff) - { - if (!m_creature->GetPet()) - DoCastSpellIfCan(m_creature, urand(0,1) ? SPELL_SUMMON_FATHOM_LURKER : SPELL_SUMMON_FATHOM_SPOREBAT); - } - else - m_uiPet_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_THE_BEAST_WITHIN) == CAST_OK) + m_uiTheBeastWithinTimer = 30000; } + else + m_uiTheBeastWithinTimer -= uiDiff; - //m_uiHurlTrident_Timer - if (m_uiHurlTrident_Timer < uiDiff) + if (m_uiMultiTossTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (!m_creature->IsWithinDist(pTarget,ATTACK_DISTANCE)) - DoCastSpellIfCan(pTarget, SPELL_HURL_TRIDENT); + if (DoCastSpellIfCan(pTarget, SPELL_HURL_TRIDENT) == CAST_OK) + m_uiMultiTossTimer = urand(7000, 12000); } - - m_uiHurlTrident_Timer = 5000; - }else m_uiHurlTrident_Timer -= uiDiff; - - //m_uiLeechingThrow_Timer - if (m_uiLeechingThrow_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_LEECHING_THROW); - m_uiLeechingThrow_Timer = 20000; - }else m_uiLeechingThrow_Timer -= uiDiff; - - //m_uiTheBeastWithin_Timer - if (m_uiTheBeastWithin_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_THE_BEAST_WITHIN); - m_uiTheBeastWithin_Timer = 30000; - }else m_uiTheBeastWithin_Timer -= uiDiff; + } + else + m_uiMultiTossTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Fathom-Guard Tidalvess AI -struct MANGOS_DLL_DECL boss_fathomguard_tidalvessAI : public Advisor_Base_AI +/*###### +## boss_fathomguard_tidalvess +######*/ + +struct MANGOS_DLL_DECL boss_fathomguard_tidalvessAI : public ScriptedAI { - boss_fathomguard_tidalvessAI(Creature* pCreature) : Advisor_Base_AI(pCreature) + boss_fathomguard_tidalvessAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiFrostShockTimer; + uint32 m_uiWindfuryTimer; + uint32 m_uiTotemTimer; + + void Reset() override { - Reset(); - m_uiAdvisor = DATA_TIDALVESS; + m_uiFrostShockTimer = 25000; + m_uiWindfuryTimer = 0; + m_uiTotemTimer = urand(2000, 5000); } - // timers - uint32 m_uiFrostShock_Timer; - - void Reset() + void JustDied(Unit* /*pKiller*/) override { - m_uiFrostShock_Timer = 25000; + DoCastSpellIfCan(m_creature, SPELL_POWER_OF_TIDALVESS, CAST_TRIGGERED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetData64(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 && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == NOT_STARTED) + 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_uiFrostShock_Timer - if (m_uiFrostShock_Timer < uiDiff) + if (m_uiTotemTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK); - m_uiFrostShock_Timer = urand(25000, 30000); - }else m_uiFrostShock_Timer -= uiDiff; + 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_uiTotemTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Fathom-Guard Caribdis AI -struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public Advisor_Base_AI +/*###### +## boss_fathomguard_caribdis +######*/ + +struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public ScriptedAI { - boss_fathomguard_caribdisAI(Creature* pCreature) : Advisor_Base_AI(pCreature) + boss_fathomguard_caribdisAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiWaterBoltVolleyTimer; + uint32 m_uiTidalSurgeTimer; + uint32 m_uiHealTimer; + uint32 m_uiCycloneTimer; + + void Reset() override { - Reset(); - m_uiAdvisor = DATA_CARIBDIS; + m_uiWaterBoltVolleyTimer = 35000; + m_uiTidalSurgeTimer = urand(15000, 20000); + m_uiHealTimer = 55000; + m_uiCycloneTimer = urand(10000, 15000); } - // timers - uint32 m_uiWaterBoltVolley_Timer; - uint32 m_uiTidalSurge_Timer; - uint32 m_uiHeal_Timer; + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_POWER_OF_CARIBDIS, CAST_TRIGGERED); + } - void Reset() + void JustSummoned(Creature* pSummoned) override { - m_uiWaterBoltVolley_Timer = 35000; - m_uiTidalSurge_Timer = urand(15000, 20000); - m_uiHeal_Timer = 55000; + // ToDo: research if this creature should follow the summoner or a random target + if (pSummoned->GetEntry() == NPC_CYCLONE) + pSummoned->CastSpell(pSummoned, SPELL_CYCLONE, 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()) - { - //check if the event is started - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetData64(DATA_KARATHRESS_STARTER))) - AttackStart(pTarget); - } return; - } - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == NOT_STARTED) + if (m_uiWaterBoltVolleyTimer < uiDiff) { - EnterEvadeMode(); - return; + if (DoCastSpellIfCan(m_creature, SPELL_WATER_BOLT_VOLLEY) == CAST_OK) + m_uiWaterBoltVolleyTimer = 30000; } + else + m_uiWaterBoltVolleyTimer -= uiDiff; - //m_uiWaterBoltVolley_Timer - if (m_uiWaterBoltVolley_Timer < uiDiff) + if (m_uiTidalSurgeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_WATER_BOLT_VOLLEY); - m_uiWaterBoltVolley_Timer = 30000; - }else m_uiWaterBoltVolley_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_TIDAL_SURGE) == CAST_OK) + m_uiTidalSurgeTimer = urand(15000, 20000); + } + else + m_uiTidalSurgeTimer -= uiDiff; - //m_uiTidalSurge_Timer - if (m_uiTidalSurge_Timer < uiDiff) + if (m_uiCycloneTimer < uiDiff) { - // the victim has to cast it on himself because in the spell.dbc the EffectImplicitTargetA1 is 1 (TARGET_SELF) - m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_TIDAL_SURGE, true); - m_uiTidalSurge_Timer = urand(15000, 20000); - }else m_uiTidalSurge_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_CYCLONE) == CAST_OK) + m_uiCycloneTimer = urand(45000, 60000); + } + else + m_uiCycloneTimer -= uiDiff; - //m_uiHeal_Timer - if (m_uiHeal_Timer < uiDiff) + if (m_uiHealTimer < uiDiff) { - // It can be cast on any of the mobs - Unit* pUnit = NULL; - - if (m_pInstance) + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - switch(urand(0, 3)) - { - case 0: pUnit = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_KARATHRESS)); break; - case 1: pUnit = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_SHARKKIS)); break; - case 2: pUnit = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_TIDALVESS)); break; - case 3: pUnit = m_creature; break; - } + if (DoCastSpellIfCan(pTarget, SPELL_HEALING_WAVE) == CAST_OK) + m_uiHealTimer = 60000; } - else - pUnit = m_creature; - - if (pUnit && pUnit->isAlive()) - DoCastSpellIfCan(pUnit, SPELL_HEAL); - - m_uiHeal_Timer = 60000; - }else m_uiHeal_Timer -= uiDiff; + } + else + m_uiHealTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -589,24 +490,25 @@ CreatureAI* GetAI_boss_fathomguard_caribdis(Creature* pCreature) void AddSC_boss_fathomlord_karathress() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_fathomlord_karathress"; - newscript->GetAI = &GetAI_boss_fathomlord_karathress; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_fathomguard_sharkkis"; - newscript->GetAI = &GetAI_boss_fathomguard_sharkkis; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_fathomguard_tidalvess"; - newscript->GetAI = &GetAI_boss_fathomguard_tidalvess; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_fathomguard_caribdis"; - newscript->GetAI = &GetAI_boss_fathomguard_caribdis; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_fathomlord_karathress"; + pNewScript->GetAI = &GetAI_boss_fathomlord_karathress; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_fathomguard_sharkkis"; + pNewScript->GetAI = &GetAI_boss_fathomguard_sharkkis; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_fathomguard_tidalvess"; + pNewScript->GetAI = &GetAI_boss_fathomguard_tidalvess; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_fathomguard_caribdis"; + pNewScript->GetAI = &GetAI_boss_fathomguard_caribdis; + pNewScript->RegisterSelf(); } 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 87be6e1756..d7f577b996 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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, }; +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 MANGOS_DLL_DECL 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); + } + } + } - m_uiVileSludge_Timer = 15000; - }else m_uiVileSludge_Timer -= uiDiff; + 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; + } - //PosCheck_Timer - if (m_uiPosCheck_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; + + // 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; - - 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(); } @@ -314,9 +362,10 @@ CreatureAI* GetAI_boss_hydross_the_unstable(Creature* pCreature) void AddSC_boss_hydross_the_unstable() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_hydross_the_unstable"; - newscript->GetAI = &GetAI_boss_hydross_the_unstable; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_hydross_the_unstable"; + pNewScript->GetAI = &GetAI_boss_hydross_the_unstable; + pNewScript->RegisterSelf(); } 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 f528de7919..9bddd235db 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,93 +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 { boss_lady_vashjAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - memset(&m_auiShieldGeneratorChannel, 0, sizeof(m_auiShieldGeneratorChannel)); + m_pInstance = (instance_serpentshrine_cavern*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance *m_pInstance; // the instance - - uint64 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] = 0; - } - } - } - - 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; @@ -200,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->GetGUID(); + 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; @@ -260,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); @@ -268,445 +244,247 @@ struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI m_pInstance->SetData(TYPE_LADYVASHJ_EVENT, DONE); } - void CastShootOrMultishot() + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LADYVASHJ_EVENT, FAIL); + } + + 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; + } + + // Wrapper to inform the boss that a generator has been deactivated + void DoInformGeneratorStopped() { - //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); + ++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()); - if (urand(0, 2)) - DoScriptText(urand(0,1) ? SAY_BOWSHOT1 : SAY_BOWSHOT2, m_creature); + m_uiPhase = PHASE_3; + m_uiRangedCheckTimer = 3000; + } } - 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_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 { - bool bInMeleeRange = false; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + // Cast Shoot or Multishot when nobody in melee range + if (m_uiRangedCheckTimer < uiDiff) { - Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - //if in melee range - if (pTarget && pTarget->IsWithinDistInMap(m_creature, ATTACK_DISTANCE)) - { - bInMeleeRange = true; - break; - } + if (CanCastShootOrMultishot()) + m_uiRangedCheckTimer = urand(1000, 2000); } - - //if nobody is in melee range - if (!bInMeleeRange) - CastShootOrMultishot(); - - m_uiCheck_Timer = 1500; - }else m_uiCheck_Timer -= uiDiff; + 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; + 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_TAINTED_ELEMENTAL - if (m_uiTaintedElemental_Timer < uiDiff) + if (m_uiEnchantedElementalTimer < 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); + 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); - m_uiTaintedElemental_Timer = 120000; - }else m_uiTaintedElemental_Timer -= uiDiff; + m_uiEnchantedElementalTimer = urand(5000, 10000); + } + else + m_uiEnchantedElementalTimer -= uiDiff; - //NPC_COILFANG_ELITE - if (m_uiCoilfangElite_Timer < uiDiff) + if (m_uiTaintedElementalTimer) { - 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); + if (m_uiTaintedElementalTimer <= uiDiff) + { + uint8 uiPos = urand(0, 7); - //wowwiki says 50 seconds, bosskillers says 45 - m_uiCoilfangElite_Timer = urand(45000, 50000); - }else m_uiCoilfangElite_Timer -= uiDiff; + 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; + } + else + m_uiTaintedElementalTimer -= uiDiff; + } - //NPC_COILFANG_STRIDER - if (m_uiCoilfangStrider_Timer < uiDiff) + if (m_uiCoilfangEliteTimer < 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, 2); - //wowwiki says 60 seconds, bosskillers says 60-70 - m_uiCoilfangStrider_Timer = urand(60000, 70000); - }else m_uiCoilfangStrider_Timer -= uiDiff; + 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; - //m_uiCheck_Timer - if (m_uiCheck_Timer < uiDiff) + if (m_uiCoilfangStriderTimer < uiDiff) { - //Start m_uiPhase 3 - if (m_pInstance && m_pInstance->GetData(TYPE_VASHJ_PHASE3_CHECK) == DONE) - { - DoScriptText(SAY_PHASE3, m_creature); + uint8 uiPos = urand(0, 2); - //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); - - //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_uiCheck_Timer = 1000; - }else m_uiCheck_Timer -= uiDiff; + 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; } } }; -//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(); } - ScriptedInstance *m_pInstance; // the instance + void Reset() override { } - void Reset() { } - - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (m_pInstance) - { - if (Creature* pVashj = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_LADYVASHJ))) - { - if (pVashj->IsWithinDistInMap(m_creature, ATTACK_DISTANCE)) - { - //increase lady vashj damage - if (pVashj->isAlive() && pVashj->isInCombat()) - m_creature->CastSpell(pVashj, SPELL_SURGE, false, 0, 0, pVashj->GetGUID()); - else - m_creature->SetDeathState(JUST_DIED); - } - } - } + // 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) { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } }; -//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 +bool GOUse_go_shield_generator(Player* /*pPlayer*/, GameObject* pGo) { - mob_tainted_elementalAI(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(); - SetCombatMovement(false); - Reset(); - } - - ScriptedInstance* m_pInstance; // the instance - - // timers - uint32 m_uiPoisonBolt_Timer; + if (Creature* pGenerator = GetClosestCreatureWithEntry(pGo, NPC_SHIELD_GENERATOR, 5.0f)) + pGenerator->InterruptNonMeleeSpells(false); - void Reset() - { - m_uiPoisonBolt_Timer = urand(5000, 10000); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //m_uiPoisonBolt_Timer - if (m_uiPoisonBolt_Timer < uiDiff) + if (Creature* pVashj = pInstance->GetSingleCreatureFromStorage(NPC_LADYVASHJ)) { - 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; - } -}; - -//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 -{ - mob_toxic_sporebatAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiToxicSpore_Timer; - uint32 m_uiCheck_Timer; - - 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) - { - //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_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_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 = pPlayer->GetMap()->GetCreature(pInstance->GetData64(DATA_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) @@ -719,51 +497,22 @@ 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 *newscript; - newscript = new Script; - newscript->Name = "boss_lady_vashj"; - newscript->GetAI = &GetAI_boss_lady_vashj; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_enchanted_elemental"; - newscript->GetAI = &GetAI_mob_enchanted_elemental; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_tainted_elemental"; - newscript->GetAI = &GetAI_mob_tainted_elemental; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_toxic_sporebat"; - newscript->GetAI = &GetAI_mob_toxic_sporebat; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_shield_generator_channel"; - newscript->GetAI = &GetAI_mob_shield_generator_channel; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "item_tainted_core"; - newscript->pItemUse = &ItemUse_item_tainted_core; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lady_vashj"; + pNewScript->GetAI = &GetAI_boss_lady_vashj; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_enchanted_elemental"; + pNewScript->GetAI = &GetAI_mob_enchanted_elemental; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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 426a341556..25a86aa514 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,83 +39,99 @@ 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 { boss_leotheras_the_blindAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_uiShadowLeo = 0; 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; - uint64 m_uiShadowLeo; + 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; @@ -123,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_uiShadowLeo = pSummoned->GetGUID(); 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_uiShadowLeo) - { - if (Creature* pShadowLeo = m_creature->GetMap()->GetCreature(m_uiShadowLeo)) - pShadowLeo->ForcedDespawn(); - } - if (m_pInstance) m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // 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); + // switch to nightelf form + m_creature->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS); - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - - //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; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->HandleEmote(EMOTE_ONESHOT_KNEEL); - if (!m_bDemonForm) - DoMeleeAttackIfReady(); - } -}; + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); -//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() { } - - void Aggro(Unit* pWho) - { - DoScriptText(SAY_FREE, m_creature); - } - - 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) @@ -321,22 +328,12 @@ 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_leotheras_the_blind"; - newscript->GetAI = &GetAI_boss_leotheras_the_blind; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_leotheras_the_blind_demonform"; - newscript->GetAI = &GetAI_boss_leotheras_the_blind_demonform; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_leotheras_the_blind"; + pNewScript->GetAI = &GetAI_boss_leotheras_the_blind; + 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 6a46a76874..7a525433be 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,11 +62,14 @@ 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 +static const uint32 m_auiSpellWateryGraveTeleport[] = { 37850, 38023, 38024, 38025 }; + struct MANGOS_DLL_DECL 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,190 +127,168 @@ 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); - - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && !pTarget->HasAuraType(SPELL_AURA_MOD_STUN) && pTarget->IsWithinDistInMap(m_creature, 45.0f)) - { - 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 { 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->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - { - 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() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_morogrim_tidewalker"; - newscript->GetAI = &GetAI_boss_morogrim_tidewalker; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_morogrim_tidewalker"; + pNewScript->GetAI = &GetAI_boss_morogrim_tidewalker; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_water_globule"; - newscript->GetAI = &GetAI_mob_water_globule; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_water_globule"; + pNewScript->GetAI = &GetAI_mob_water_globule; + pNewScript->RegisterSelf(); } 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 24a05a16a1..303347fa34 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,23 @@ 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, + + ACHIEVEMENT_LURKER = 144, }; enum Phases @@ -41,10 +53,23 @@ 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 +// Coords are guesswork +static const SPAWNLOCATION aLurkerLoc[MAX_SUBMERGE_ADDS] = +{ + {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 MANGOS_DLL_DECL boss_the_lurker_belowAI : public Scripted_NoMovementAI { - boss_the_lurker_belowAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_the_lurker_belowAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -53,60 +78,189 @@ struct MANGOS_DLL_DECL boss_the_lurker_belowAI : public ScriptedAI 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; + + DoResetCombatTimers(); + } - m_uiWhirlTimer = 19500; - m_uiGeyserTimer = 49700; + 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].m_uiEntry, aLurkerLoc[i].m_fX, aLurkerLoc[i].m_fY, aLurkerLoc[i].m_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; } } @@ -118,16 +272,17 @@ CreatureAI* GetAI_boss_the_lurker_below(Creature* pCreature) } // Cast the spell that should summon the Lurker-Below -bool GOHello_go_strange_pool(Player* pPlayer, GameObject* pGo) +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); + pPlayer->CompletedAchievement(ACHIEVEMENT_LURKER); pInstance->SetData(TYPE_THELURKER_EVENT, IN_PROGRESS); return true; } @@ -147,6 +302,6 @@ void AddSC_boss_the_lurker_below() pNewScript = new Script; pNewScript->Name = "go_strange_pool"; - pNewScript->pGOHello = &GOHello_go_strange_pool; + pNewScript->pGOUse = &GOUse_go_strange_pool; pNewScript->RegisterSelf(); } 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 73c21d2184..7d9a62220d 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -33,168 +33,221 @@ EndScriptData */ 5 - Lady Vashj Event */ -const int MAX_ENCOUNTER = 6; -const int MAX_GENERATOR = 4; - -struct MANGOS_DLL_DECL instance_serpentshrine_cavern : public ScriptedInstance +instance_serpentshrine_cavern::instance_serpentshrine_cavern(Map* pMap) : ScriptedInstance(pMap), + m_uiSpellBinderCount(0) { - instance_serpentshrine_cavern(Map* pMap) : ScriptedInstance(pMap) { Initialize(); }; - - uint64 m_uiSharkkis; - uint64 m_uiTidalvess; - uint64 m_uiCaribdis; - uint64 m_uiLadyVashj; - uint64 m_uiKarathress; - uint64 m_uiKarathressEvent_Starter; + Initialize(); +} - uint32 m_auiShieldGenerator[MAX_GENERATOR]; - uint32 m_auiEncounter[MAX_ENCOUNTER]; +void instance_serpentshrine_cavern::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +bool instance_serpentshrine_cavern::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_auiShieldGenerator, 0, sizeof(m_auiShieldGenerator)); - - m_uiSharkkis = 0; - m_uiTidalvess = 0; - m_uiCaribdis = 0; - m_uiLadyVashj = 0; - m_uiKarathress = 0; - m_uiKarathressEvent_Starter = 0; + if (m_auiEncounter[i] == IN_PROGRESS) + return true; } - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; + return false; +} - return false; +void instance_serpentshrine_cavern::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_LADYVASHJ: + 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 OnCreatureCreate(Creature* pCreature) +void instance_serpentshrine_cavern::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case 21212: m_uiLadyVashj = pCreature->GetGUID(); break; - case 21214: m_uiKarathress = pCreature->GetGUID(); break; - case 21966: m_uiSharkkis = pCreature->GetGUID(); break; - case 21965: m_uiTidalvess = pCreature->GetGUID(); break; - case 21964: m_uiCaribdis = pCreature->GetGUID(); break; - } + 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 SetData64(uint32 uiType, uint64 uiData) +void instance_serpentshrine_cavern::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - if (uiType == DATA_KARATHRESS_STARTER) - m_uiKarathressEvent_Starter = uiData; + case TYPE_HYDROSS_EVENT: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_LEOTHERAS_EVENT: + 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: + case TYPE_KARATHRESS_EVENT: + case TYPE_MOROGRIM_EVENT: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_LADYVASHJ_EVENT: + 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; } - uint64 GetData64(uint32 uiIdentifier) + if (uiData == DONE) { - switch(uiIdentifier) - { - case DATA_SHARKKIS: - return m_uiSharkkis; - case DATA_TIDALVESS: - return m_uiTidalvess; - case DATA_CARIBDIS: - return m_uiCaribdis; - case DATA_LADYVASHJ: - return m_uiLadyVashj; - case DATA_KARATHRESS: - return m_uiKarathress; - case DATA_KARATHRESS_STARTER: - return m_uiKarathressEvent_Starter; - } - return 0; + 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_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_serpentshrine_cavern::Load(const char* chrIn) +{ + if (!chrIn) { - switch(uiType) - { - case TYPE_HYDROSS_EVENT: - m_auiEncounter[0] = uiData; - break; - case TYPE_LEOTHERAS_EVENT: - m_auiEncounter[1] = uiData; - 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; - break; - case TYPE_LADYVASHJ_EVENT: - if (uiData == NOT_STARTED) - memset(&m_auiShieldGenerator, 0, sizeof(m_auiShieldGenerator)); - m_auiEncounter[5] = uiData; - break; - case TYPE_SHIELDGENERATOR1: - m_auiShieldGenerator[0] = uiData; - break; - case TYPE_SHIELDGENERATOR2: - m_auiShieldGenerator[1] = uiData; - break; - case TYPE_SHIELDGENERATOR3: - m_auiShieldGenerator[2] = uiData; - break; - case TYPE_SHIELDGENERATOR4: - m_auiShieldGenerator[3] = uiData; - break; - } + OUT_LOAD_INST_DATA_FAIL; + return; } - uint32 GetData(uint32 uiType) - { - switch(uiType) - { - case TYPE_HYDROSS_EVENT: - return m_auiEncounter[0]; + OUT_LOAD_INST_DATA(chrIn); - case TYPE_LEOTHERAS_EVENT: - return m_auiEncounter[1]; + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5]; - case TYPE_THELURKER_EVENT: - return m_auiEncounter[2]; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } - case TYPE_KARATHRESS_EVENT: - return m_auiEncounter[3]; + OUT_LOAD_INST_DATA_COMPLETE; +} - case TYPE_MOROGRIM_EVENT: - return m_auiEncounter[4]; +uint32 instance_serpentshrine_cavern::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - case TYPE_LADYVASHJ_EVENT: - return m_auiEncounter[5]; + return 0; +} - case TYPE_SHIELDGENERATOR1: - return m_auiShieldGenerator[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)); + } +} - case TYPE_SHIELDGENERATOR2: - return m_auiShieldGenerator[1]; +bool instance_serpentshrine_cavern::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource conditionSourceType) const +{ + switch (uiInstanceConditionId) + { + case INSTANCE_CONDITION_ID_LURKER: + return GetData(TYPE_THELURKER_EVENT) != DONE; + case INSTANCE_CONDITION_ID_SCALDING_WATER: + return m_sPlatformMobsAliveGUIDSet.empty(); + } - case TYPE_SHIELDGENERATOR3: - return m_auiShieldGenerator[2]; + 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; +} - case TYPE_SHIELDGENERATOR4: - return m_auiShieldGenerator[3]; +void instance_serpentshrine_cavern::OnCreatureEnterCombat(Creature* pCreature) +{ + // Interrupt spell casting on aggro + if (pCreature->GetEntry() == NPC_GREYHEART_SPELLBINDER) + pCreature->InterruptNonMeleeSpells(false); +} - case TYPE_VASHJ_PHASE3_CHECK: - for(uint8 i = 0; i < MAX_GENERATOR; ++i) +void instance_serpentshrine_cavern::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_GREYHEART_SPELLBINDER: + ++m_uiSpellBinderCount; + + if (m_uiSpellBinderCount == MAX_SPELLBINDERS) + { + if (Creature* pLeotheras = GetSingleCreatureFromStorage(NPC_LEOTHERAS)) { - if (m_auiShieldGenerator[i] != DONE) - return NOT_STARTED; + pLeotheras->RemoveAurasDueToSpell(SPELL_LEOTHERAS_BANISH); + pLeotheras->SetInCombatWithZone(); } - return DONE; - } - - 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; } -}; +} InstanceData* GetInstanceData_instance_serpentshrine_cavern(Map* pMap) { @@ -203,9 +256,10 @@ InstanceData* GetInstanceData_instance_serpentshrine_cavern(Map* pMap) void AddSC_instance_serpentshrine_cavern() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_serpent_shrine"; - newscript->GetInstanceData = &GetInstanceData_instance_serpentshrine_cavern; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_serpent_shrine"; + pNewScript->GetInstanceData = &GetInstanceData_instance_serpentshrine_cavern; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h b/scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h index 6d2b9f48e1..98c4a065fb 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,25 +7,90 @@ enum { - TYPE_HYDROSS_EVENT = 1, - TYPE_KARATHRESS_EVENT = 2, - TYPE_LADYVASHJ_EVENT = 3, - TYPE_LEOTHERAS_EVENT = 4, - TYPE_MOROGRIM_EVENT = 5, - TYPE_THELURKER_EVENT = 6, - - DATA_KARATHRESS_STARTER = 10, - DATA_KARATHRESS = 11, - DATA_CARIBDIS = 12, - DATA_SHARKKIS = 13, - DATA_TIDALVESS = 14, - - DATA_LADYVASHJ = 15, - TYPE_VASHJ_PHASE3_CHECK = 16, - - TYPE_SHIELDGENERATOR1 = 20, - TYPE_SHIELDGENERATOR2 = 21, - TYPE_SHIELDGENERATOR3 = 22, - TYPE_SHIELDGENERATOR4 = 23 + MAX_ENCOUNTER = 6, + MAX_SPELLBINDERS = 3, + + TYPE_HYDROSS_EVENT = 0, + TYPE_KARATHRESS_EVENT = 1, + TYPE_LADYVASHJ_EVENT = 2, + TYPE_LEOTHERAS_EVENT = 3, + TYPE_MOROGRIM_EVENT = 4, + TYPE_THELURKER_EVENT = 5, + + DATA_WATERSTATE_EVENT = 1, // DO NOT CHANGE! Used by Acid. - used to check the mobs for the water event. + + // 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 +{ + public: + instance_serpentshrine_cavern(Map* pMap); + + void Initialize() override; + bool IsEncounterInProgress() const override; + + 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) override; + uint32 GetData(uint32 uiType) const override; + + void SetData64(uint32 uiType, uint64 uiGuid) override; + + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource 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]; + std::string m_strInstData; + + 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 new file mode 100644 index 0000000000..5b37c2c532 --- /dev/null +++ b/scripts/outland/coilfang_reservoir/slave_pens/boss_ahune.cpp @@ -0,0 +1,412 @@ +/* Copyright (C) 2006 - 2013 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_ahune +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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 829e674ebb..1e4729e41b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Hydromancer_Thespia SD%Complete: 80 -SDComment: Needs additional adjustments (when instance script is adjusted) +SDComment: Timers may need small adjustments; Elementals summon needs further research SDCategory: Coilfang Resevoir, The Steamvault EndScriptData */ @@ -29,17 +29,22 @@ EndContentData */ #include "precompiled.h" #include "steam_vault.h" -#define SAY_SUMMON -1545000 -#define SAY_AGGRO_1 -1545001 -#define SAY_AGGRO_2 -1545002 -#define SAY_AGGRO_3 -1545003 -#define SAY_SLAY_1 -1545004 -#define SAY_SLAY_2 -1545005 -#define SAY_DEAD -1545006 - -#define SPELL_LIGHTNING_CLOUD 25033 -#define SPELL_LUNG_BURST 31481 -#define SPELL_ENVELOPING_WINDS 31718 +enum +{ + SAY_SUMMON = -1545000, + SAY_CLOUD = -1545024, + SAY_AGGRO_1 = -1545001, + SAY_AGGRO_2 = -1545002, + SAY_AGGRO_3 = -1545003, + SAY_SLAY_1 = -1545004, + SAY_SLAY_2 = -1545005, + SAY_DEAD = -1545006, + + SPELL_LIGHTNING_CLOUD = 25033, + SPELL_LUNG_BURST = 31481, + SPELL_ENVELOPING_WINDS = 31718, + SPELL_SUMMON_ELEMENTALS = 31476, // not sure where to use this +}; struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI { @@ -53,21 +58,24 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 LightningCloud_Timer; - uint32 LungBurst_Timer; - uint32 EnvelopingWinds_Timer; + uint32 m_uiLightningCloudTimer; + uint32 m_uiLungBurstTimer; + uint32 m_uiEnvelopingWindsTimer; - void Reset() + void Reset() override { - LightningCloud_Timer = 15000; - LungBurst_Timer = 7000; - EnvelopingWinds_Timer = 9000; + m_uiLightningCloudTimer = 15000; + m_uiLungBurstTimer = urand(15000, 18000); + m_uiEnvelopingWindsTimer = urand(20000, 25000); + } - if (m_pInstance && m_creature->isAlive()) - m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA,NOT_STARTED); + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA, FAIL); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEAD, m_creature); @@ -75,14 +83,14 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA, 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 { - 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; @@ -93,76 +101,50 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //LightningCloud_Timer - if (LightningCloud_Timer < diff) - { - //cast twice in Heroic mode - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_LIGHTNING_CLOUD); - if (!m_bIsRegularMode) - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_LIGHTNING_CLOUD); - LightningCloud_Timer = urand(15000, 25000); - }else LightningCloud_Timer -=diff; - - //LungBurst_Timer - if (LungBurst_Timer < diff) + // LightningCloud_Timer + if (m_uiLightningCloudTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_LUNG_BURST); - LungBurst_Timer = urand(7000, 12000); - }else LungBurst_Timer -=diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_LIGHTNING_CLOUD) == CAST_OK) + { + if (urand(0, 1)) + DoScriptText(SAY_CLOUD, m_creature); + m_uiLightningCloudTimer = m_bIsRegularMode ? 30000 : 10000; + } + } + } + else + m_uiLightningCloudTimer -= uiDiff; - //EnvelopingWinds_Timer - if (EnvelopingWinds_Timer < diff) + // LungBurst_Timer + if (m_uiLungBurstTimer < uiDiff) { - //cast twice in Heroic mode - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_ENVELOPING_WINDS); - if (!m_bIsRegularMode) - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_ENVELOPING_WINDS); - EnvelopingWinds_Timer = urand(10000, 15000); - }else EnvelopingWinds_Timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -#define SPELL_WATER_BOLT_VOLLEY 34449 -#define H_SPELL_WATER_BOLT_VOLLEY 37924 - -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 (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_LUNG_BURST) == CAST_OK) + m_uiLungBurstTimer = urand(7000, 12000); + } + } + else + m_uiLungBurstTimer -= uiDiff; - if (WaterBoltVolley_Timer < diff) + // EnvelopingWinds_Timer + if (m_uiEnvelopingWindsTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WATER_BOLT_VOLLEY : H_SPELL_WATER_BOLT_VOLLEY); - WaterBoltVolley_Timer = urand(7000, 12000); - }else WaterBoltVolley_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ENVELOPING_WINDS) == CAST_OK) + m_uiEnvelopingWindsTimer = m_bIsRegularMode ? 10000 : 15000; + } + } + else + m_uiEnvelopingWindsTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -173,22 +155,12 @@ 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_hydromancer_thespia"; - newscript->GetAI = &GetAI_boss_thespiaAI; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "mob_coilfang_waterelemental"; - newscript->GetAI = &GetAI_mob_coilfang_waterelementalAI; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_hydromancer_thespia"; + pNewScript->GetAI = &GetAI_boss_thespiaAI; + 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 138052a31d..3a6f582f08 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,22 +29,38 @@ 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 - -#define SPELL_SUPER_SHRINK_RAY 31485 -#define SPELL_SAW_BLADE 31486 -#define SPELL_ELECTRIFIED_NET 35107 -#define H_SPELL_ENRAGE 1 //corrent enrage spell not known +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 ENTRY_STREAMRIGGER_MECHANIC 17951 +// Spawn locations +static const EVENTLOCATION 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 { @@ -58,28 +74,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 +103,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 +113,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 +126,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); - - Saw_Blade_Timer = 15000; - } else Saw_Blade_Timer -= diff; + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - 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,13 +207,6 @@ CreatureAI* GetAI_boss_mekgineer_steamrigger(Creature* pCreature) return new boss_mekgineer_steamriggerAI(pCreature); } -#define SPELL_DISPEL_MAGIC 17201 -#define SPELL_REPAIR 31532 -#define H_SPELL_REPAIR 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 { mob_steamrigger_mechanicAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -209,48 +219,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->GetData64(DATA_MEKGINEERSTEAMRIGGER) && m_pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == IN_PROGRESS) + if (m_pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == IN_PROGRESS) { - if (Creature* pMekgineer = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_MEKGINEERSTEAMRIGGER))) - { - 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 : H_SPELL_REPAIR, 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; @@ -265,15 +272,15 @@ CreatureAI* GetAI_mob_steamrigger_mechanic(Creature* pCreature) void AddSC_boss_mekgineer_steamrigger() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_mekgineer_steamrigger"; - newscript->GetAI = &GetAI_boss_mekgineer_steamrigger; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_mekgineer_steamrigger"; + pNewScript->GetAI = &GetAI_boss_mekgineer_steamrigger; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_steamrigger_mechanic"; - newscript->GetAI = &GetAI_mob_steamrigger_mechanic; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_steamrigger_mechanic"; + pNewScript->GetAI = &GetAI_mob_steamrigger_mechanic; + pNewScript->RegisterSelf(); } 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 fad04fa8a0..151a1c7502 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,104 +16,68 @@ /* ScriptData SDName: Boss_Warlord_Kalithres -SD%Complete: 65 -SDComment: Contains workarounds regarding warlord's rage spells not acting as expected. Both scripts here require review and fine tuning. +SD%Complete: 90 +SDComment: Timers may need some fine adjustments SDCategory: Coilfang Resevoir, The Steamvault EndScriptData */ #include "precompiled.h" #include "steam_vault.h" -#define SAY_INTRO -1545016 -#define SAY_REGEN -1545017 -#define SAY_AGGRO1 -1545018 -#define SAY_AGGRO2 -1545019 -#define SAY_AGGRO3 -1545020 -#define SAY_SLAY1 -1545021 -#define SAY_SLAY2 -1545022 -#define SAY_DEATH -1545023 - -#define SPELL_SPELL_REFLECTION 31534 -#define SPELL_IMPALE 39061 -#define SPELL_WARLORDS_RAGE 37081 -#define SPELL_WARLORDS_RAGE_NAGA 31543 - -#define SPELL_WARLORDS_RAGE_PROC 36453 - -struct MANGOS_DLL_DECL mob_naga_distillerAI : public ScriptedAI +enum { - mob_naga_distillerAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - void Reset() - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - //hack, due to really weird spell behaviour :( - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_DISTILLER) == IN_PROGRESS) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - } - } - - void StartRageGen(Unit *caster) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - DoCastSpellIfCan(m_creature, SPELL_WARLORDS_RAGE_NAGA, CAST_TRIGGERED); - - if (m_pInstance) - m_pInstance->SetData(TYPE_DISTILLER,IN_PROGRESS); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (m_creature->GetHealth() <= damage) - if (m_pInstance) - m_pInstance->SetData(TYPE_DISTILLER,DONE); - } + SAY_INTRO = -1545016, + SAY_REGEN = -1545017, + SAY_AGGRO1 = -1545018, + SAY_AGGRO2 = -1545019, + SAY_AGGRO3 = -1545020, + SAY_SLAY1 = -1545021, + SAY_SLAY2 = -1545022, + SAY_DEATH = -1545023, + + SPELL_SPELL_REFLECTION = 31534, + SPELL_IMPALE = 39061, + SPELL_WARLORDS_RAGE = 37081, // triggers 36453 + SPELL_WARLORDS_RAGE_NAGA = 31543, // triggers 37076 }; struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI { boss_warlord_kalithreshAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_steam_vault*)pCreature->GetInstanceData(); + m_bHasTaunted = false; Reset(); } - ScriptedInstance* m_pInstance; + instance_steam_vault* m_pInstance; + + uint32 m_uiReflectionTimer; + uint32 m_uiImpaleTimer; + uint32 m_uiRageTimer; + uint32 m_uiRageCastTimer; + + ObjectGuid m_distillerGuid; - uint32 Reflection_Timer; - uint32 Impale_Timer; - uint32 Rage_Timer; - bool CanRage; + bool m_bHasTaunted; - void Reset() + void Reset() override { - Reflection_Timer = 10000; - Impale_Timer = urand(7000, 14000); - Rage_Timer = 45000; - CanRage = false; + m_uiReflectionTimer = 15000; + m_uiImpaleTimer = urand(7000, 14000); + m_uiRageTimer = urand(15000, 20000); + m_uiRageCastTimer = 0; + } + void JustReachedHome() override + { if (m_pInstance) - m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, NOT_STARTED); + m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, FAIL); } - void Aggro(Unit *who) + 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; @@ -124,21 +88,12 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, IN_PROGRESS); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void SpellHit(Unit *caster, const SpellEntry *spell) - { - //hack :( - if (spell->Id == SPELL_WARLORDS_RAGE_PROC) - if (m_pInstance) - if (m_pInstance->GetData(TYPE_DISTILLER) == DONE) - m_creature->RemoveAurasDueToSpell(SPELL_WARLORDS_RAGE_PROC); - } - - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -146,65 +101,152 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, DONE); } - void UpdateAI(const uint32 diff) + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 40.0f)) + { + DoScriptText(SAY_INTRO, m_creature); + m_bHasTaunted = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // There is a small delay between the point reach and the channeling start + m_uiRageCastTimer = 1000; + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Rage_Timer < diff) + if (m_uiRageCastTimer) { - if (Creature* pDistiller = GetClosestCreatureWithEntry(m_creature, 17954, 100.0f)) + if (m_uiRageCastTimer <= uiDiff) { - DoScriptText(SAY_REGEN, m_creature); - DoCastSpellIfCan(m_creature,SPELL_WARLORDS_RAGE); - - if (mob_naga_distillerAI* pDistillerAI = dynamic_cast(pDistiller->AI())) - pDistillerAI->StartRageGen(m_creature); + if (DoCastSpellIfCan(m_creature, SPELL_WARLORDS_RAGE) == CAST_OK) + { + DoScriptText(SAY_REGEN, m_creature); + SetCombatMovement(true); + m_uiRageCastTimer = 0; + + // Also make the distiller cast + if (Creature* pDistiller = m_creature->GetMap()->GetCreature(m_distillerGuid)) + { + pDistiller->CastSpell(pDistiller, SPELL_WARLORDS_RAGE_NAGA, true); + pDistiller->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } } - Rage_Timer = urand(3000, 18000); - }else Rage_Timer -= diff; + else + m_uiRageCastTimer -= uiDiff; + } - //Reflection_Timer - if (Reflection_Timer < diff) + // Move to closest distiller + if (m_uiRageTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SPELL_REFLECTION); - Reflection_Timer = urand(15000, 25000); - }else Reflection_Timer -= diff; + 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); + } + else + m_uiRageTimer -= uiDiff; - //Impale_Timer - if (Impale_Timer < diff) + // Reflection_Timer + if (m_uiReflectionTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_IMPALE); + if (DoCastSpellIfCan(m_creature, SPELL_SPELL_REFLECTION) == CAST_OK) + m_uiReflectionTimer = 30000; + } + else + m_uiReflectionTimer -= uiDiff; - Impale_Timer = urand(7500, 12500); - }else Impale_Timer -= diff; + // Impale_Timer + if (m_uiImpaleTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_IMPALE) == CAST_OK) + m_uiImpaleTimer = urand(7500, 12500); + } + } + else + m_uiImpaleTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_mob_naga_distiller(Creature* pCreature) +bool EffectAuraDummy_spell_aura_dummy_warlord_rage(const Aura* pAura, bool bApply) { - return new mob_naga_distillerAI(pCreature); + if (pAura->GetId() == SPELL_WARLORDS_RAGE && pAura->GetEffIndex() == EFFECT_INDEX_0) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + // Resume combat when the cast is finished or interrupted + if (!bApply) + { + if (pTarget->getVictim()) + { + pTarget->GetMotionMaster()->MovementExpired(); + pTarget->GetMotionMaster()->MoveChase(pTarget->getVictim()); + } + } + } + } + + return true; } +struct MANGOS_DLL_DECL mob_naga_distillerAI : public Scripted_NoMovementAI +{ + mob_naga_distillerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + CreatureAI* GetAI_boss_warlord_kalithresh(Creature* pCreature) { return new boss_warlord_kalithreshAI(pCreature); } -void AddSC_boss_warlord_kalithresh() +CreatureAI* GetAI_mob_naga_distiller(Creature* pCreature) { - Script *newscript; - - newscript = new Script; - newscript->Name = "mob_naga_distiller"; - newscript->GetAI = &GetAI_mob_naga_distiller; - newscript->RegisterSelf(); + return new mob_naga_distillerAI(pCreature); +} - newscript = new Script; - newscript->Name = "boss_warlord_kalithresh"; - newscript->GetAI = &GetAI_boss_warlord_kalithresh; - newscript->RegisterSelf(); +void AddSC_boss_warlord_kalithresh() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_warlord_kalithresh"; + pNewScript->GetAI = &GetAI_boss_warlord_kalithresh; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_warlord_rage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_naga_distiller"; + pNewScript->GetAI = &GetAI_mob_naga_distiller; + pNewScript->RegisterSelf(); } 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 db2492543a..ccdbdc6631 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,164 +24,168 @@ EndScriptData */ #include "precompiled.h" #include "steam_vault.h" -#define MAX_ENCOUNTER 4 - -#define MAIN_CHAMBERS_DOOR 183049 -#define ACCESS_PANEL_HYDRO 184125 -#define ACCESS_PANEL_MEK 184126 - /* Steam Vaults encounters: 1 - Hydromancer Thespia Event 2 - Mekgineer Steamrigger Event 3 - Warlord Kalithresh Event */ -bool GOHello_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; - - if (pGo->GetEntry() == ACCESS_PANEL_HYDRO && pInstance->GetData(TYPE_HYDROMANCER_THESPIA) == DONE) - pInstance->SetData(TYPE_HYDROMANCER_THESPIA,SPECIAL); + return true; - if (pGo->GetEntry() == ACCESS_PANEL_MEK && pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == DONE) - pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER,SPECIAL); + if (pGo->GetEntry() == GO_ACCESS_PANEL_HYDRO) + pInstance->SetData(TYPE_HYDROMANCER_THESPIA, SPECIAL); + else if (pGo->GetEntry() == GO_ACCESS_PANEL_MEK) + pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, SPECIAL); - return true; + return false; } -struct MANGOS_DLL_DECL instance_steam_vault : public ScriptedInstance +instance_steam_vault::instance_steam_vault(Map* pMap) : ScriptedInstance(pMap) { - instance_steam_vault(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint64 m_uiThespiaGUID; - uint64 m_uiMekgineerGUID; - uint64 m_uiKalithreshGUID; - - uint64 m_uiMainChambersDoor; - uint64 m_uiAccessPanelHydro; - uint64 m_uiAccessPanelMek; + Initialize(); +} - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiThespiaGUID = 0; - m_uiMekgineerGUID = 0; - m_uiKalithreshGUID = 0; - m_uiMainChambersDoor = 0; - m_uiAccessPanelHydro = 0; - m_uiAccessPanelMek = 0; - } +void instance_steam_vault::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - bool IsEncounterInProgress() const +void instance_steam_vault::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; + 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 OnCreatureCreate(Creature* pCreature) +void instance_steam_vault::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case 17797: m_uiThespiaGUID = pCreature->GetGUID(); break; - case 17796: m_uiMekgineerGUID = pCreature->GetGUID(); break; - case 17798: m_uiKalithreshGUID = pCreature->GetGUID(); break; - } + 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: + 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 OnObjectCreate(GameObject* pGo) +void instance_steam_vault::OnCreatureDeath(Creature* pCreature) +{ + // Break the Warlord spell on the Distiller death + if (pCreature->GetEntry() == NPC_NAGA_DISTILLER) { - switch(pGo->GetEntry()) - { - case MAIN_CHAMBERS_DOOR: m_uiMainChambersDoor = pGo->GetGUID(); break; - case ACCESS_PANEL_HYDRO: m_uiAccessPanelHydro = pGo->GetGUID(); break; - case ACCESS_PANEL_MEK: m_uiAccessPanelMek = pGo->GetGUID(); break; - } + if (Creature* pWarlord = GetSingleCreatureFromStorage(NPC_KALITHRESH)) + pWarlord->InterruptNonMeleeSpells(false); } +} - void SetData(uint32 type, uint32 data) +void instance_steam_vault::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(type) - { - case TYPE_HYDROMANCER_THESPIA: - if (data == SPECIAL) + case TYPE_HYDROMANCER_THESPIA: + if (uiData == DONE) + DoToggleGameObjectFlags(GO_ACCESS_PANEL_HYDRO, GO_FLAG_NO_INTERACT, false); + if (uiData == SPECIAL) + { + if (GetData(TYPE_MEKGINEER_STEAMRIGGER) == SPECIAL) + DoUseDoorOrButton(GO_MAIN_CHAMBERS_DOOR); + } + 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) + { + if (GetData(TYPE_HYDROMANCER_THESPIA) == SPECIAL) + DoUseDoorOrButton(GO_MAIN_CHAMBERS_DOOR); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_WARLORD_KALITHRESH: + 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 (GameObject* pGo = instance->GetGameObject(m_uiAccessPanelHydro)) - pGo->SetGoState(GO_STATE_ACTIVE); - - if (GetData(TYPE_MEKGINEER_STEAMRIGGER) == SPECIAL) + if (Creature* pDistiller = instance->GetCreature(*itr)) { - if (GameObject* pGo = instance->GetGameObject(m_uiMainChambersDoor)) - pGo->SetGoState(GO_STATE_ACTIVE); + if (!pDistiller->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + pDistiller->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - - debug_log("SD2: Instance Steamvault: Access panel used."); } - m_auiEncounter[0] = data; - break; - case TYPE_MEKGINEER_STEAMRIGGER: - if (data == SPECIAL) - { - if (GameObject* pGo = instance->GetGameObject(m_uiAccessPanelMek)) - pGo->SetGoState(GO_STATE_ACTIVE); + } + m_auiEncounter[uiType] = uiData; + break; + } - if (GetData(TYPE_HYDROMANCER_THESPIA) == SPECIAL) - { - if (GameObject* pGo = instance->GetGameObject(m_uiMainChambersDoor)) - pGo->SetGoState(GO_STATE_ACTIVE); - } + if (uiData == DONE || uiData == SPECIAL) + { + OUT_SAVE_INST_DATA; - debug_log("SD2: Instance Steamvault: Access panel used."); - } - m_auiEncounter[1] = data; - break; - case TYPE_WARLORD_KALITHRESH: - m_auiEncounter[2] = data; - break; - case TYPE_DISTILLER: - m_auiEncounter[3] = data; - break; - } + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - uint32 GetData(uint32 type) +uint32 instance_steam_vault::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_steam_vault::Load(const char* chrIn) +{ + if (!chrIn) { - switch(type) - { - case TYPE_HYDROMANCER_THESPIA: - return m_auiEncounter[0]; - case TYPE_MEKGINEER_STEAMRIGGER: - return m_auiEncounter[1]; - case TYPE_WARLORD_KALITHRESH: - return m_auiEncounter[2]; - case TYPE_DISTILLER: - return m_auiEncounter[3]; - } - return 0; + OUT_LOAD_INST_DATA_FAIL; + return; } - uint64 GetData64(uint32 data) + 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) { - switch(data) - { - case DATA_THESPIA: - return m_uiThespiaGUID; - case DATA_MEKGINEERSTEAMRIGGER: - return m_uiMekgineerGUID; - case DATA_KALITRESH: - return m_uiKalithreshGUID; - } - return 0; + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } -}; + + OUT_LOAD_INST_DATA_COMPLETE; +} InstanceData* GetInstanceData_instance_steam_vault(Map* pMap) { @@ -190,15 +194,15 @@ InstanceData* GetInstanceData_instance_steam_vault(Map* pMap) void AddSC_instance_steam_vault() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "go_main_chambers_access_panel"; - newscript->pGOHello = &GOHello_go_main_chambers_access_panel; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_main_chambers_access_panel"; + pNewScript->pGOUse = &GOUse_go_main_chambers_access_panel; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "instance_steam_vault"; - newscript->GetInstanceData = &GetInstanceData_instance_steam_vault; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "instance_steam_vault"; + pNewScript->GetInstanceData = &GetInstanceData_instance_steam_vault; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h b/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h index fea0b997eb..6da760241f 100644 --- a/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h +++ b/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h @@ -1,16 +1,51 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef DEF_STEAM_VAULT_H #define DEF_STEAM_VAULT_H -#define TYPE_HYDROMANCER_THESPIA 1 -#define TYPE_MEKGINEER_STEAMRIGGER 2 -#define TYPE_WARLORD_KALITHRESH 3 -#define TYPE_DISTILLER 4 +enum +{ + MAX_ENCOUNTER = 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, + + GO_MAIN_CHAMBERS_DOOR = 183049, + GO_ACCESS_PANEL_HYDRO = 184125, + GO_ACCESS_PANEL_MEK = 184126, +}; + +class MANGOS_DLL_DECL instance_steam_vault : public ScriptedInstance +{ + public: + instance_steam_vault(Map* pMap); + + 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; + + private: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + GuidList m_lNagaDistillerGuidList; +}; -#define DATA_MEKGINEERSTEAMRIGGER 5 -#define DATA_KALITRESH 6 -#define DATA_THESPIA 7 #endif diff --git a/scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp b/scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp index b4c7476856..0d84293077 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,15 +16,26 @@ /* ScriptData SDName: Boss_Hungarfen -SD%Complete: 95 -SDComment: Need confirmation if spell data are same in both modes. Summons should have faster rate in heroic +SD%Complete: 80 +SDComment: Need confirmation if spell data are same in both modes; The Underbog Mushroom may need some more research SDCategory: Coilfang Resevoir, Underbog EndScriptData */ #include "precompiled.h" -#define SPELL_FOUL_SPORES 31673 -#define SPELL_ACID_GEYSER 38739 +enum +{ + SPELL_FOUL_SPORES = 31673, + SPELL_ACID_GEYSER = 38739, + SPELL_DESPAWN_MUSHROOMS = 34874, + + // Mushroom spells + SPELL_SPORE_CLOUD = 34168, + SPELL_PUTRID_MUSHROOM = 31690, + SPELL_GROW = 31698, + + NPC_UNDERBOG_MUSHROOM = 17990, +}; struct MANGOS_DLL_DECL boss_hungarfenAI : public ScriptedAI { @@ -35,100 +46,129 @@ struct MANGOS_DLL_DECL boss_hungarfenAI : public ScriptedAI } bool m_bIsRegularMode; - bool Root; - uint32 Mushroom_Timer; - uint32 AcidGeyser_Timer; + bool m_bHasSpores; + uint32 m_uiMushroomTimer; + uint32 m_uiAcidGeyserTimer; + + 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_uiAcidGeyserTimer = 10000; + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_DESPAWN_MUSHROOMS, CAST_TRIGGERED); + } - void Reset() + void JustReachedHome() override { - Root = false; - Mushroom_Timer = 5000; // 1 mushroom after 5s, then one per 10s. This should be different in heroic mode - AcidGeyser_Timer = 10000; + DoCastSpellIfCan(m_creature, SPELL_DESPAWN_MUSHROOMS, CAST_TRIGGERED); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->GetHealthPercent() <= 20.0f) + if (m_creature->GetHealthPercent() <= 20.0f && !m_bHasSpores) { - if (!Root) - { - DoCastSpellIfCan(m_creature,SPELL_FOUL_SPORES); - Root = true; - } + if (DoCastSpellIfCan(m_creature, SPELL_FOUL_SPORES) == CAST_OK) + m_bHasSpores = true; } - if (Mushroom_Timer < diff) + if (m_uiMushroomTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - m_creature->SummonCreature(17990, target->GetPositionX()+(rand()%8), target->GetPositionY()+(rand()%8), target->GetPositionZ(), (rand()%5), TEMPSUMMON_TIMED_DESPAWN, 22000); - else - m_creature->SummonCreature(17990, m_creature->GetPositionX()+(rand()%8), m_creature->GetPositionY()+(rand()%8), m_creature->GetPositionZ(), (rand()%5), TEMPSUMMON_TIMED_DESPAWN, 22000); + // Summon a mushroom exactly on target position + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->SummonCreature(NPC_UNDERBOG_MUSHROOM, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - Mushroom_Timer = 10000; - }else Mushroom_Timer -= diff; + m_uiMushroomTimer = m_bIsRegularMode ? 10000 : 5000; + } + else + m_uiMushroomTimer -= uiDiff; - if (AcidGeyser_Timer < diff) + if (m_uiAcidGeyserTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_ACID_GEYSER); - AcidGeyser_Timer = urand(10000, 17500); - }else AcidGeyser_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ACID_GEYSER) == CAST_OK) + m_uiAcidGeyserTimer = urand(10000, 17500); + } + } + else + m_uiAcidGeyserTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_hungarfen(Creature* pCreature) { return new boss_hungarfenAI(pCreature); } -#define SPELL_SPORE_CLOUD 34168 -#define SPELL_PUTRID_MUSHROOM 31690 -#define SPELL_GROW 31698 - struct MANGOS_DLL_DECL mob_underbog_mushroomAI : public ScriptedAI { mob_underbog_mushroomAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool Stop; - uint32 Grow_Timer; - uint32 Shrink_Timer; + uint32 m_uiGrowTimer; + uint32 m_uiShrinkTimer; + uint32 m_uiSporeTimer; - void Reset() + void Reset() override { - Stop = false; - Grow_Timer = 0; - Shrink_Timer = 20000; + m_uiGrowTimer = 1000; + m_uiSporeTimer = 15000; + m_uiShrinkTimer = 20000; - DoCastSpellIfCan(m_creature, SPELL_PUTRID_MUSHROOM, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_SPORE_CLOUD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PUTRID_MUSHROOM); } - void MoveInLineOfSight(Unit *who) { return; } - - void AttackStart(Unit* who) { return; } + void MoveInLineOfSight(Unit* /*pWho*/) override { return; } + void AttackStart(Unit* /*pWho*/) override { return; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (Stop) - return; + if (m_uiSporeTimer) + { + if (m_uiSporeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SPORE_CLOUD) == CAST_OK) + { + m_uiGrowTimer = 0; + m_uiSporeTimer = 0; + } + } + else + m_uiSporeTimer -= uiDiff; + } - if (Grow_Timer <= diff) + if (m_uiGrowTimer) { - DoCastSpellIfCan(m_creature,SPELL_GROW); - Grow_Timer = 3000; - }else Grow_Timer -= diff; + if (m_uiGrowTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GROW) == CAST_OK) + m_uiGrowTimer = 3000; + } + else + m_uiGrowTimer -= uiDiff; + } - if (Shrink_Timer <= diff) + if (m_uiShrinkTimer) { - m_creature->RemoveAurasDueToSpell(SPELL_GROW); - Stop = true; - }else Shrink_Timer -= diff; + if (m_uiShrinkTimer <= uiDiff) + { + m_creature->RemoveAurasDueToSpell(SPELL_GROW); + m_uiShrinkTimer = 0; + } + else + m_uiShrinkTimer -= uiDiff; + } } }; + CreatureAI* GetAI_mob_underbog_mushroom(Creature* pCreature) { return new mob_underbog_mushroomAI(pCreature); @@ -136,15 +176,15 @@ CreatureAI* GetAI_mob_underbog_mushroom(Creature* pCreature) void AddSC_boss_hungarfen() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_hungarfen"; - newscript->GetAI = &GetAI_boss_hungarfen; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_hungarfen"; + pNewScript->GetAI = &GetAI_boss_hungarfen; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_underbog_mushroom"; - newscript->GetAI = &GetAI_mob_underbog_mushroom; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_underbog_mushroom"; + pNewScript->GetAI = &GetAI_mob_underbog_mushroom; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/gruuls_lair/boss_gruul.cpp b/scripts/outland/gruuls_lair/boss_gruul.cpp index 75181490b2..89b19872d6 100644 --- a/scripts/outland/gruuls_lair/boss_gruul.cpp +++ b/scripts/outland/gruuls_lair/boss_gruul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -40,16 +40,16 @@ 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 @@ -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,47 +106,45 @@ 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->GetGUID()); break; - case 1: pTarget->CastSpell(pTarget, SPELL_KNOCK_BACK, true, NULL, NULL, m_creature->GetGUID()); break; + 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; } } } - //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,71 +192,56 @@ struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI else { // Hurtful Strike - if (m_uiHurtfulStrike_Timer < uiDiff) + if (m_uiHurtfulStrikeTimer < uiDiff) { - // Find 2nd-aggro target within melee range. - Unit *pTarget = NULL; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - ThreatList::const_iterator itr = tList.begin(); - std::advance(itr, 1); - for (;itr != tList.end(); ++itr) - { - pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - // exclude pets, totems & player out of melee range - if (pTarget->GetTypeId() != TYPEID_PLAYER || !pTarget->IsWithinDist(m_creature, ATTACK_DISTANCE, false)) - { - pTarget = NULL; - continue; - } - //we've found someone - break; - } - - if (pTarget) - DoCastSpellIfCan(pTarget,SPELL_HURTFUL_STRIKE); + 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); + 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; @@ -275,9 +258,10 @@ CreatureAI* GetAI_boss_gruul(Creature* pCreature) void AddSC_boss_gruul() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_gruul"; - newscript->GetAI = &GetAI_boss_gruul; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_gruul"; + pNewScript->GetAI = &GetAI_boss_gruul; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp b/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp index 1ecdeeed28..273392629e 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -50,82 +50,63 @@ 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; - -//High King Maulgar AI +// High King Maulgar AI struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI { boss_high_king_maulgarAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - memset(&m_auiCouncil, 0, sizeof(m_auiCouncil)); Reset(); } 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; - uint64 m_auiCouncil[MAX_COUNCIL]; // Council GUIDs - - 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 { - for (uint8 i = 0; i < MAX_COUNCIL; ++i) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_auiCouncil[i])) - { - if (!pCreature->isAlive()) - pCreature->Respawn(); - else if (pCreature->getVictim()) - pCreature->AI()->EnterEvadeMode(); - } - } - - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_MAULGAR_EVENT, NOT_STARTED); + if (m_pInstance) + m_pInstance->SetData(TYPE_MAULGAR_EVENT, FAIL); } - void KilledUnit() + 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; @@ -133,47 +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; - - GetCouncil(); - DoScriptText(SAY_AGGRO, m_creature); - m_creature->CallForHelp(50.0f); - - if (m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) + if (m_pInstance) m_pInstance->SetData(TYPE_MAULGAR_EVENT, IN_PROGRESS); } - void GetCouncil() - { - if (!m_pInstance) - return; - - //get council member's guid to respawn them if needed - m_auiCouncil[0] = m_pInstance->GetData64(DATA_KIGGLER); - m_auiCouncil[1] = m_pInstance->GetData64(DATA_BLINDEYE); - m_auiCouncil[2] = m_pInstance->GetData64(DATA_OLM); - m_auiCouncil[3] = m_pInstance->GetData64(DATA_KROSH); - } - 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; @@ -182,75 +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; - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) + if (m_uiArcingSmashTimer < uiDiff) { - EnterEvadeMode(); - return; - } - - //m_uiArcingSmash_Timer - if (m_uiArcingSmash_Timer < 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(); @@ -267,114 +216,91 @@ struct MANGOS_DLL_DECL Council_Base_AI : public ScriptedAI ScriptedInstance* m_pInstance; - void JustReachedHome() - { - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_MAULGAR_EVENT, NOT_STARTED); - } - - void Aggro(Unit *pWho) - { - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) - m_pInstance->SetData(TYPE_MAULGAR_EVENT, IN_PROGRESS); - - m_creature->CallForHelp(50.0f); - } - - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { if (!m_pInstance) return; - Creature* pMaulgar = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_MAULGAR)); - - if (pMaulgar->isAlive()) + Creature* pMaulgar = m_pInstance->GetSingleCreatureFromStorage(NPC_MAULGAR); + if (pMaulgar && pMaulgar->isAlive()) { 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 +// Olm The Summoner AI struct MANGOS_DLL_DECL 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; - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) + if (m_uiDarkDecayTimer < uiDiff) { - EnterEvadeMode(); - return; - } - - //m_uiDarkDecay_Timer - if (m_uiDarkDecay_Timer < 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 +// Kiggler The Crazed AI struct MANGOS_DLL_DECL 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: @@ -383,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; @@ -398,140 +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; - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) - { - EnterEvadeMode(); - 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 +// Blindeye The Seer AI struct MANGOS_DLL_DECL 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; - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) + if (m_uiGreaterPowerWordShieldTimer < uiDiff) { - EnterEvadeMode(); - return; - } - - //m_uiGreaterPowerWordShield_Timer - if (m_uiGreaterPowerWordShield_Timer < 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 +// Krosh Firehand AI struct MANGOS_DLL_DECL 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; @@ -542,48 +451,38 @@ 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; - //someone evaded! - if (m_pInstance && m_pInstance->GetData(TYPE_MAULGAR_EVENT) == NOT_STARTED) - { - EnterEvadeMode(); - 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) { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin(); i != tList.end(); ++i) + GuidVector vGuids; + m_creature->FillGuidsListFromThreatList(vGuids); + for (GuidVector::const_iterator i = vGuids.begin(); i != vGuids.end(); ++i) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); + Unit* pUnit = m_creature->GetMap()->GetUnit(*i); if (pUnit && pUnit->IsWithinDistInMap(m_creature, 15.0f)) { @@ -592,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; } }; @@ -609,47 +508,47 @@ 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); } void AddSC_boss_high_king_maulgar() { - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_high_king_maulgar"; - newscript->GetAI = &GetAI_boss_high_king_maulgar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_kiggler_the_crazed"; - newscript->GetAI = &GetAI_boss_kiggler_the_crazed; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_blindeye_the_seer"; - newscript->GetAI = &GetAI_boss_blindeye_the_seer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_olm_the_summoner"; - newscript->GetAI = &GetAI_boss_olm_the_summoner; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_krosh_firehand"; - newscript->GetAI = &GetAI_boss_krosh_firehand; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_high_king_maulgar"; + pNewScript->GetAI = &GetAI_boss_high_king_maulgar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_kiggler_the_crazed"; + pNewScript->GetAI = &GetAI_boss_kiggler_the_crazed; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_blindeye_the_seer"; + pNewScript->GetAI = &GetAI_boss_blindeye_the_seer; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_olm_the_summoner"; + pNewScript->GetAI = &GetAI_boss_olm_the_summoner; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_krosh_firehand"; + pNewScript->GetAI = &GetAI_boss_krosh_firehand; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/gruuls_lair/gruuls_lair.h b/scripts/outland/gruuls_lair/gruuls_lair.h index 34cdf26755..9dbab6c36a 100644 --- a/scripts/outland/gruuls_lair/gruuls_lair.h +++ b/scripts/outland/gruuls_lair/gruuls_lair.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,17 +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 - DATA_MAULGAR = 3, - DATA_BLINDEYE = 4, - DATA_KIGGLER = 5, - DATA_KROSH = 6, - DATA_OLM = 7 + NPC_MAULGAR = 18831, + // NPC_BLINDEYE = 18836, + // NPC_KIGGLER = 18835, + // NPC_KROSH = 18832, + // NPC_OLM = 18834, +}; + +class MANGOS_DLL_DECL instance_gruuls_lair : public ScriptedInstance +{ + public: + instance_gruuls_lair(Map* pMap); + + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + 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 449a186de3..b620907ab1 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,149 +29,117 @@ EndScriptData */ 2 - Gruul event */ -struct MANGOS_DLL_DECL instance_gruuls_lair : public ScriptedInstance +instance_gruuls_lair::instance_gruuls_lair(Map* pMap) : ScriptedInstance(pMap), + m_uiCouncilMembersDied(0) { - instance_gruuls_lair(Map *pMap) : ScriptedInstance(pMap) {Initialize();} - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strSaveData; - - uint64 m_uiMaulgarGUID; - uint64 m_uiKigglerGUID; - uint64 m_uiBlindeyeGUID; - uint64 m_uiOlmGUID; - uint64 m_uiKroshGUID; - uint64 m_uiMaulgarDoorGUID; - uint64 m_uiGruulEncounterDoorGUID; - - void Initialize() - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + Initialize(); +} - m_uiMaulgarGUID = 0; - m_uiKigglerGUID = 0; - m_uiBlindeyeGUID = 0; - m_uiOlmGUID = 0; - m_uiKroshGUID = 0; +void instance_gruuls_lair::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - m_uiMaulgarDoorGUID = 0; - m_uiGruulEncounterDoorGUID = 0; - } +bool instance_gruuls_lair::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + return true; - bool IsEncounterInProgress() const - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; + return false; +} - return false; - } +void instance_gruuls_lair::OnCreatureCreate(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_MAULGAR) + m_mNpcEntryGuidStore[NPC_MAULGAR] = pCreature->GetObjectGuid(); +} - void OnCreatureCreate(Creature* pCreature) +void instance_gruuls_lair::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch (pCreature->GetEntry()) - { - case 18831: m_uiMaulgarGUID = pCreature->GetGUID(); break; - case 18832: m_uiKroshGUID = pCreature->GetGUID(); break; - case 18834: m_uiOlmGUID = pCreature->GetGUID(); break; - case 18835: m_uiKigglerGUID = pCreature->GetGUID(); break; - case 18836: m_uiBlindeyeGUID = pCreature->GetGUID(); break; - } + case GO_PORT_GRONN_1: + if (m_auiEncounter[TYPE_MAULGAR_EVENT] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_PORT_GRONN_2: + break; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) +void instance_gruuls_lair::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch (pGo->GetEntry()) - { - case 184468: - m_uiMaulgarDoorGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); + 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; - case 184662: - m_uiGruulEncounterDoorGUID = pGo->GetGUID(); - break; - } + } + if (uiData == FAIL) + m_uiCouncilMembersDied = 0; + if (uiData == DONE) + DoUseDoorOrButton(GO_PORT_GRONN_1); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_GRUUL_EVENT: + DoUseDoorOrButton(GO_PORT_GRONN_2); + m_auiEncounter[uiType] = uiData; + break; } - void SetData(uint32 uiType, uint32 uiData) + if (uiData == DONE) { - switch (uiType) - { - case TYPE_MAULGAR_EVENT: - if (uiData == DONE) - DoUseDoorOrButton(m_uiMaulgarDoorGUID); - m_auiEncounter[0] = uiData; - break; - case TYPE_GRUUL_EVENT: - DoUseDoorOrButton(m_uiGruulEncounterDoorGUID); - m_auiEncounter[1] = uiData; - break; - } + OUT_SAVE_INST_DATA; - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; + m_strSaveData = saveStream.str(); - strSaveData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - const char* Save() - { - return strSaveData.c_str(); - } +uint32 instance_gruuls_lair::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - uint32 GetData(uint32 uiType) - { - switch (uiType) - { - case TYPE_MAULGAR_EVENT: return m_auiEncounter[0]; - case TYPE_GRUUL_EVENT: return m_auiEncounter[1]; - } - return 0; - } + return 0; +} - uint64 GetData64(uint32 uiData) +void instance_gruuls_lair::Load(const char* chrIn) +{ + if (!chrIn) { - switch (uiData) - { - case DATA_MAULGAR: return m_uiMaulgarGUID; - case DATA_BLINDEYE: return m_uiBlindeyeGUID; - case DATA_KIGGLER: return m_uiKigglerGUID; - case DATA_KROSH: return m_uiKroshGUID; - case DATA_OLM: return m_uiOlmGUID; - } - return 0; + OUT_LOAD_INST_DATA_FAIL; + return; } - void Load(const char* chrIn) - { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } + OUT_LOAD_INST_DATA(chrIn); - OUT_LOAD_INST_DATA(chrIn); + std::istringstream loadStream(chrIn); - std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - - OUT_LOAD_INST_DATA_COMPLETE; - } -}; + OUT_LOAD_INST_DATA_COMPLETE; +} InstanceData* GetInstanceData_instance_gruuls_lair(Map* pMap) { @@ -180,9 +148,10 @@ InstanceData* GetInstanceData_instance_gruuls_lair(Map* pMap) void AddSC_instance_gruuls_lair() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_gruuls_lair"; - newscript->GetInstanceData = &GetInstanceData_instance_gruuls_lair; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_gruuls_lair"; + pNewScript->GetInstanceData = &GetInstanceData_instance_gruuls_lair; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h b/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h index 2041214b5d..e5db040987 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,6 +7,20 @@ enum { + MAX_ENCOUNTER = 3, + MAX_ORC_WAVES = 4, + + TYPE_THE_MAKER_EVENT = 0, + TYPE_BROGGOK_EVENT = 1, + TYPE_KELIDAN_EVENT = 2, + + // NPC_THE_MAKER = 17381, + NPC_BROGGOK = 17380, + NPC_KELIDAN_THE_BREAKER = 17377, + NPC_NASCENT_FEL_ORC = 17398, // Used in the Broggok event + NPC_MAGTHERIDON = 21174, + NPC_SHADOWMOON_CHANNELER = 17653, + GO_DOOR_FINAL_EXIT = 181766, GO_DOOR_MAKER_FRONT = 181811, GO_DOOR_MAKER_REAR = 181812, @@ -14,22 +28,72 @@ enum GO_DOOR_BROGGOK_REAR = 181819, GO_DOOR_KELIDAN_EXIT = 181823, - DATA_THE_MAKER = 1, - DATA_BROGGOK = 2, - DATA_KELIDAN_THE_MAKER = 3, - - TYPE_THE_MAKER_EVENT = 4, - TYPE_BROGGOK_EVENT = 5, - TYPE_KELIDAN_EVENT = 6, - - DATA_PRISON_CELL_MAKER1 = 10, - DATA_PRISON_CELL_MAKER2 = 11, - DATA_PRISON_CELL_MAKER3 = 12, - DATA_PRISON_CELL_MAKER4 = 13, - DATA_PRISON_CELL_BROGGOK1 = 14, - DATA_PRISON_CELL_BROGGOK2 = 15, - DATA_PRISON_CELL_BROGGOK3 = 16, - DATA_PRISON_CELL_BROGGOK4 = 17 + // GO_PRISON_CELL_MAKER1 = 181813, // The maker cell front right + // GO_PRISON_CELL_MAKER2 = 181814, // The maker cell back right + // GO_PRISON_CELL_MAKER3 = 181816, // The maker cell front left + // GO_PRISON_CELL_MAKER4 = 181815, // The maker cell back left + + GO_PRISON_CELL_BROGGOK_1 = 181817, // Broggok cell back left (NE) + GO_PRISON_CELL_BROGGOK_2 = 181818, // Broggok cell back right (SE) + GO_PRISON_CELL_BROGGOK_3 = 181820, // Broggok cell front left (NW) + GO_PRISON_CELL_BROGGOK_4 = 181821, // Broggok cell front right (SW) + + 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) {} + + ObjectGuid m_cellGuid; + bool m_bIsCellOpened; + uint8 m_uiKilledOrcCount; + GuidSet m_sSortedOrcGuids; +}; + +class MANGOS_DLL_DECL instance_blood_furnace : public ScriptedInstance +{ + public: + instance_blood_furnace(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void Update(uint32 uiDiff) override; + + 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(); } + + private: + void DoSortBroggokOrcs(); + void DoNextBroggokEventPhase(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + BroggokEventInfo m_aBroggokEvent[MAX_ORC_WAVES]; + + 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; }; #endif diff --git a/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp b/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp index fc9bb71e70..2e12f42994 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,87 +29,126 @@ enum SAY_AGGRO = -1542008, SPELL_SLIME_SPRAY = 30913, - H_SPELL_SLIME_SPRAY = 38458, + SPELL_SLIME_SPRAY_H = 38458, SPELL_POISON_CLOUD = 30916, SPELL_POISON_BOLT = 30917, - H_SPELL_POISON_BOLT = 38459, + SPELL_POISON_BOLT_H = 38459, - SPELL_POISON = 30914 + SPELL_POISON = 30914, + + POINT_EVENT_COMBAT = 1, }; struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI { boss_broggokAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_blood_furnace*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_blood_furnace* m_pInstance; bool m_bIsRegularMode; - uint32 AcidSpray_Timer; - uint32 PoisonSpawn_Timer; - uint32 PoisonBolt_Timer; + uint32 m_uiAcidSprayTimer; + uint32 m_uiPoisonSpawnTimer; + uint32 m_uiPoisonBoltTimer; - void Reset() + void Reset() override { - AcidSpray_Timer = 10000; - PoisonSpawn_Timer = 5000; - PoisonBolt_Timer = 7000; + m_uiAcidSprayTimer = 10000; + m_uiPoisonSpawnTimer = 5000; + m_uiPoisonBoltTimer = 7000; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) - m_pInstance->SetData(TYPE_BROGGOK_EVENT,IN_PROGRESS); + m_pInstance->SetData(TYPE_BROGGOK_EVENT, IN_PROGRESS); } - void JustReachedHome() + void JustSummoned(Creature* pSummoned) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_BROGGOK_EVENT,FAIL); + // ToDo: set correct flags and data in DB!!! + pSummoned->setFaction(16); + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pSummoned->CastSpell(pSummoned, SPELL_POISON, false, NULL, NULL, m_creature->GetObjectGuid()); } - void JustSummoned(Creature *summoned) + void JustDied(Unit* /*pWho*/) override { - summoned->setFaction(16); - summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - summoned->CastSpell(summoned,SPELL_POISON,false,0,0,m_creature->GetGUID()); + if (m_pInstance) + m_pInstance->SetData(TYPE_BROGGOK_EVENT, DONE); } - void JustDied(Unit *who) + 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_pInstance) - m_pInstance->SetData(TYPE_BROGGOK_EVENT,DONE); + { + float dx, dy; + float fRespX, fRespY, fRespZ; + m_creature->GetRespawnCoord(fRespX, fRespY, fRespZ); + m_pInstance->GetMovementDistanceForIndex(4, dx, dy); + m_creature->GetMotionMaster()->MovePoint(POINT_EVENT_COMBAT, dx, dy, fRespZ); + } + else + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + // Reset Orientation + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_EVENT_COMBAT) + return; + + if (GameObject* pFrontDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_DOOR_BROGGOK_FRONT)) + m_creature->SetFacingToObject(pFrontDoor); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (AcidSpray_Timer < diff) + if (m_uiAcidSprayTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? H_SPELL_SLIME_SPRAY : SPELL_SLIME_SPRAY); - AcidSpray_Timer = urand(4000, 12000); - }else AcidSpray_Timer -=diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SLIME_SPRAY : SPELL_SLIME_SPRAY_H) == CAST_OK) + m_uiAcidSprayTimer = urand(4000, 12000); + } + else + m_uiAcidSprayTimer -= uiDiff; - if (PoisonBolt_Timer < diff) + if (m_uiPoisonBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? H_SPELL_POISON_BOLT : SPELL_POISON_BOLT); - PoisonBolt_Timer = urand(4000, 12000); - }else PoisonBolt_Timer -=diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_POISON_BOLT : SPELL_POISON_BOLT_H) == CAST_OK) + m_uiPoisonBoltTimer = urand(4000, 12000); + } + else + m_uiPoisonBoltTimer -= uiDiff; - if (PoisonSpawn_Timer < diff) + if (m_uiPoisonSpawnTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_POISON_CLOUD); - PoisonSpawn_Timer = 20000; - }else PoisonSpawn_Timer -=diff; + if (DoCastSpellIfCan(m_creature, SPELL_POISON_CLOUD) == CAST_OK) + m_uiPoisonSpawnTimer = 20000; + } + else + m_uiPoisonSpawnTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -119,9 +158,9 @@ struct MANGOS_DLL_DECL 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) @@ -136,14 +175,15 @@ CreatureAI* GetAI_mob_broggok_poisoncloud(Creature* pCreature) void AddSC_boss_broggok() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_broggok"; - newscript->GetAI = &GetAI_boss_broggok; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_broggok_poisoncloud"; - newscript->GetAI = &GetAI_mob_broggok_poisoncloud; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_broggok"; + pNewScript->GetAI = &GetAI_boss_broggok; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_broggok_poisoncloud"; + pNewScript->GetAI = &GetAI_mob_broggok_poisoncloud; + pNewScript->RegisterSelf(); } 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 5c7216d295..d8ee525814 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Kelidan_The_Breaker -SD%Complete: 60 -SDComment: Event with channeleres vs. boss not implemented yet +SD%Complete: 100 +SDComment: SDCategory: Hellfire Citadel, Blood Furnace EndScriptData */ @@ -31,6 +31,9 @@ EndContentData */ enum { + MAX_ADDS = 5, + + SAY_MAGTHERIDON_INTRO = -1542016, // Yell by Magtheridon SAY_WAKE = -1542000, SAY_ADD_AGGRO_1 = -1542001, SAY_ADD_AGGRO_2 = -1542002, @@ -41,50 +44,84 @@ enum SAY_DIE = -1542007, SPELL_CORRUPTION = 30938, + SPELL_EVOCATION = 30935, SPELL_FIRE_NOVA = 33132, - H_SPELL_FIRE_NOVA = 37371, + SPELL_FIRE_NOVA_H = 37371, SPELL_SHADOW_BOLT_VOLLEY = 28599, - H_SPELL_SHADOW_BOLT_VOLLEY = 40070, + SPELL_SHADOW_BOLT_VOLLEY_H = 40070, SPELL_BURNING_NOVA = 30940, - SPELL_VORTEX = 37370 + SPELL_VORTEX = 37370, + + SPELL_CHANNELING = 39123, +}; + +struct SortByAngle +{ + SortByAngle(WorldObject const* pRef): m_pRef(pRef) {} + bool operator()(WorldObject* pLeft, WorldObject* pRight) + { + return m_pRef->GetAngle(pLeft) < m_pRef->GetAngle(pRight); + } + WorldObject const* m_pRef; }; struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI { boss_kelidan_the_breakerAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_blood_furnace*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_uiSetupAddsTimer = 100; + m_bDidMagtheridonYell = false; + DoCastSpellIfCan(m_creature, SPELL_EVOCATION); Reset(); } - ScriptedInstance* m_pInstance; + instance_blood_furnace* m_pInstance; bool m_bIsRegularMode; - uint32 ShadowVolley_Timer; - uint32 BurningNova_Timer; - uint32 Firenova_Timer; - uint32 Corruption_Timer; - bool Firenova; + uint32 m_uiShadowVolleyTimer; + uint32 m_uiBurningNovaTimer; + uint32 m_uiFirenovaTimer; + uint32 m_uiCorruptionTimer; + uint32 m_uiSetupAddsTimer; + uint8 m_uiKilledAdds; + bool m_bDidMagtheridonYell; + + GuidVector m_vAddGuids; - void Reset() + void Reset() override { - ShadowVolley_Timer = 1000; - BurningNova_Timer = 15000; - Corruption_Timer = 5000; - Firenova = false; + m_uiShadowVolleyTimer = 1000; + m_uiBurningNovaTimer = 15000; + m_uiCorruptionTimer = 5000; + m_uiFirenovaTimer = 0; + m_uiKilledAdds = 0; } - void Aggro(Unit *who) + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bDidMagtheridonYell && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->_IsWithinDist(pWho, 73.0f, false)) + { + if (m_pInstance) + m_pInstance->DoOrSimulateScriptTextForThisInstance(SAY_MAGTHERIDON_INTRO, NPC_MAGTHERIDON); + + m_bDidMagtheridonYell = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_WAKE, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -92,59 +129,153 @@ 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* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); if (m_pInstance) - m_pInstance->SetData(TYPE_KELIDAN_EVENT,DONE); + m_pInstance->SetData(TYPE_KELIDAN_EVENT, DONE); } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_pInstance) + m_pInstance->SetData(TYPE_KELIDAN_EVENT, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_EVOCATION); + m_uiSetupAddsTimer = 2000; + } + + void DoSetupAdds() + { + m_uiSetupAddsTimer = 0; + + if (!m_pInstance) return; - if (Firenova) + GuidList lAddGuids; + m_pInstance->GetKelidanAddList(lAddGuids); + + // Sort Adds to vector if not already done + if (!lAddGuids.empty()) { - if (Firenova_Timer < diff) + m_vAddGuids.reserve(lAddGuids.size()); + std::list lAdds; + for (GuidList::const_iterator itr = lAddGuids.begin(); itr != lAddGuids.end(); ++itr) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FIRE_NOVA : H_SPELL_FIRE_NOVA); - Firenova = false; - ShadowVolley_Timer = 2000; - }else Firenova_Timer -=diff; + if (Creature* pAdd = m_pInstance->instance->GetCreature(*itr)) + lAdds.push_back(pAdd); + } + // Sort them by angle + lAdds.sort(SortByAngle(m_creature)); + for (std::list::const_iterator itr = lAdds.begin(); itr != lAdds.end(); ++itr) + m_vAddGuids.push_back((*itr)->GetObjectGuid()); + } - return; + // Respawn killed adds and reset counter + m_uiKilledAdds = 0; + for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) + { + Creature* pAdd = m_pInstance->instance->GetCreature(*itr); + if (pAdd && !pAdd->isAlive()) + pAdd->Respawn(); + } + + // Cast pentagram + uint8 s = m_vAddGuids.size(); + for (uint8 i = 0; i < s; ++i) + { + Creature* pCaster = m_pInstance->instance->GetCreature(m_vAddGuids[i]); + Creature* pTarget = m_pInstance->instance->GetCreature(m_vAddGuids[(i + 2) % s]); + if (pCaster && pTarget) + pCaster->CastSpell(pTarget, SPELL_CHANNELING, false); + } + } + + void AddJustAggroed(Unit* pWho) + { + // Let all adds attack + for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) + { + Creature* pAdd = m_creature->GetMap()->GetCreature(*itr); + if (pAdd && !pAdd->getVictim()) + pAdd->AI()->AttackStart(pWho); + } + } + + void AddJustReachedHome() + { + m_uiSetupAddsTimer = 2000; + } + + void AddJustDied(Unit* pKiller) + { + ++m_uiKilledAdds; + if (m_uiKilledAdds == MAX_ADDS) + { + m_creature->InterruptNonMeleeSpells(true); + AttackStart(pKiller); } + } - if (ShadowVolley_Timer < diff) + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSetupAddsTimer) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_BOLT_VOLLEY : H_SPELL_SHADOW_BOLT_VOLLEY); - ShadowVolley_Timer = urand(5000, 13000); - }else ShadowVolley_Timer -=diff; + if (m_uiSetupAddsTimer <= uiDiff) + DoSetupAdds(); + else + m_uiSetupAddsTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - if (Corruption_Timer < diff) + if (m_uiFirenovaTimer) { - DoCastSpellIfCan(m_creature,SPELL_CORRUPTION); - Corruption_Timer = urand(30000, 50000); - }else Corruption_Timer -=diff; + if (m_uiFirenovaTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FIRE_NOVA : SPELL_FIRE_NOVA_H) == CAST_OK) + { + m_uiFirenovaTimer = 0; + m_uiShadowVolleyTimer = 2000; + } + } + else + m_uiFirenovaTimer -= uiDiff; + } - if (BurningNova_Timer < diff) + if (m_uiShadowVolleyTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_BOLT_VOLLEY : SPELL_SHADOW_BOLT_VOLLEY_H) == CAST_OK) + m_uiShadowVolleyTimer = urand(5000, 13000); + } + else + m_uiShadowVolleyTimer -= uiDiff; - DoScriptText(SAY_NOVA, m_creature); + if (m_uiCorruptionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CORRUPTION) == CAST_OK) + m_uiCorruptionTimer = urand(30000, 50000); + } + else + m_uiCorruptionTimer -= uiDiff; - if (!m_bIsRegularMode) - DoCastSpellIfCan(m_creature, SPELL_VORTEX); + if (m_uiBurningNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BURNING_NOVA, CAST_TRIGGERED) == CAST_OK) + { + DoScriptText(SAY_NOVA, m_creature); - DoCastSpellIfCan(m_creature,SPELL_BURNING_NOVA); + if (!m_bIsRegularMode) + DoCastSpellIfCan(m_creature, SPELL_VORTEX, CAST_TRIGGERED); - BurningNova_Timer = urand(20000, 28000); - Firenova_Timer= 5000; - Firenova = true; - }else BurningNova_Timer -=diff; + m_uiBurningNovaTimer = urand(20000, 28000); + m_uiFirenovaTimer = 5000; + } + } + else + m_uiBurningNovaTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -162,12 +293,10 @@ CreatureAI* GetAI_boss_kelidan_the_breaker(Creature* pCreature) enum { SPELL_SHADOW_BOLT = 12739, - H_SPELL_SHADOW_BOLT = 15472, + SPELL_SHADOW_BOLT_H = 15472, SPELL_MARK_OF_SHADOW = 30937, - - SPELL_CHANNELING = 0 //initial spell channeling boss/each other not known -}; //when engaged all channelers must stop, trigger yell (SAY_ADD_AGGRO_*), and engage. +}; struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI { @@ -181,37 +310,86 @@ struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 ShadowBolt_Timer; - uint32 MarkOfShadow_Timer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiMarkOfShadowTimer; - void Reset() + void Reset() override { - ShadowBolt_Timer = urand(1000, 2000); - MarkOfShadow_Timer = urand(5000, 7000); + m_uiShadowBoltTimer = urand(1000, 2000); + m_uiMarkOfShadowTimer = urand(5000, 7000); } - void Aggro(Unit* who) + void Aggro(Unit* pWho) override { - //trigger boss to yell + m_creature->InterruptNonMeleeSpells(false); + + switch (urand(0, 2)) + { + case 0: + DoScriptText(SAY_ADD_AGGRO_1, m_creature); + break; + case 1: + DoScriptText(SAY_ADD_AGGRO_2, m_creature); + break; + case 2: + DoScriptText(SAY_ADD_AGGRO_3, m_creature); + break; + } + + if (!m_pInstance) + return; + + if (Creature* pKelidan = m_pInstance->GetSingleCreatureFromStorage(NPC_KELIDAN_THE_BREAKER)) + if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast(pKelidan->AI())) + pKelidanAI->AddJustAggroed(pWho); + } + + 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())) + pKelidanAI->AddJustDied(pKiller); + } + + 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())) + pKelidanAI->AddJustReachedHome(); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (MarkOfShadow_Timer < diff) + if (m_uiMarkOfShadowTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target,SPELL_MARK_OF_SHADOW); - MarkOfShadow_Timer = urand(15000, 20000); - }else MarkOfShadow_Timer -=diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MARK_OF_SHADOW) == CAST_OK) + m_uiMarkOfShadowTimer = urand(15000, 20000); + } + } + else + m_uiMarkOfShadowTimer -= uiDiff; - if (ShadowBolt_Timer < diff) + if (m_uiShadowBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_BOLT : H_SPELL_SHADOW_BOLT); - ShadowBolt_Timer = urand(5000, 6000); - }else ShadowBolt_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 = urand(5000, 6000); + } + } + else + m_uiShadowBoltTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -224,15 +402,15 @@ CreatureAI* GetAI_mob_shadowmoon_channeler(Creature* pCreature) void AddSC_boss_kelidan_the_breaker() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_kelidan_the_breaker"; - newscript->GetAI = &GetAI_boss_kelidan_the_breaker; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_kelidan_the_breaker"; + pNewScript->GetAI = &GetAI_boss_kelidan_the_breaker; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_shadowmoon_channeler"; - newscript->GetAI = &GetAI_mob_shadowmoon_channeler; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_shadowmoon_channeler"; + pNewScript->GetAI = &GetAI_mob_shadowmoon_channeler; + pNewScript->RegisterSelf(); } 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 6b13dcac2d..3730f06fbd 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -35,9 +35,9 @@ enum SPELL_ACID_SPRAY = 38153, // heroic 38973 ??? 38153 SPELL_EXPLODING_BREAKER = 30925, - H_SPELL_EXPLODING_BREAKER = 40059, + SPELL_EXPLODING_BREAKER_H = 40059, SPELL_KNOCKDOWN = 20276, - SPELL_DOMINATION = 25772 // ??? + SPELL_DOMINATION = 30923 }; struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI @@ -52,22 +52,22 @@ struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 AcidSpray_Timer; - uint32 ExplodingBreaker_Timer; - uint32 Domination_Timer; - uint32 Knockdown_Timer; + uint32 m_uiAcidSprayTimer; + uint32 m_uiExplodingBreakerTimer; + uint32 m_uiDominationTimer; + uint32 m_uiKnockdownTimer; - void Reset() + void Reset() override { - AcidSpray_Timer = 15000; - ExplodingBreaker_Timer = 6000; - Domination_Timer = 20000; - Knockdown_Timer = 10000; + m_uiAcidSprayTimer = 15000; + m_uiExplodingBreakerTimer = 6000; + m_uiDominationTimer = 20000; + m_uiKnockdownTimer = 10000; } - 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; @@ -75,61 +75,70 @@ struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI } if (m_pInstance) - m_pInstance->SetData(TYPE_THE_MAKER_EVENT,IN_PROGRESS); + 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); + m_pInstance->SetData(TYPE_THE_MAKER_EVENT, FAIL); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); if (m_pInstance) - m_pInstance->SetData(TYPE_THE_MAKER_EVENT,DONE); + m_pInstance->SetData(TYPE_THE_MAKER_EVENT, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (AcidSpray_Timer < diff) + if (m_uiAcidSprayTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ACID_SPRAY); - AcidSpray_Timer = urand(15000, 23000); - }else AcidSpray_Timer -=diff; + if (DoCastSpellIfCan(m_creature, SPELL_ACID_SPRAY) == CAST_OK) + m_uiAcidSprayTimer = urand(15000, 23000); + } + else + m_uiAcidSprayTimer -= uiDiff; - if (ExplodingBreaker_Timer < diff) + if (m_uiExplodingBreakerTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? H_SPELL_EXPLODING_BREAKER : SPELL_EXPLODING_BREAKER); - ExplodingBreaker_Timer = urand(4000, 12000); - }else ExplodingBreaker_Timer -=diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_EXPLODING_BREAKER : SPELL_EXPLODING_BREAKER_H) == CAST_OK) + m_uiExplodingBreakerTimer = urand(4000, 12000); + } + } + else + m_uiExplodingBreakerTimer -= uiDiff; - if (Domination_Timer < diff) + if (m_uiDominationTimer < uiDiff) { - Unit* target; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - - DoCastSpellIfCan(target,SPELL_DOMINATION); - - Domination_Timer = 15000+rand()%10000; - }else Domination_Timer -=diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DOMINATION) == CAST_OK) + m_uiDominationTimer = urand(15000, 25000); + } + } + else + m_uiDominationTimer -= uiDiff; - if (Knockdown_Timer < diff) + if (m_uiKnockdownTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKDOWN); - Knockdown_Timer = urand(4000, 12000); - }else Knockdown_Timer -=diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KNOCKDOWN) == CAST_OK) + m_uiKnockdownTimer = urand(4000, 12000); + } + else + m_uiKnockdownTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -142,9 +151,10 @@ CreatureAI* GetAI_boss_the_makerAI(Creature* pCreature) void AddSC_boss_the_maker() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_the_maker"; - newscript->GetAI = &GetAI_boss_the_makerAI; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_the_maker"; + pNewScript->GetAI = &GetAI_boss_the_makerAI; + pNewScript->RegisterSelf(); } 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 70f36a38d2..1c9d0cb4fa 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,233 +24,400 @@ EndScriptData */ #include "precompiled.h" #include "blood_furnace.h" -#define MAX_ENCOUNTER 3 +instance_blood_furnace::instance_blood_furnace(Map* pMap) : ScriptedInstance(pMap), + m_uiBroggokEventTimer(30000), + m_uiBroggokEventPhase(0), + m_uiRandYellTimer(90000) +{ + Initialize(); +} -struct MANGOS_DLL_DECL instance_blood_furnace : public ScriptedInstance +void instance_blood_furnace::Initialize() { - instance_blood_furnace(Map* pMap) : ScriptedInstance(pMap) {Initialize();} - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strInstData; - - uint64 m_uiMakerGUID; - uint64 m_uiBroggokGUID; - uint64 m_uiKelidanGUID; - - uint64 m_uiDoorFinalExitGUID; - uint64 m_uiDoorMakerFrontGUID; - uint64 m_uiDoorMakerRearGUID; - uint64 m_uiDoorBroggokFrontGUID; - uint64 m_uiDoorBrokkokRearGUID; - uint64 m_uiDoorKelidanExitGUID; - - uint64 m_uiPrisonCell1GUID; - uint64 m_uiPrisonCell2GUID; - uint64 m_uiPrisonCell3GUID; - uint64 m_uiPrisonCell4GUID; - uint64 m_uiPrisonCell5GUID; - uint64 m_uiPrisonCell6GUID; - uint64 m_uiPrisonCell7GUID; - uint64 m_uiPrisonCell8GUID; - - void Initialize() + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +void instance_blood_furnace::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiMakerGUID = 0; - m_uiBroggokGUID = 0; - m_uiKelidanGUID = 0; - - m_uiDoorFinalExitGUID = 0; - m_uiDoorMakerFrontGUID = 0; - m_uiDoorMakerRearGUID = 0; - m_uiDoorBroggokFrontGUID = 0; - m_uiDoorBrokkokRearGUID = 0; - m_uiDoorKelidanExitGUID = 0; - - m_uiPrisonCell1GUID = 0; - m_uiPrisonCell2GUID = 0; - m_uiPrisonCell3GUID = 0; - m_uiPrisonCell4GUID = 0; - m_uiPrisonCell5GUID = 0; - m_uiPrisonCell6GUID = 0; - m_uiPrisonCell7GUID = 0; - m_uiPrisonCell8GUID = 0; + case NPC_BROGGOK: + case NPC_KELIDAN_THE_BREAKER: + case NPC_MAGTHERIDON: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + case NPC_NASCENT_FEL_ORC: + m_luiNascentOrcGuids.push_back(pCreature->GetObjectGuid()); + break; + case NPC_SHADOWMOON_CHANNELER: + m_lChannelersGuids.push_back(pCreature->GetObjectGuid()); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_blood_furnace::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pCreature->GetEntry()) - { - case 17381: m_uiMakerGUID = pCreature->GetGUID(); break; - case 17380: m_uiBroggokGUID = pCreature->GetGUID(); break; - case 17377: m_uiKelidanGUID = pCreature->GetGUID(); break; - } + case GO_DOOR_MAKER_FRONT: // the maker front door + break; + case GO_DOOR_MAKER_REAR: // the maker rear door + if (m_auiEncounter[TYPE_THE_MAKER_EVENT] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOOR_BROGGOK_FRONT: // broggok front door + break; + case GO_DOOR_BROGGOK_REAR: // broggok rear door + if (m_auiEncounter[TYPE_BROGGOK_EVENT] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOOR_KELIDAN_EXIT: // kelidan exit door + if (m_auiEncounter[TYPE_KELIDAN_EVENT] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOOR_FINAL_EXIT: // final exit door + if (m_auiEncounter[TYPE_KELIDAN_EVENT] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + + case GO_PRISON_CELL_BROGGOK_1: m_aBroggokEvent[0].m_cellGuid = pGo->GetObjectGuid(); return; + case GO_PRISON_CELL_BROGGOK_2: m_aBroggokEvent[1].m_cellGuid = pGo->GetObjectGuid(); return; + case GO_PRISON_CELL_BROGGOK_3: m_aBroggokEvent[2].m_cellGuid = pGo->GetObjectGuid(); return; + case GO_PRISON_CELL_BROGGOK_4: m_aBroggokEvent[3].m_cellGuid = pGo->GetObjectGuid(); return; + + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void OnObjectCreate(GameObject* pGo) +void instance_blood_furnace::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch (pGo->GetEntry()) - { - case GO_DOOR_MAKER_FRONT: //the maker front door - m_uiDoorMakerFrontGUID = pGo->GetGUID(); - break; - case GO_DOOR_MAKER_REAR: //the maker rear door - m_uiDoorMakerRearGUID = pGo->GetGUID(); - if (m_auiEncounter[0] == DONE && pGo->GetGoState() == GO_STATE_READY) - DoUseDoorOrButton(m_uiDoorMakerRearGUID); - break; - case GO_DOOR_BROGGOK_FRONT: //broggok front door - m_uiDoorBroggokFrontGUID = pGo->GetGUID(); - break; - case GO_DOOR_BROGGOK_REAR: //broggok rear door - m_uiDoorBrokkokRearGUID = pGo->GetGUID(); - if (m_auiEncounter[1] == DONE && pGo->GetGoState() == GO_STATE_READY) - DoUseDoorOrButton(m_uiDoorBrokkokRearGUID); - break; - case GO_DOOR_KELIDAN_EXIT: //kelidan exit door - m_uiDoorKelidanExitGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE && pGo->GetGoState() == GO_STATE_READY) - DoUseDoorOrButton(m_uiDoorKelidanExitGUID); - break; - case GO_DOOR_FINAL_EXIT: //final exit door - m_uiDoorFinalExitGUID = pGo->GetGUID(); - if (m_auiEncounter[2] == DONE && pGo->GetGoState() == GO_STATE_READY) - DoUseDoorOrButton(m_uiDoorFinalExitGUID); - break; - case 181813: m_uiPrisonCell1GUID = pGo->GetGUID(); break;//the maker cell front right - case 181814: m_uiPrisonCell2GUID = pGo->GetGUID(); break;//the maker cell back right - case 181816: m_uiPrisonCell3GUID = pGo->GetGUID(); break;//the maker cell front left - case 181815: m_uiPrisonCell4GUID = pGo->GetGUID(); break;//the maker cell back left - case 181821: m_uiPrisonCell5GUID = pGo->GetGUID(); break;//broggok cell front right - case 181818: m_uiPrisonCell6GUID = pGo->GetGUID(); break;//broggok cell back right - case 181820: m_uiPrisonCell7GUID = pGo->GetGUID(); break;//broggok cell front left - case 181817: m_uiPrisonCell8GUID = pGo->GetGUID(); break;//broggok cell back left - } + case TYPE_THE_MAKER_EVENT: + if (uiData == IN_PROGRESS) + DoUseDoorOrButton(GO_DOOR_MAKER_FRONT); + if (uiData == FAIL) + DoUseDoorOrButton(GO_DOOR_MAKER_FRONT); + if (uiData == DONE) + { + DoUseDoorOrButton(GO_DOOR_MAKER_FRONT); + DoUseDoorOrButton(GO_DOOR_MAKER_REAR); + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_BROGGOK_EVENT: + if (m_auiEncounter[uiType] == uiData) + return; + + // Combat door; the exit door is opened in event + DoUseDoorOrButton(GO_DOOR_BROGGOK_FRONT); + if (uiData == IN_PROGRESS) + { + if (m_uiBroggokEventPhase <= MAX_ORC_WAVES) + { + m_uiBroggokEventPhase = 0; + DoSortBroggokOrcs(); + // open first cage + DoNextBroggokEventPhase(); + } + } + else if (uiData == FAIL) + { + // On wipe we reset only the orcs; if the party wipes at the boss itself then the orcs don't reset + if (m_uiBroggokEventPhase <= MAX_ORC_WAVES) + { + for (uint8 i = 0; i < MAX_ORC_WAVES; ++i) + { + // Reset Orcs + if (!m_aBroggokEvent[i].m_bIsCellOpened) + 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) + { + if (Creature* pOrc = instance->GetCreature(*itr)) + { + if (!pOrc->isAlive()) + pOrc->Respawn(); + } + } + + // Close Door + DoUseDoorOrButton(m_aBroggokEvent[i].m_cellGuid); + m_aBroggokEvent[i].m_bIsCellOpened = false; + } + } + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_KELIDAN_EVENT: + if (uiData == DONE) + { + DoUseDoorOrButton(GO_DOOR_KELIDAN_EXIT); + DoUseDoorOrButton(GO_DOOR_FINAL_EXIT); + } + m_auiEncounter[uiType] = uiData; + break; + default: + script_error_log("Instance Blood Furnace SetData with Type %u Data %u, but this is not implemented.", uiType, uiData); + return; } - uint64 GetData64(uint32 uiData) + if (uiData == DONE) { - switch(uiData) - { - case DATA_THE_MAKER: return m_uiMakerGUID; - case DATA_BROGGOK: return m_uiBroggokGUID; - case DATA_PRISON_CELL_MAKER1: return m_uiPrisonCell1GUID; - case DATA_PRISON_CELL_MAKER2: return m_uiPrisonCell2GUID; - case DATA_PRISON_CELL_MAKER3: return m_uiPrisonCell3GUID; - case DATA_PRISON_CELL_MAKER4: return m_uiPrisonCell4GUID; - case DATA_PRISON_CELL_BROGGOK1: return m_uiPrisonCell5GUID; - case DATA_PRISON_CELL_BROGGOK2: return m_uiPrisonCell6GUID; - case DATA_PRISON_CELL_BROGGOK3: return m_uiPrisonCell7GUID; - case DATA_PRISON_CELL_BROGGOK4: return m_uiPrisonCell8GUID; - } + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; - return 0; + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_blood_furnace::DoNextBroggokEventPhase() +{ + // Get Movement Position + float dx, dy; + GetMovementDistanceForIndex(m_uiBroggokEventPhase, dx, dy); + + // Open door to the final boss now and move boss to the center of the room + if (m_uiBroggokEventPhase >= MAX_ORC_WAVES) { - switch(uiType) + DoUseDoorOrButton(GO_DOOR_BROGGOK_REAR); + + if (Creature* pBroggok = GetSingleCreatureFromStorage(NPC_BROGGOK)) { - case TYPE_THE_MAKER_EVENT: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiDoorMakerFrontGUID); - if (uiData == FAIL) - DoUseDoorOrButton(m_uiDoorMakerFrontGUID); - if (uiData == DONE) - { - DoUseDoorOrButton(m_uiDoorMakerFrontGUID); - DoUseDoorOrButton(m_uiDoorMakerRearGUID); - } - m_auiEncounter[0] = uiData; - break; - case TYPE_BROGGOK_EVENT: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiDoorBroggokFrontGUID); - if (uiData == FAIL) - DoUseDoorOrButton(m_uiDoorBroggokFrontGUID); - if (uiData == DONE) - { - DoUseDoorOrButton(m_uiDoorBroggokFrontGUID); - DoUseDoorOrButton(m_uiDoorBrokkokRearGUID); - } - m_auiEncounter[1] = uiData; - break; - case TYPE_KELIDAN_EVENT: - if (uiData == DONE) - { - DoUseDoorOrButton(m_uiDoorKelidanExitGUID); - DoUseDoorOrButton(m_uiDoorFinalExitGUID); - } - m_auiEncounter[2] = uiData; - break; - default: - error_log("SD2: Instance Blood Furnace SetData with Type %u Data %u, but this is not implemented.",uiType,uiData); - break; + pBroggok->SetWalk(false); + pBroggok->GetMotionMaster()->MovePoint(0, dx, dy, pBroggok->GetPositionZ()); } + } + else + { + // Open cage door + if (!m_aBroggokEvent[m_uiBroggokEventPhase].m_bIsCellOpened) + DoUseDoorOrButton(m_aBroggokEvent[m_uiBroggokEventPhase].m_cellGuid); + + m_aBroggokEvent[m_uiBroggokEventPhase].m_bIsCellOpened = true; - if (uiData == DONE) + for (GuidSet::const_iterator itr = m_aBroggokEvent[m_uiBroggokEventPhase].m_sSortedOrcGuids.begin(); itr != m_aBroggokEvent[m_uiBroggokEventPhase].m_sSortedOrcGuids.end(); ++itr) { - OUT_SAVE_INST_DATA; + if (Creature* pOrc = instance->GetCreature(*itr)) + { + // Remove unit flags from npcs + pOrc->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pOrc->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // Move them out of the cages + pOrc->SetWalk(false); + pOrc->GetMotionMaster()->MovePoint(0, pOrc->GetPositionX() + dx, pOrc->GetPositionY() + dy, pOrc->GetPositionZ()); + } + } + } - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + // Prepare for further handling + m_uiBroggokEventTimer = 30000; + ++m_uiBroggokEventPhase; +} + +void instance_blood_furnace::OnCreatureEvade(Creature* pCreature) +{ + if (m_auiEncounter[TYPE_BROGGOK_EVENT] == FAIL) + return; - strInstData = saveStream.str(); + if (pCreature->GetEntry() == NPC_BROGGOK) + SetData(TYPE_BROGGOK_EVENT, FAIL); - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; + else if (pCreature->GetEntry() == NPC_NASCENT_FEL_ORC) + { + for (uint8 i = 0; i < std::min(m_uiBroggokEventPhase, MAX_ORC_WAVES); ++i) + { + if (m_aBroggokEvent[i].m_sSortedOrcGuids.find(pCreature->GetObjectGuid()) != m_aBroggokEvent[i].m_sSortedOrcGuids.end()) + SetData(TYPE_BROGGOK_EVENT, FAIL); } } +} - uint32 GetData(uint32 uiData) +void instance_blood_furnace::OnCreatureDeath(Creature* pCreature) +{ + if (m_auiEncounter[TYPE_BROGGOK_EVENT] != IN_PROGRESS) + return; + + if (pCreature->GetEntry() == NPC_NASCENT_FEL_ORC) { - switch(uiData) + uint8 uiClearedCells = 0; + for (uint8 i = 0; i < std::min(m_uiBroggokEventPhase, MAX_ORC_WAVES); ++i) { - case TYPE_THE_MAKER_EVENT: return m_auiEncounter[0]; - case TYPE_BROGGOK_EVENT: return m_auiEncounter[1]; - case TYPE_KELIDAN_EVENT: return m_auiEncounter[2]; + if (m_aBroggokEvent[i].m_sSortedOrcGuids.size() == m_aBroggokEvent[i].m_uiKilledOrcCount) + { + ++uiClearedCells; + continue; + } + + // Increase kill counter, if we found a mob of this cell + if (m_aBroggokEvent[i].m_sSortedOrcGuids.find(pCreature->GetObjectGuid()) != m_aBroggokEvent[i].m_sSortedOrcGuids.end()) + m_aBroggokEvent[i].m_uiKilledOrcCount++; + + if (m_aBroggokEvent[i].m_sSortedOrcGuids.size() == m_aBroggokEvent[i].m_uiKilledOrcCount) + ++uiClearedCells; } - return 0; + // Increase phase when all opened cells are cleared + if (uiClearedCells == m_uiBroggokEventPhase) + DoNextBroggokEventPhase(); } +} - const char* Save() +void instance_blood_furnace::Update(uint32 uiDiff) +{ + // Broggok Event: For the last wave we don't check the timer; the boss is released only when all mobs die, also the timer is only active on heroic + if (m_auiEncounter[TYPE_BROGGOK_EVENT] == IN_PROGRESS && m_uiBroggokEventPhase < MAX_ORC_WAVES && !instance->IsRegularDifficulty()) { - return strInstData.c_str(); + if (m_uiBroggokEventTimer < uiDiff) + DoNextBroggokEventPhase(); + else + m_uiBroggokEventTimer -= uiDiff; } - void Load(const char* in) + if (m_uiRandYellTimer < uiDiff) { - if (!in) + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) { - OUT_LOAD_INST_DATA_FAIL; - return; + DoScriptText(aRandomTaunt[urand(0, 5)], pMagtheridon); + m_uiRandYellTimer = 90000; } + } + else + m_uiRandYellTimer -= uiDiff; +} + +uint32 instance_blood_furnace::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} - OUT_LOAD_INST_DATA(in); +void instance_blood_furnace::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); - std::istringstream loadStream(in); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; + 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] == FAIL) - m_auiEncounter[i] = NOT_STARTED; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS || m_auiEncounter[i] == FAIL) + m_auiEncounter[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; + OUT_LOAD_INST_DATA_COMPLETE; +} + +// 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) + { + if (Creature* pOrc = instance->GetCreature(*itr)) + { + for (uint8 i = 0; i < MAX_ORC_WAVES; ++i) + { + if (GameObject* pDoor = instance->GetGameObject(m_aBroggokEvent[i].m_cellGuid)) + { + if (pOrc->IsWithinDistInMap(pDoor, 15.0f)) + { + m_aBroggokEvent[i].m_sSortedOrcGuids.insert(pOrc->GetObjectGuid()); + if (!pOrc->isAlive()) + pOrc->Respawn(); + break; + } + } + } + } } -}; +} + +// Helper function to calculate the position to where the orcs should move +// For case of orc-indexes the difference, for Braggok his position +void instance_blood_furnace::GetMovementDistanceForIndex(uint32 uiIndex, float& dx, float& dy) +{ + GameObject* pDoor[2]; + + if (uiIndex < MAX_ORC_WAVES) + { + // Use doors 0, 1 for index 0 or 1; and use doors 2, 3 for index 2 or 3 + pDoor[0] = instance->GetGameObject(m_aBroggokEvent[(uiIndex / 2) * 2].m_cellGuid); + pDoor[1] = instance->GetGameObject(m_aBroggokEvent[(uiIndex / 2) * 2 + 1].m_cellGuid); + } + else + { + // Use doors 0 and 3 for Braggok case (which means the middle point is the center of the room) + pDoor[0] = instance->GetGameObject(m_aBroggokEvent[0].m_cellGuid); + pDoor[1] = instance->GetGameObject(m_aBroggokEvent[3].m_cellGuid); + } + + if (!pDoor[0] || !pDoor[1]) + return; + + if (uiIndex < MAX_ORC_WAVES) + { + dx = (pDoor[0]->GetPositionX() + pDoor[1]->GetPositionX()) / 2 - pDoor[uiIndex % 2]->GetPositionX(); + dy = (pDoor[0]->GetPositionY() + pDoor[1]->GetPositionY()) / 2 - pDoor[uiIndex % 2]->GetPositionY(); + } + else + { + dx = (pDoor[0]->GetPositionX() + pDoor[1]->GetPositionX()) / 2; + dy = (pDoor[0]->GetPositionY() + pDoor[1]->GetPositionY()) / 2; + } +} InstanceData* GetInstanceData_instance_blood_furnace(Map* pMap) { return new instance_blood_furnace(pMap); } +bool GOUse_go_prison_cell_lever(Player* /*pPlayer*/, GameObject* pGo) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + + if (!pInstance) + return false; + + // Set broggok event in progress + if (pInstance->GetData(TYPE_BROGGOK_EVENT) != DONE && pInstance->GetData(TYPE_BROGGOK_EVENT) != IN_PROGRESS) + { + pInstance->SetData(TYPE_BROGGOK_EVENT, IN_PROGRESS); + + // Yell intro + if (Creature* pBroggok = pInstance->GetSingleCreatureFromStorage(NPC_BROGGOK)) + DoScriptText(SAY_BROGGOK_INTRO, pBroggok); + } + + return false; +} + void AddSC_instance_blood_furnace() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_blood_furnace"; - newscript->GetInstanceData = &GetInstanceData_instance_blood_furnace; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_blood_furnace"; + pNewScript->GetInstanceData = &GetInstanceData_instance_blood_furnace; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_prison_cell_lever"; + pNewScript->pGOUse = &GOUse_go_prison_cell_lever; + pNewScript->RegisterSelf(); } 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 52d682c48f..2f93b1beaa 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Nazan_And_Vazruden -SD%Complete: 30 -SDComment: Encounter is not complete. TODO: re-check script when MovementInform call from core work as expected. +SD%Complete: 95 +SDComment: Bellowing Roar Timer (heroic) needs some love SDCategory: Hellfire Citadel, Hellfire Ramparts EndScriptData */ @@ -36,35 +36,44 @@ enum SAY_DEATH = -1543024, EMOTE_DESCEND = -1543025, - //vazruden - SPELL_REVENGE = 40392, + SPELL_SUMMON_VAZRUDEN = 30717, - //nazan - SPELL_FIREBALL = 30691, - SPELL_H_FIREBALL = 36920, + // 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, SPELL_CONE_OF_FIRE = 30926, - SPELL_H_CONE_OF_FIRE = 36921, + SPELL_CONE_OF_FIRE_H = 36921, - SPELL_H_BELLOW_ROAR = 39427, + SPELL_BELLOW_ROAR_H = 39427, - //misc + // misc POINT_ID_CENTER = 100, - POINT_ID_WAITING = 101, + POINT_ID_FLYING = 101, POINT_ID_COMBAT = 102, - NPC_VAZRUDEN_HERALD = 17307, NPC_NAZAN = 17536, - NPC_VAZRUDEN = 17537 }; -const float afCenterPos[3] = {-1399.401f, 1736.365f, 86.008f}; //moves here to drop off nazan -const float afCombatPos[3] = {-1413.848f, 1754.019f, 83.146f}; //moves here when decending +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 +// 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 MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI { - boss_vazrudenAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_vazruden_heraldAI(Creature* pCreature) : ScriptedAI(pCreature) { + pCreature->SetActiveObjectState(true); m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); @@ -73,218 +82,377 @@ struct MANGOS_DLL_DECL boss_vazrudenAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - bool m_bHealthBelow; + 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 { - m_bHealthBelow = false; + if (m_creature->GetEntry() != NPC_VAZRUDEN_HERALD) + m_creature->UpdateEntry(NPC_VAZRUDEN_HERALD); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + 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_HOVER); + m_creature->SetLevitate(true); } - void Aggro(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - switch(urand(0, 2)) + if (m_bIsEventInProgress && !m_lastSeenPlayerGuid && pWho->GetTypeId() == TYPEID_PLAYER && pWho->isAlive() && !((Player*)pWho)->isGameMaster()) { - case 0: DoScriptText(SAY_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_AGGRO2, m_creature); break; - case 2: DoScriptText(SAY_AGGRO3, m_creature); break; + if (m_creature->IsWithinDistInMap(pWho, 40.0f)) + m_lastSeenPlayerGuid = pWho->GetObjectGuid(); } - } - void JustDied(Unit* pKiller) - { - DoScriptText(SAY_DEATH, m_creature); + if (m_pInstance && m_pInstance->GetData(TYPE_NAZAN) != IN_PROGRESS) + return; - if (m_pInstance) - m_pInstance->SetData(TYPE_VAZRUDEN, DONE); + ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* pVictim) + void AttackStart(Unit* pWho) override { - DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); + if (m_pInstance && m_pInstance->GetData(TYPE_NAZAN) != IN_PROGRESS) + return; + + ScriptedAI::AttackStart(pWho); } - void PrepareAndDescendMount() + void MovementInform(uint32 uiType, uint32 uiPointId) override { - if (Creature* pHerald = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_HERALD))) + if (!m_pInstance) + return; + + if (uiType == WAYPOINT_MOTION_TYPE) + { + if (m_uiMovementTimer || m_bIsEventInProgress) + return; + + if (m_pInstance->GetData(TYPE_NAZAN) == SPECIAL) + { + m_creature->SetCombatStartPosition(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + m_uiMovementTimer = 1000; + m_bIsEventInProgress = true; + } + } + + if (uiType == POINT_MOTION_TYPE) { - if (pHerald->HasSplineFlag(SPLINEFLAG_WALKMODE)) - pHerald->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + switch (uiPointId) + { + case POINT_ID_CENTER: + DoSplit(); + break; + case POINT_ID_COMBAT: + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_pInstance->SetData(TYPE_NAZAN, IN_PROGRESS); + m_creature->SetInCombatWithZone(); - pHerald->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, afCombatPos[0], afCombatPos[1], afCombatPos[2]); + // Landing + // undo flying + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); + m_creature->SetLevitate(false); - DoScriptText(EMOTE_DESCEND, pHerald); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_lastSeenPlayerGuid); + if (pPlayer && pPlayer->isAlive()) + AttackStart(pPlayer); + + // Initialize for combat + m_uiFireballTimer = urand(5200, 16500); + + break; + } + case POINT_ID_FLYING: + if (m_bIsEventInProgress) // Additional check for wipe case, while nazan is flying to this point + m_uiFireballTimer = 1; + break; + } } } - void UpdateAI(const uint32 uiDiff) + void DoMoveToCenter() { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + DoScriptText(SAY_INTRO, m_creature); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, afCenterPos[0], afCenterPos[1], afCenterPos[2]); + } - if (!m_bHealthBelow && m_creature->GetHealthPercent() <= 30.0f) - { - if (m_pInstance) - PrepareAndDescendMount(); + void DoSplit() + { + m_creature->UpdateEntry(NPC_NAZAN); - m_bHealthBelow = true; - } + DoCastSpellIfCan(m_creature, SPELL_SUMMON_VAZRUDEN); - DoMeleeAttackIfReady(); - } -}; + m_uiMovementTimer = 3000; -CreatureAI* GetAI_boss_vazruden(Creature* pCreature) -{ - return new boss_vazrudenAI(pCreature); -} + // Let him idle for now + m_creature->GetMotionMaster()->MoveIdle(); + } -// 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 -{ - boss_vazruden_heraldAI(Creature* pCreature) : ScriptedAI(pCreature) + void DoMoveToAir() { - pCreature->SetActiveObjectState(true); - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } + float fX, fY, fZ; + m_creature->GetCombatStartPosition(fX, fY, fZ); - ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; + // Remove Idle MMGen + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE) + m_creature->GetMotionMaster()->MovementExpired(false); - uint32 m_uiMovementTimer; + m_creature->GetMotionMaster()->MovePoint(POINT_ID_FLYING, fX, fY, fZ); + } - void Reset() + void DoMoveToCombat() { - if (m_creature->GetEntry() != NPC_VAZRUDEN_HERALD) - m_creature->UpdateEntry(NPC_VAZRUDEN_HERALD); + if (m_bIsDescending || !m_pInstance || m_pInstance->GetData(TYPE_NAZAN) == IN_PROGRESS) + return; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_bIsDescending = true; - m_uiMovementTimer = 0; + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, afCombatPos[0], afCombatPos[1], afCombatPos[2]); + DoScriptText(EMOTE_DESCEND, m_creature); } - void MoveInLineOfSight(Unit* pWho) + void JustSummoned(Creature* pSummoned) override { - if (m_pInstance && m_pInstance->GetData(TYPE_NAZAN) != IN_PROGRESS) + if (pSummoned->GetEntry() != NPC_VAZRUDEN) return; - ScriptedAI::MoveInLineOfSight(pWho); + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_lastSeenPlayerGuid)) + pSummoned->AI()->AttackStart(pPlayer); + + m_vazrudenGuid = pSummoned->GetObjectGuid(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VAZRUDEN, IN_PROGRESS); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void JustDied(Unit* /*pKiller*/) override { - if (!m_pInstance) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_NAZAN, DONE); + } - if (uiType == WAYPOINT_MOTION_TYPE) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NAZAN, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { if (m_uiMovementTimer) - return; + { + if (m_uiMovementTimer <= uiDiff) + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_VAZRUDEN) == IN_PROGRESS) + DoMoveToAir(); + else + DoMoveToCenter(); + } + m_uiMovementTimer = 0; + } + else + m_uiMovementTimer -= uiDiff; + } - if (m_pInstance->GetData(TYPE_NAZAN) == SPECIAL) + if (m_vazrudenGuid && m_uiFireballTimer) { - m_creature->SetCombatStartPosition(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - m_uiMovementTimer = 1000; + if (m_uiFireballTimer <= 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 : SPELL_FIREBALL_H, 0, pVazruden->GetObjectGuid()) == CAST_OK) + m_uiFireballTimer = urand(2100, 7300); + } + } + } + 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; } - if (uiType == POINT_MOTION_TYPE) + // In Combat + if (m_uiFireballTimer < uiDiff) { - if (uiPointId == POINT_ID_CENTER) - DoSplit(); - else if (uiPointId == POINT_ID_COMBAT) + if (Unit* pEnemy = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_pInstance->SetData(TYPE_NAZAN, IN_PROGRESS); + if (DoCastSpellIfCan(pEnemy, m_bIsRegularMode ? SPELL_FIREBALL_LAND : SPELL_FIREBALL_LAND_H) == CAST_OK) + m_uiFireballTimer = urand(7300, 13200); } } - } + else + m_uiFireballTimer -= uiDiff; - void DoMoveToCenter() - { - DoScriptText(SAY_INTRO, m_creature); + if (m_uiConeOfFireTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_CONE_OF_FIRE : SPELL_CONE_OF_FIRE_H) == CAST_OK) + m_uiConeOfFireTimer = urand(7300, 13200); + } + else + m_uiConeOfFireTimer -= uiDiff; - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) + if (!m_bIsRegularMode) { - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveIdle(); + if (m_uiBellowingRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BELLOW_ROAR_H) == CAST_OK) + m_uiBellowingRoarTimer = urand(8000, 12000); // TODO Guesswork, 8s cooldown + } + else + m_uiBellowingRoarTimer -= uiDiff; } - m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, afCenterPos[0], afCenterPos[1], afCenterPos[2]); + DoMeleeAttackIfReady(); } +}; + +CreatureAI* GetAI_boss_vazruden_herald(Creature* pCreature) +{ + return new boss_vazruden_heraldAI(pCreature); +} - void DoMoveToHold() +// This is the summoned boss ("dismounted") that starts attacking the players +struct MANGOS_DLL_DECL boss_vazrudenAI : public ScriptedAI +{ + boss_vazrudenAI(Creature* pCreature) : ScriptedAI(pCreature) { - float fX, fY, fZ; - m_creature->GetCombatStartPosition(fX, fY, fZ); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - m_creature->GetMotionMaster()->MovePoint(POINT_ID_WAITING, fX, fY, fZ); + uint32 m_uiRevengeTimer; + bool m_bHealthBelow; + + void Reset() override + { + m_bHealthBelow = false; + m_uiRevengeTimer = urand(5500, 8400); } - void DoSplit() + void Aggro(Unit* /*pWho*/) override { - m_creature->UpdateEntry(NPC_NAZAN); + 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; + } + } - m_creature->SummonCreature(NPC_VAZRUDEN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); - m_uiMovementTimer = 3000; + if (m_pInstance) + m_pInstance->SetData(TYPE_VAZRUDEN, DONE); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_VAZRUDEN, IN_PROGRESS); + m_pInstance->SetData(TYPE_VAZRUDEN, FAIL); } - void JustDied(Unit* pKiller) + void KilledUnit(Unit* /*pVictim*/) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_NAZAN, DONE); + DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { - if (!m_creature->getVictim() && m_uiMovementTimer) + if (!m_bHealthBelow && m_pInstance && (float(m_creature->GetHealth() - uiDamage) / m_creature->GetMaxHealth()) < 0.30f) { - if (m_uiMovementTimer <= uiDiff) - { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_VAZRUDEN) == IN_PROGRESS) - DoMoveToHold(); - else - DoMoveToCenter(); - } - m_uiMovementTimer = 0; - } else m_uiMovementTimer -= uiDiff; + 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_herald(Creature* pCreature) +CreatureAI* GetAI_boss_vazruden(Creature* pCreature) { - return new boss_vazruden_heraldAI(pCreature); + return new boss_vazrudenAI(pCreature); } void AddSC_boss_nazan_and_vazruden() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_vazruden"; - newscript->GetAI = &GetAI_boss_vazruden; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_vazruden"; + pNewScript->GetAI = &GetAI_boss_vazruden; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "boss_vazruden_herald"; - newscript->GetAI = &GetAI_boss_vazruden_herald; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_vazruden_herald"; + pNewScript->GetAI = &GetAI_boss_vazruden_herald; + pNewScript->RegisterSelf(); } 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 299bec47ca..3aa6dea586 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -23,23 +23,26 @@ EndScriptData */ #include "precompiled.h" -#define SAY_AGGRO_1 -1543009 -#define SAY_AGGRO_2 -1543010 -#define SAY_AGGRO_3 -1543011 -#define SAY_SUMMON -1543012 -#define SAY_CURSE -1543013 -#define SAY_KILL_1 -1543014 -#define SAY_DIE -1543015 -#define SAY_WIPE -1543016 - -#define SPELL_ORBITAL_STRIKE 30637 -#define SPELL_SHADOW_WHIP 30638 -#define SPELL_TREACHEROUS_AURA 30695 -#define H_SPELL_BANE_OF_TREACHERY 37566 -#define SPELL_DEMONIC_SHIELD 31901 -#define SPELL_SHADOW_BOLT 30686 -#define H_SPELL_SHADOW_BOLT 39297 -#define SPELL_SUMMON_FIENDISH_HOUND 30707 +enum +{ + SAY_AGGRO_1 = -1543009, + SAY_AGGRO_2 = -1543010, + SAY_AGGRO_3 = -1543011, + SAY_SUMMON = -1543012, + SAY_CURSE = -1543013, + SAY_KILL_1 = -1543014, + SAY_DIE = -1543015, + SAY_WIPE = -1543016, + + SPELL_ORBITAL_STRIKE = 30637, + SPELL_SHADOW_WHIP = 30638, + SPELL_TREACHEROUS_AURA = 30695, + SPELL_BANE_OF_TREACHERY_H = 37566, + SPELL_DEMONIC_SHIELD = 31901, + SPELL_SHADOW_BOLT = 30686, + SPELL_SHADOW_BOLT_H = 39297, + SPELL_SUMMON_FIENDISH_HOUND = 30707, +}; struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI { @@ -52,34 +55,32 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI bool m_bIsRegularMode; - uint32 OrbitalStrike_Timer; - uint32 ShadowWhip_Timer; - uint32 Aura_Timer; - uint32 DemonicShield_Timer; - uint32 Shadowbolt_Timer; - uint32 Summon_Timer; - uint32 SummonedCount; - uint64 playerGUID; - bool CanPullBack; - - void Reset() + uint32 m_uiOrbitalStrikeTimer; + uint32 m_uiShadowWhipTimer; + uint32 m_uiAuraTimer; + uint32 m_uiDemonicShieldTimer; + uint32 m_uiShadowboltTimer; + uint32 m_uiSummonTimer; + ObjectGuid m_playerGuid; + bool m_bCanPullBack; + + void Reset() override { DoScriptText(SAY_WIPE, m_creature); - OrbitalStrike_Timer = 25000; - ShadowWhip_Timer = 2000; - Aura_Timer = 10000; - DemonicShield_Timer = 1000; - Shadowbolt_Timer = 2000; - Summon_Timer = 10000; - SummonedCount = 0; - playerGUID = 0; - CanPullBack = false; + m_uiOrbitalStrikeTimer = 25000; + m_uiShadowWhipTimer = 2000; + m_uiAuraTimer = urand(12300, 23300); + m_uiDemonicShieldTimer = 1000; + m_uiShadowboltTimer = urand(6600, 8900); + m_uiSummonTimer = urand(19600, 23100); + m_playerGuid.Clear(); + m_bCanPullBack = false; } - 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; @@ -87,7 +88,7 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI } } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -95,104 +96,108 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI DoScriptText(SAY_KILL_1, m_creature); } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* pSummoned) override { DoScriptText(SAY_SUMMON, m_creature); - if (Unit* random = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - summoned->AI()->AttackStart(random); - - ++SummonedCount; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //only two may be wrong, perhaps increase timer and spawn periodically instead. - if (SummonedCount < 2) + if (m_uiSummonTimer < uiDiff) { - if (Summon_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature,SPELL_SUMMON_FIENDISH_HOUND); - Summon_Timer = urand(15000, 30000); - }else Summon_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIENDISH_HOUND) == CAST_OK) + m_uiSummonTimer = urand(24100, 26900); } + else + m_uiSummonTimer -= uiDiff; - if (CanPullBack) + if (m_bCanPullBack) { - if (ShadowWhip_Timer < diff) + if (m_uiShadowWhipTimer < uiDiff) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(playerGUID)) + 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)) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(pPlayer,SPELL_SHADOW_WHIP); - } + DoCastSpellIfCan(pPlayer, SPELL_SHADOW_WHIP, CAST_INTERRUPT_PREVIOUS); } - playerGUID = 0; - ShadowWhip_Timer = 2000; - CanPullBack = false; - }else ShadowWhip_Timer -= diff; + m_playerGuid.Clear(); + m_uiShadowWhipTimer = 2000; + m_bCanPullBack = false; + } + else + m_uiShadowWhipTimer -= uiDiff; } - else if (OrbitalStrike_Timer < diff) + else if (m_uiOrbitalStrikeTimer < uiDiff) { - Unit* temp = NULL; - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - temp = m_creature->getVictim(); - else temp = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); + Unit* pTemp = NULL; + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + pTemp = m_creature->getVictim(); + else + pTemp = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (temp && temp->GetTypeId() == TYPEID_PLAYER) + if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER) { - DoCastSpellIfCan(temp,SPELL_ORBITAL_STRIKE); - OrbitalStrike_Timer = urand(14000, 16000); - playerGUID = temp->GetGUID(); + if (DoCastSpellIfCan(pTemp, SPELL_ORBITAL_STRIKE) == CAST_OK) + { + m_uiOrbitalStrikeTimer = urand(14000, 16000); + m_playerGuid = pTemp->GetObjectGuid(); - if (playerGUID) - CanPullBack = true; + m_bCanPullBack = true; + } } - }else OrbitalStrike_Timer -= diff; + } + else + m_uiOrbitalStrikeTimer -= uiDiff; if (m_creature->GetHealthPercent() < 20.0f) { - if (DemonicShield_Timer < diff) + if (m_uiDemonicShieldTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_DEMONIC_SHIELD); - DemonicShield_Timer = 15000; - }else DemonicShield_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_DEMONIC_SHIELD) == CAST_OK) + m_uiDemonicShieldTimer = 15000; + } + else + m_uiDemonicShieldTimer -= uiDiff; } - if (Aura_Timer < diff) + if (m_uiAuraTimer < uiDiff) { - DoScriptText(SAY_CURSE, m_creature); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_TREACHEROUS_AURA : H_SPELL_BANE_OF_TREACHERY); - Aura_Timer = urand(8000, 16000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_TREACHEROUS_AURA : SPELL_BANE_OF_TREACHERY_H) == CAST_OK) + { + m_uiAuraTimer = urand(8000, 16000); + DoScriptText(SAY_CURSE, m_creature); + } } - }else Aura_Timer -= diff; + } + else + m_uiAuraTimer -= uiDiff; - if (Shadowbolt_Timer < diff) + if (m_uiShadowboltTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) { - if (target) - target = m_creature->getVictim(); - - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_SHADOW_BOLT : H_SPELL_SHADOW_BOLT); - Shadowbolt_Timer = urand(4000, 6500); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT_H) == CAST_OK) + m_uiShadowboltTimer = urand(4200, 7300); } - }else Shadowbolt_Timer -= diff; + else + m_uiShadowboltTimer = 2000; + } + else + m_uiShadowboltTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -205,10 +210,10 @@ CreatureAI* GetAI_boss_omor_the_unscarredAI(Creature* pCreature) void AddSC_boss_omor_the_unscarred() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_omor_the_unscarred"; - newscript->GetAI = &GetAI_boss_omor_the_unscarredAI; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_omor_the_unscarred"; + pNewScript->GetAI = &GetAI_boss_omor_the_unscarredAI; + pNewScript->RegisterSelf(); } 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 f38953d7de..5a8c63b644 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,26 +17,30 @@ /* ScriptData SDName: Boss_Watchkeeper_Gargolmar SD%Complete: 80 -SDComment: Missing adds to heal him. Surge should be used on target furthest away, not random. +SDComment: Missing adds to heal him. Surge should be used on pTarget furthest away, not random. SDCategory: Hellfire Citadel, Hellfire Ramparts EndScriptData */ #include "precompiled.h" -#define SAY_TAUNT -1543000 -#define SAY_HEAL -1543001 -#define SAY_SURGE -1543002 -#define SAY_AGGRO_1 -1543003 -#define SAY_AGGRO_2 -1543004 -#define SAY_AGGRO_3 -1543005 -#define SAY_KILL_1 -1543006 -#define SAY_KILL_2 -1543007 -#define SAY_DIE -1543008 - -#define SPELL_MORTAL_WOUND 30641 -#define H_SPELL_MORTAL_WOUND 36814 -#define SPELL_SURGE 34645 -#define SPELL_RETALIATION 22857 +enum +{ + SAY_TAUNT = -1543000, + SAY_HEAL = -1543001, + SAY_SURGE = -1543002, + SAY_AGGRO_1 = -1543003, + SAY_AGGRO_2 = -1543004, + SAY_AGGRO_3 = -1543005, + SAY_KILL_1 = -1543006, + SAY_KILL_2 = -1543007, + SAY_DIE = -1543008, + + SPELL_MORTAL_WOUND = 30641, + SPELL_MORTAL_WOUND_H = 36814, + SPELL_SURGE = 34645, + SPELL_RETALIATION = 22857, + SPELL_OVERPOWER = 32154, +}; struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI { @@ -48,26 +52,28 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI bool m_bIsRegularMode; - uint32 Surge_Timer; - uint32 MortalWound_Timer; - uint32 Retaliation_Timer; + uint32 m_uiSurgeTimer; + uint32 m_uiMortalWoundTimer; + uint32 m_uiRetaliationTimer; + uint32 m_uiOverpowerTimer; - bool HasTaunted; - bool YelledForHeal; + bool m_bHasTaunted; + bool m_bYelledForHeal; - void Reset() + void Reset() override { - Surge_Timer = 5000; - MortalWound_Timer = 4000; - Retaliation_Timer = 0; + m_uiSurgeTimer = urand(2400, 6100); + m_uiMortalWoundTimer = urand(3500, 14400); + m_uiRetaliationTimer = 0; + m_uiOverpowerTimer = urand(3600, 14800); - HasTaunted = false; - YelledForHeal = false; + m_bHasTaunted = false; + m_bYelledForHeal = false; } - 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; @@ -75,73 +81,79 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* who) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_creature->getVictim() && who->isTargetableForAttack() && (m_creature->IsHostileTo(who)) && who->isInAccessablePlaceFor(m_creature)) + if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 60.0f)) { - if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(who); - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) - { - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) - { - DoScriptText(SAY_TAUNT, m_creature); - HasTaunted = true; - } + DoScriptText(SAY_TAUNT, m_creature); + m_bHasTaunted = true; } + + ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (MortalWound_Timer < diff) + if (m_uiMortalWoundTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MORTAL_WOUND : H_SPELL_MORTAL_WOUND); - MortalWound_Timer = urand(5000, 13000); - }else MortalWound_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MORTAL_WOUND : SPELL_MORTAL_WOUND_H) == CAST_OK) + m_uiMortalWoundTimer = urand(6100, 12200); + } + else + m_uiMortalWoundTimer -= uiDiff; - if (Surge_Timer < diff) + if (m_uiSurgeTimer < uiDiff) { - DoScriptText(SAY_SURGE, m_creature); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_SURGE); - - Surge_Timer = urand(5000, 12000); - }else Surge_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SURGE) == CAST_OK) + { + DoScriptText(SAY_SURGE, m_creature); + m_uiSurgeTimer = urand(12100, 21700); + } + } + } + else + m_uiSurgeTimer -= uiDiff; if (m_creature->GetHealthPercent() < 20.0f) { - if (Retaliation_Timer < diff) + if (m_uiRetaliationTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_RETALIATION); - Retaliation_Timer = 30000; - }else Retaliation_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_RETALIATION) == CAST_OK) + m_uiRetaliationTimer = 30000; + } + else + m_uiRetaliationTimer -= uiDiff; } - if (!YelledForHeal) + if (m_uiOverpowerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_OVERPOWER) == CAST_OK) + m_uiOverpowerTimer = urand(18100, 33700); + } + else + m_uiOverpowerTimer -= uiDiff; + + if (!m_bYelledForHeal) { if (m_creature->GetHealthPercent() < 40.0f) { DoScriptText(SAY_HEAL, m_creature); - YelledForHeal = true; + m_bYelledForHeal = true; } } @@ -156,9 +168,10 @@ CreatureAI* GetAI_boss_watchkeeper_gargolmarAI(Creature* pCreature) void AddSC_boss_watchkeeper_gargolmar() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_watchkeeper_gargolmar"; - newscript->GetAI = &GetAI_boss_watchkeeper_gargolmarAI; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_watchkeeper_gargolmar"; + pNewScript->GetAI = &GetAI_boss_watchkeeper_gargolmarAI; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h b/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h index 5c5638f955..98f1c7e186 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,11 +7,41 @@ enum { - MAX_ENCOUNTER = 2, + MAX_ENCOUNTER = 2, - TYPE_VAZRUDEN = 1, - TYPE_NAZAN = 2, - DATA_HERALD = 3 + TYPE_VAZRUDEN = 1, + TYPE_NAZAN = 2, // Do not change, used in ACID (SetData(SPECIAL) on death of 17517 + + NPC_HELLFIRE_SENTRY = 17517, + NPC_VAZRUDEN_HERALD = 17307, + NPC_VAZRUDEN = 17537, + + GO_FEL_IRON_CHEST = 185168, + GO_FEL_IRON_CHEST_H = 185169, +}; + +class MANGOS_DLL_DECL instance_ramparts : public ScriptedInstance +{ + public: + instance_ramparts(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + 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) + + private: + void DoFailVazruden(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + uint32 m_uiSentryCounter; + 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 5791824398..da2f64cc57 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,90 +24,123 @@ EndScriptData */ #include "precompiled.h" #include "hellfire_ramparts.h" -struct MANGOS_DLL_DECL instance_ramparts : public ScriptedInstance +instance_ramparts::instance_ramparts(Map* pMap) : ScriptedInstance(pMap), + m_uiSentryCounter(0) { - instance_ramparts(Map* pMap) : ScriptedInstance(pMap) {Initialize();} + Initialize(); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint32 m_uiSentryCounter; - uint64 m_uiChestNGUID; - uint64 m_uiChestHGUID; - uint64 m_uiHeraldGUID; +void instance_ramparts::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +void instance_ramparts::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiSentryCounter = 0; - m_uiChestNGUID = 0; - m_uiChestHGUID = 0; - m_uiHeraldGUID = 0; + case NPC_VAZRUDEN_HERALD: + case NPC_VAZRUDEN: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_HELLFIRE_SENTRY: + m_lSentryGUIDs.push_back(pCreature->GetObjectGuid()); + break; } +} - void OnCreatureCreate(Creature* pCreature) +void instance_ramparts::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - if (pCreature->GetEntry() == 17307) - m_uiHeraldGUID = pCreature->GetGUID(); + case GO_FEL_IRON_CHEST: + case GO_FEL_IRON_CHEST_H: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; } +} - void OnObjectCreate(GameObject* pGo) - { - switch(pGo->GetEntry()) - { - case 185168: m_uiChestNGUID = pGo->GetGUID(); break; - case 185169: m_uiChestHGUID = pGo->GetGUID(); break; - } - } +void instance_ramparts::SetData(uint32 uiType, uint32 uiData) +{ + debug_log("SD2: Instance Ramparts: SetData received for type %u with data %u", uiType, uiData); - void SetData(uint32 uiType, uint32 uiData) + switch (uiType) { - debug_log("SD2: Instance Ramparts: SetData received for type %u with data %u",uiType,uiData); - - switch(uiType) - { - case TYPE_VAZRUDEN: - if (uiData == DONE && m_auiEncounter[1] == DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? m_uiChestNGUID : m_uiChestHGUID, HOUR*IN_MILLISECONDS); - m_auiEncounter[0] = uiData; - break; - case TYPE_NAZAN: - if (uiData == SPECIAL) - { - ++m_uiSentryCounter; - - if (m_uiSentryCounter == 2) - m_auiEncounter[1] = uiData; - } - if (uiData == DONE && m_auiEncounter[0] == DONE) - { - DoRespawnGameObject(instance->IsRegularDifficulty() ? m_uiChestNGUID : m_uiChestHGUID, HOUR*IN_MILLISECONDS); - m_auiEncounter[1] = uiData; - } - if (uiData == IN_PROGRESS) + 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) + DoFailVazruden(); + m_auiEncounter[0] = uiData; + break; + case TYPE_NAZAN: + if (m_auiEncounter[1] == uiData) + return; + if (uiData == SPECIAL) // SPECIAL set via ACID + { + ++m_uiSentryCounter; + + if (m_uiSentryCounter == 2) m_auiEncounter[1] = uiData; - break; - } + + return; + } + if (uiData == DONE && m_auiEncounter[0] == DONE) + { + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_FEL_IRON_CHEST : GO_FEL_IRON_CHEST_H, HOUR); + DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_FEL_IRON_CHEST : GO_FEL_IRON_CHEST_H, GO_FLAG_NO_INTERACT, false); + } + if (uiData == FAIL && m_auiEncounter[1] != FAIL) + DoFailVazruden(); + + m_auiEncounter[1] = uiData; + break; } +} - uint32 GetData(uint32 uiType) - { - if (uiType == TYPE_VAZRUDEN) - return m_auiEncounter[0]; +uint32 instance_ramparts::GetData(uint32 uiType) const +{ + if (uiType == TYPE_VAZRUDEN) + return m_auiEncounter[0]; - if (uiType == TYPE_NAZAN) - return m_auiEncounter[1]; + if (uiType == TYPE_NAZAN) + return m_auiEncounter[1]; - return 0; - } + return 0; +} + +void instance_ramparts::DoFailVazruden() +{ + // Store FAIL for both types + m_auiEncounter[0] = FAIL; + m_auiEncounter[1] = FAIL; - uint64 GetData64(uint32 uiData) + // Restore Sentries (counter and respawn them) + m_uiSentryCounter = 0; + for (GuidList::const_iterator itr = m_lSentryGUIDs.begin(); itr != m_lSentryGUIDs.end(); ++itr) { - if (uiData == DATA_HERALD) - return m_uiHeraldGUID; + if (Creature* pSentry = instance->GetCreature(*itr)) + pSentry->Respawn(); + } - return 0; + // Respawn or Reset Vazruden the herald + if (Creature* pVazruden = GetSingleCreatureFromStorage(NPC_VAZRUDEN_HERALD)) + { + if (!pVazruden->isAlive()) + pVazruden->Respawn(); + else + { + if (ScriptedAI* pVazrudenAI = dynamic_cast(pVazruden->AI())) + pVazrudenAI->EnterEvadeMode(); + } } -}; + + // Despawn Vazruden + if (Creature* pVazruden = GetSingleCreatureFromStorage(NPC_VAZRUDEN)) + pVazruden->ForcedDespawn(); +} InstanceData* GetInstanceData_instance_ramparts(Map* pMap) { @@ -117,6 +150,7 @@ InstanceData* GetInstanceData_instance_ramparts(Map* pMap) void AddSC_instance_ramparts() { Script* pNewScript; + pNewScript = new Script; pNewScript->Name = "instance_ramparts"; pNewScript->GetInstanceData = &GetInstanceData_instance_ramparts; diff --git a/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp b/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp index 2fb590c6b4..4c4673002a 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,272 @@ 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 MANGOS_DLL_DECL 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; - } - } + m_bIsPhase3 = false; - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } + SetCombatMovement(true); - void AttackStart(Unit* pWho) - { - if (m_uiTriggerId) - return; - - 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 Cube; - - 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); - } + m_pInstance->SetData(TYPE_MAGTHERIDON_EVENT, FAIL); } - void SetClicker(uint64 uiCubeGUID, uint64 uiClickerGUID) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - // to avoid multiclicks from 1 cube - if (uint64 guid = Cube[uiCubeGUID]) - DebuffClicker(m_creature->GetMap()->GetPlayer(guid)); - - Cube[uiCubeGUID] = uiClickerGUID; - m_bNeedCheckCube = true; - } - - //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) - { - 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 = Cube.begin(); i != Cube.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 = 0; + 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)) - { - DoScriptText(SAY_BANISH, m_creature); - m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE, true); - } - else + // Transition to phase 3 + if (m_uiTransitionTimer) { - 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) - { - m_creature->SetInCombatWithZone(); - 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(); } }; +/*###### +## mob_hellfire_channeler +######*/ + struct MANGOS_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI { mob_hellfire_channelerAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -514,159 +312,232 @@ 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; + uint32 m_uiShadowGraspTimer; + uint32 m_uiShadowBoltVolleyTimer; + uint32 m_uiDarkMendingTimer; + uint32 m_uiFearTimer; + uint32 m_uiInfernalTimer; - bool m_bIsInfernalSpawned; - - 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->instance->GetCreature(m_pInstance->GetData64(DATA_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); - - m_creature->SetInCombatWithZone(); + 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 -bool GOHello_go_manticron_cube(Player* pPlayer, GameObject* pGo) +/*###### +## 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) return true; - if (Creature* pMagtheridon = pInstance->instance->GetCreature(pInstance->GetData64(DATA_MAGTHERIDON))) + if (Creature* pMagtheridon = pInstance->GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) { 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->GetGUID(), pPlayer->GetGUID()); + // 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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); @@ -677,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); @@ -684,24 +560,30 @@ CreatureAI* GetAI_mob_abyssalAI(Creature* pCreature) void AddSC_boss_magtheridon() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_magtheridon"; - newscript->GetAI = &GetAI_boss_magtheridon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_hellfire_channeler"; - newscript->GetAI = &GetAI_mob_hellfire_channeler; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_manticron_cube"; - newscript->pGOHello = &GOHello_go_manticron_cube; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_abyssal"; - newscript->GetAI = &GetAI_mob_abyssalAI; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_magtheridon"; + pNewScript->GetAI = &GetAI_boss_magtheridon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_hellfire_channeler"; + pNewScript->GetAI = &GetAI_mob_hellfire_channeler; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_manticron_cube"; + 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; + pNewScript->RegisterSelf(); } 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 c52acfacf0..52a185b48b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,254 +24,222 @@ EndScriptData */ #include "precompiled.h" #include "magtheridons_lair.h" -struct MANGOS_DLL_DECL instance_magtheridons_lair : public ScriptedInstance +instance_magtheridons_lair::instance_magtheridons_lair(Map* pMap) : ScriptedInstance(pMap), + m_uiRandYellTimer(90000), + m_uiCageBreakTimer(0), + m_uiCageBreakStage(0) { - instance_magtheridons_lair(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint64 m_uiMagtheridonGUID; - std::set ChannelerGUID; - uint64 m_uiDoorGUID; - std::set ColumnGUID; + Initialize(); +} - uint32 m_uiCageTimer; - uint32 m_uiRespawnTimer; +void instance_magtheridons_lair::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +bool instance_magtheridons_lair::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - ChannelerGUID.clear(); - ColumnGUID.clear(); - - m_uiMagtheridonGUID = 0; - m_uiDoorGUID = 0; - - m_uiCageTimer = 0; - m_uiRespawnTimer = 0; + if (m_auiEncounter[i] == IN_PROGRESS) + return true; } - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; - } + return false; +} - void OnCreatureCreate(Creature* pCreature) +void instance_magtheridons_lair::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pCreature->GetEntry()) - { - case NPC_MAGTHERION: m_uiMagtheridonGUID = pCreature->GetGUID(); break; - case NPC_CHANNELER: ChannelerGUID.insert(pCreature->GetGUID()); break; - } + case NPC_MAGTHERIDON: + m_mNpcEntryGuidStore[NPC_MAGTHERIDON] = pCreature->GetObjectGuid(); + break; + case NPC_CHANNELER: + m_lChannelerGuidList.push_back(pCreature->GetObjectGuid()); + break; } +} - void OnObjectCreate(GameObject* pGo) +void instance_magtheridons_lair::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(pGo->GetEntry()) - { - case 181713: - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK1); - break; - case 183847: //event door - m_uiDoorGUID = pGo->GetGUID(); - break; - case 184653: // hall - case 184634: // six columns - case 184635: - case 184636: - case 184637: - case 184638: - case 184639: - ColumnGUID.insert(pGo->GetGUID()); - break; - } + case GO_DOODAD_HF_MAG_DOOR01: // event door + m_mGoEntryGuidStore[GO_DOODAD_HF_MAG_DOOR01] = pGo->GetObjectGuid(); + break; + case GO_DOODAD_HF_RAID_FX01: // hall + case GO_MAGTHERIDON_COLUMN_003: // six columns + case GO_MAGTHERIDON_COLUMN_002: + case GO_MAGTHERIDON_COLUMN_004: + case GO_MAGTHERIDON_COLUMN_005: + case GO_MAGTHERIDON_COLUMN_000: + case GO_MAGTHERIDON_COLUMN_001: + m_lColumnGuidList.push_back(pGo->GetObjectGuid()); + break; + case GO_MANTICRON_CUBE: + m_lCubeGuidList.push_back(pGo->GetObjectGuid()); + break; } +} - void SetData(uint32 uiType, uint32 uiData) +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) - { - if (GameObject* pDoor = instance->GetGameObject(m_uiDoorGUID)) - 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 TYPE_MAGTHERIDON_EVENT: + switch (uiData) + { + case FAIL: + // Reset channelers + for (GuidList::const_iterator itr = m_lChannelerGuidList.begin(); itr != m_lChannelerGuidList.end(); ++itr) + { + if (Creature* pChanneler = instance->GetCreature(*itr)) { - m_auiEncounter[1] = NOT_STARTED; - - if (ChannelerGUID.empty()) - { - debug_log("SD2: Instance Magtheridon: Channeler GUID list are empty."); - break; - } - - for(std::set::iterator i = ChannelerGUID.begin(); i != ChannelerGUID.end(); ++i) - { - if (Creature* pChanneler = instance->GetCreature(*i)) - { - if (pChanneler->isAlive()) - pChanneler->AI()->EnterEvadeMode(); - else - pChanneler->Respawn(); - } - } - - m_uiCageTimer = 0; - - if (GameObject* pDoor = instance->GetGameObject(m_uiDoorGUID)) - pDoor->SetGoState(GO_STATE_ACTIVE); + if (!pChanneler->isAlive()) + pChanneler->Respawn(); } - break; - case IN_PROGRESS: // Event start. - if (m_auiEncounter[1] != IN_PROGRESS) - { - m_auiEncounter[1] = IN_PROGRESS; - - // Let all five channelers aggro. - for(std::set::iterator i = ChannelerGUID.begin(); i != ChannelerGUID.end(); ++i) - { - Creature* pChanneler = instance->GetCreature(*i); - - if (pChanneler && pChanneler->isAlive()) - AttackNearestTarget(pChanneler); - } - - // Magtheridon breaks free after two minutes. - Creature* pMagtheridon = instance->GetCreature(m_uiMagtheridonGUID); + } - if (pMagtheridon && pMagtheridon->isAlive()) - m_uiCageTimer = 120000; + // Reset columns + for (GuidList::const_iterator itr = m_lColumnGuidList.begin(); itr != m_lColumnGuidList.end(); ++itr) + { + if (GameObject* pColumn = instance->GetGameObject(*itr)) + pColumn->ResetDoorOrButton(); + } - if (GameObject* pDoor = instance->GetGameObject(m_uiDoorGUID)) - pDoor->SetGoState(GO_STATE_READY); - } - break; - case DONE: // Add buff and check if all channelers are dead. - for(std::set::iterator i = ChannelerGUID.begin(); i != ChannelerGUID.end(); ++i) + // Reset cubes + for (GuidList::const_iterator itr = m_lCubeGuidList.begin(); itr != m_lCubeGuidList.end(); ++itr) + DoToggleGameObjectFlags(*itr, GO_FLAG_NO_INTERACT, true); + + // Reset timers and doors + SetData(TYPE_CHANNELER_EVENT, NOT_STARTED); + m_uiCageBreakTimer = 0; + m_uiCageBreakStage = 0; + + // no break; + case DONE: + // Reset door on Fail or Done + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_DOODAD_HF_MAG_DOOR01)) + pDoor->ResetDoorOrButton(); + break; + case IN_PROGRESS: + // Set boss in combat + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) + { + if (pMagtheridon->isAlive()) { - Creature* pChanneler = instance->GetCreature(*i); - - if (pChanneler && pChanneler->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(); } - break; - } - m_auiEncounter[1] = uiData; + } + // 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[uiType] = uiData; + break; + case TYPE_CHANNELER_EVENT: + // don't set the same data twice + if (m_auiEncounter[1] == uiData) break; - case TYPE_HALL_COLLAPSE: - // IN_PROGRESS - collapse / NOT_STARTED - reset - for(std::set::iterator i = ColumnGUID.begin(); i != ColumnGUID.end(); ++i) + // 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)) { - DoUseDoorOrButton(*i); + 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; + } } - break; - } - } - - uint32 GetData(uint32 uiType) - { - if (uiType == TYPE_MAGTHERIDON_EVENT) - return m_auiEncounter[0]; - if (uiType == TYPE_CHANNELER_EVENT) - return m_auiEncounter[1]; - return 0; + // combat door + DoUseDoorOrButton(GO_DOODAD_HF_MAG_DOOR01); + } + m_auiEncounter[uiType] = uiData; + break; } - uint64 GetData64(uint32 uiData) - { - if (uiData == DATA_MAGTHERIDON) - return m_uiMagtheridonGUID; + // Instance save isn't needed for this one +} - return 0; - } +uint32 instance_magtheridons_lair::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - void AttackNearestTarget(Creature* pCreature) - { - float minRange = VISIBLE_RANGE; - float range; - Player* target = NULL; + return 0; +} - Map::PlayerList const& players = instance->GetPlayers(); - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) +void instance_magtheridons_lair::Update(uint32 uiDiff) +{ + // Prepare to release Magtheridon + if (m_uiCageBreakTimer) + { + if (m_uiCageBreakTimer <= uiDiff) { - if (Player* i_pl = itr->getSource()) + switch (m_uiCageBreakStage) { - if (i_pl->isTargetableForAttack()) - { - range = i_pl->GetDistance(pCreature); - if (range < minRange) + case 0: + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) { - minRange = range; - target = i_pl; + 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; + ++m_uiCageBreakStage; } - pCreature->AI()->AttackStart(target); + else + m_uiCageBreakTimer -= uiDiff; } - void Update(uint32 uiDiff) - { - if (m_uiCageTimer) - { - if (m_uiCageTimer <= uiDiff) - { - SetData(TYPE_MAGTHERIDON_EVENT, IN_PROGRESS); - m_uiCageTimer = 0; - } - else - m_uiCageTimer -= uiDiff; - } + // no yell if event is in progress or finished + if (m_auiEncounter[TYPE_CHANNELER_EVENT] == IN_PROGRESS || m_auiEncounter[TYPE_MAGTHERIDON_EVENT] == DONE) + return; - if (m_uiRespawnTimer) - { - if (m_uiRespawnTimer <= uiDiff) - { - for(std::set::iterator i = ChannelerGUID.begin(); i != ChannelerGUID.end(); ++i) - { - if (Creature* pChanneler = instance->GetCreature(*i)) - { - if (pChanneler->isAlive()) - pChanneler->AI()->EnterEvadeMode(); - else - pChanneler->Respawn(); - } - } - - 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) { @@ -280,9 +248,10 @@ InstanceData* GetInstanceData_instance_magtheridons_lair(Map* pMap) void AddSC_instance_magtheridons_lair() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_magtheridons_lair"; - newscript->GetInstanceData = &GetInstanceData_instance_magtheridons_lair; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_magtheridons_lair"; + pNewScript->GetInstanceData = &GetInstanceData_instance_magtheridons_lair; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h b/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h index 51bd7289d1..65eb382773 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -9,20 +9,55 @@ enum { MAX_ENCOUNTER = 2, - TYPE_MAGTHERIDON_EVENT = 1, - TYPE_CHANNELER_EVENT = 2, - DATA_MAGTHERIDON = 3, - TYPE_HALL_COLLAPSE = 4, + TYPE_MAGTHERIDON_EVENT = 0, + TYPE_CHANNELER_EVENT = 1, - DATA_CHANNELER = 5, - - NPC_MAGTHERION = 17257, + 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, + GO_MAGTHERIDON_COLUMN_003 = 184634, + GO_MAGTHERIDON_COLUMN_002 = 184635, + GO_MAGTHERIDON_COLUMN_004 = 184636, + GO_MAGTHERIDON_COLUMN_005 = 184637, + GO_MAGTHERIDON_COLUMN_000 = 184638, + GO_MAGTHERIDON_COLUMN_001 = 184639, + + EMOTE_EVENT_BEGIN = -1544014, + EMOTE_NEARLY_FREE = -1544016, +}; + +static const int32 aRandomTaunt[] = { -1544000, -1544001, -1544002, -1544003, -1544004, -1544005}; + +class MANGOS_DLL_DECL instance_magtheridons_lair : public ScriptedInstance +{ + public: + instance_magtheridons_lair(Map* pMap); + + void Initialize() override; + + bool IsEncounterInProgress() const 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; + + private: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + GuidList m_lChannelerGuidList; + GuidList m_lColumnGuidList; + GuidList m_lCubeGuidList; + + 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 0114c6cbb3..c5500a1f98 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 @@ -69,12 +69,14 @@ enum SPELL_SHADOW_FISSURE = 30496, // Summon the ShadowFissure NPC SPELL_SHADOW_CLEAVE = 30495, - H_SPELL_SHADOW_SLAM = 35953, + SPELL_SHADOW_SLAM_H = 35953, + SPELL_SHADOW_SEAR = 30735, // On fel orcs - not sure yet how it is used SPELL_HEMORRHAGE = 30478, - SPELL_CONSUMPTION = 30497, - SPELL_TEMPORARY_VISUAL = 39312 // this is wrong, a temporary solution. spell consumption already has the purple visual, but doesn't display as it should + SPELL_CONSUMPTION = 30497, // Cast by the shadow fissure + + NPC_FEL_ORC_CONVERT = 17083, }; struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI @@ -83,6 +85,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bIntroOnce = false; Reset(); } @@ -93,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; @@ -104,14 +107,15 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI uint32 m_uiShadowFissureTimer; uint32 m_uiCleaveTimer; - void Reset() + ObjectGuid m_lastEventInvokerGuid; + + void Reset() override { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_bIsIntroEvent = false; - m_bIntroOnce = false; m_bIsMainEvent = false; - //m_bHasTaunted = false; + // m_bHasTaunted = false; m_bSpinOnce = false; m_bPhase = false; @@ -122,18 +126,23 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI m_uiDeathCoilTimer = 20000; m_uiShadowFissureTimer = 8000; m_uiCleaveTimer = 5000; + + m_lastEventInvokerGuid.Clear(); } - void DoYellForPeonAggro() + void DoYellForPeonAggro(Unit* pWho) { if (m_uiPeonEngagedCount >= 4) return; DoScriptText(PeonAttacked[m_uiPeonEngagedCount].id, m_creature); ++m_uiPeonEngagedCount; + + if (pWho) + m_lastEventInvokerGuid = pWho->GetObjectGuid(); } - void DoYellForPeonDeath() + void DoYellForPeonDeath(Unit* pKiller) { if (m_uiPeonKilledCount >= 4) return; @@ -146,27 +155,37 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI m_bIsIntroEvent = false; m_bIsMainEvent = true; m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + 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; case 2: DoScriptText(SAY_TAUNT_3, m_creature); break; } - // TODO: kill the peons first + std::list lFelConverts; + GetCreatureListWithEntryInGrid(lFelConverts, m_creature, NPC_FEL_ORC_CONVERT, 40.0f); + for (std::list::iterator itr = lFelConverts.begin(); itr != lFelConverts.end(); ++itr) + (*itr)->DealDamage(*itr, (*itr)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_bIsIntroEvent = false; m_uiPeonEngagedCount = 4; m_uiPeonKilledCount = 4; m_bIsMainEvent = true; m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (Unit* pEnemy = m_creature->GetMap()->GetUnit(m_lastEventInvokerGuid)) + AttackStart(pEnemy); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_bIsIntroEvent || !m_bIsMainEvent) return; @@ -184,17 +203,16 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bIntroOnce && m_creature->IsWithinDistInMap(pWho, 50.0f)) + if (!m_bIntroOnce && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, 50.0f) && m_creature->IsWithinLOSInMap(pWho)) { - if (pWho->GetTypeId() != TYPEID_PLAYER) - return; - DoScriptText(SAY_INTRO, m_creature); m_bIntroOnce = true; m_bIsIntroEvent = true; + m_lastEventInvokerGuid = pWho->GetObjectGuid(); + if (m_pInstance) m_pInstance->SetData(TYPE_NETHEKURSE, IN_PROGRESS); } @@ -205,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; @@ -215,23 +233,21 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - pSummoned->setFaction(16); + // ToDo: this should be done in DB pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // triggered spell of consumption does not properly show it's SpellVisual, wrong spellid? - pSummoned->CastSpell(pSummoned, SPELL_TEMPORARY_VISUAL, true); - pSummoned->CastSpell(pSummoned, SPELL_CONSUMPTION, false, 0, 0, m_creature->GetGUID()); + 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); @@ -241,7 +257,21 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI m_pInstance->SetData(TYPE_NETHEKURSE, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NETHEKURSE, FAIL); + + std::list lFelConverts; + GetCreatureListWithEntryInGrid(lFelConverts, m_creature, NPC_FEL_ORC_CONVERT, 40.0f); + for (std::list::iterator itr = lFelConverts.begin(); itr != lFelConverts.end(); ++itr) + { + if (!(*itr)->isAlive()) + (*itr)->Respawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (m_bIsIntroEvent) { @@ -273,7 +303,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_CLEAVE : H_SPELL_SHADOW_SLAM); + DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_CLEAVE : SPELL_SHADOW_SLAM_H); m_uiCleaveTimer = urand(6000, 8500); } else @@ -318,26 +348,26 @@ 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) { - Creature* pKurse = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(NPC_NETHEKURSE)); + Creature* pKurse = m_pInstance->GetSingleCreatureFromStorage(NPC_NETHEKURSE); if (pKurse && m_creature->IsWithinDist(pKurse, 45.0f)) { if (boss_grand_warlock_nethekurseAI* pKurseAI = dynamic_cast(pKurse->AI())) - pKurseAI->DoYellForPeonAggro(); + pKurseAI->DoYellForPeonAggro(pWho); if (m_pInstance->GetData(TYPE_NETHEKURSE) == IN_PROGRESS) return; @@ -347,22 +377,22 @@ struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (m_pInstance) { if (m_pInstance->GetData(TYPE_NETHEKURSE) != IN_PROGRESS) return; - if (Creature* pKurse = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(NPC_NETHEKURSE))) + if (Creature* pKurse = m_pInstance->GetSingleCreatureFromStorage(NPC_NETHEKURSE)) { if (boss_grand_warlock_nethekurseAI* pKurseAI = dynamic_cast(pKurse->AI())) - pKurseAI->DoYellForPeonAggro(); + pKurseAI->DoYellForPeonDeath(pKiller); } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -380,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 ScriptedAI +struct MANGOS_DLL_DECL mob_lesser_shadow_fissureAI : public Scripted_NoMovementAI { - mob_lesser_shadow_fissureAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + 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 7182fb1595..a5cc40fa8d 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -40,7 +40,7 @@ enum SPELL_THUNDERCLAP = 30633, SPELL_BURNING_MAUL = 30598, - H_SPELL_BURNING_MAUL = 36056, + SPELL_BURNING_MAUL_H = 36056, NPC_LEFT_HEAD = 19523, NPC_RIGHT_HEAD = 19524 @@ -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 { 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,17 +116,19 @@ 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; } }; @@ -134,8 +136,6 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI { boss_warbringer_omroggAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiLeftHeadGUID = 0; - m_uiRightHeadGUID = 0; m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); @@ -144,8 +144,8 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint64 m_uiLeftHeadGUID; - uint64 m_uiRightHeadGUID; + ObjectGuid m_leftHeadGuid; + ObjectGuid m_rightHeadGuid; int m_iAggro; int m_iThreat; @@ -156,49 +156,34 @@ 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_uiLeftHeadGUID)) - { - pLeftHead->SetDeathState(JUST_DIED); - m_uiLeftHeadGUID = 0; - } - - if (Creature* pRightHead = m_creature->GetMap()->GetCreature(m_uiRightHeadGUID)) - { - pRightHead->SetDeathState(JUST_DIED); - m_uiRightHeadGUID = 0; - } - - 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() { - Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_uiLeftHeadGUID); - Creature* pRightHead = m_creature->GetMap()->GetCreature(m_uiRightHeadGUID); + Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); + Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); if (!pLeftHead || !pRightHead) return; @@ -209,22 +194,22 @@ 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); - if (Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_uiLeftHeadGUID)) + if (Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid)) { m_iAggro = irand(0, 2); DoScriptText(GoCombat[m_iAggro].id, pLeftHead); - m_uiDelay_Timer = 3500; + m_uiDelayTimer = 3500; m_bAggroYell = true; } @@ -232,23 +217,18 @@ 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_uiLeftHeadGUID = pSummoned->GetGUID(); - - if (pSummoned->GetEntry() == NPC_RIGHT_HEAD) - m_uiRightHeadGUID = pSummoned->GetGUID(); - - //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pSummoned->SetVisibility(VISIBILITY_OFF); + m_leftHeadGuid = pSummoned->GetObjectGuid(); + else if (pSummoned->GetEntry() == NPC_RIGHT_HEAD) + m_rightHeadGuid = pSummoned->GetObjectGuid(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_uiLeftHeadGUID); - Creature* pRightHead = m_creature->GetMap()->GetCreature(m_uiRightHeadGUID); + Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); + Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); if (!pLeftHead || !pRightHead) return; @@ -257,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: @@ -271,16 +251,16 @@ 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_uiLeftHeadGUID); - Creature* pRightHead = m_creature->GetMap()->GetCreature(m_uiRightHeadGUID); + Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); + Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); if (!pLeftHead || !pRightHead) return; DoScriptText(YELL_DIE_L, pLeftHead); - pLeftHead->SetDeathState(JUST_DIED); + pLeftHead->ForcedDespawn(1000); if (mob_omrogg_headsAI* pHeadAI = dynamic_cast(pRightHead->AI())) pHeadAI->DoDeathYell(); @@ -289,14 +269,32 @@ 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_uiLeftHeadGUID); - Creature* pRightHead = m_creature->GetMap()->GetCreature(m_uiRightHeadGUID); + Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); + Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); if (!pLeftHead || !pRightHead) return; @@ -331,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 : H_SPELL_BURNING_MAUL); - 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(); } @@ -394,15 +411,15 @@ CreatureAI* GetAI_mob_omrogg_heads(Creature* pCreature) void AddSC_boss_warbringer_omrogg() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_warbringer_omrogg"; - newscript->GetAI = &GetAI_boss_warbringer_omrogg; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_warbringer_omrogg"; + pNewScript->GetAI = &GetAI_boss_warbringer_omrogg; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_omrogg_heads"; - newscript->GetAI = &GetAI_mob_omrogg_heads; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_omrogg_heads"; + pNewScript->GetAI = &GetAI_mob_omrogg_heads; + pNewScript->RegisterSelf(); } 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 1b202abd46..997f53725a 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -26,23 +26,28 @@ boss_warchief_kargath_bladefist EndContentData */ #include "precompiled.h" +#include "shattered_halls.h" -#define SAY_AGGRO1 -1540042 -#define SAY_AGGRO2 -1540043 -#define SAY_AGGRO3 -1540044 -#define SAY_SLAY1 -1540045 -#define SAY_SLAY2 -1540046 -#define SAY_DEATH -1540047 - -#define SPELL_BLADE_DANCE 30739 -#define H_SPELL_CHARGE 25821 - -#define TARGET_NUM 5 - -#define MOB_SHATTERED_ASSASSIN 17695 -#define MOB_HEARTHEN_GUARD 17621 -#define MOB_SHARPSHOOTER_GUARD 17622 -#define MOB_REAVER_GUARD 17623 +enum +{ + SAY_AGGRO1 = -1540042, + SAY_AGGRO2 = -1540043, + SAY_AGGRO3 = -1540044, + SAY_SLAY1 = -1540045, + SAY_SLAY2 = -1540046, + SAY_DEATH = -1540047, + SAY_EVADE = -1540048, + + SPELL_BLADE_DANCE = 30739, + SPELL_CHARGE_H = 25821, + + TARGET_NUM = 5, + + NPC_SHATTERED_ASSASSIN = 17695, + NPC_HEARTHEN_GUARD = 17621, + NPC_SHARPSHOOTER_GUARD = 17622, + NPC_REAVER_GUARD = 17623, +}; float AssassEntrance[3] = {275.136f, -84.29f, 2.3f}; // y -8 float AssassExit[3] = {184.233f, -84.29f, 2.3f}; // y -8 @@ -60,224 +65,240 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - std::vector adds; - std::vector assassins; + GuidVector m_vAddGuids; + GuidVector m_vAssassinGuids; - uint32 Charge_timer; - uint32 Blade_Dance_Timer; - uint32 Summon_Assistant_Timer; - uint32 resetcheck_timer; - uint32 Wait_Timer; + uint32 m_uiChargeTimer; + uint32 m_uiBladeDanceTimer; + uint32 m_uiSummonAssistantTimer; + uint32 m_uiWaitTimer; - uint32 Assassins_Timer; + uint32 m_uiAssassinsTimer; - uint32 summoned; - bool InBlade; + uint32 m_uiSummoned; + bool m_bInBlade; - uint32 target_num; + uint32 m_uiTargetNum; - void Reset() + void Reset() override { - removeAdds(); - m_creature->SetSpeedRate(MOVE_RUN, 2.0f); - summoned = 2; - InBlade = false; - Wait_Timer = 0; + m_uiSummoned = 2; + m_bInBlade = false; + m_uiWaitTimer = 0; - Charge_timer = 0; - Blade_Dance_Timer = 45000; - Summon_Assistant_Timer = 30000; - Assassins_Timer = 5000; - resetcheck_timer = 5000; + m_uiChargeTimer = 0; + m_uiBladeDanceTimer = 45000; + m_uiSummonAssistantTimer = 30000; + m_uiAssassinsTimer = 5000; } - void Aggro(Unit *who) + 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; case 2: DoScriptText(SAY_AGGRO3, m_creature); break; } + + if (m_pInstance) + m_pInstance->SetData(TYPE_BLADEFIST, IN_PROGRESS); } - void JustSummoned(Creature *summoned) + void JustSummoned(Creature* pSummoned) override { - switch(summoned->GetEntry()) + switch (pSummoned->GetEntry()) { - case MOB_HEARTHEN_GUARD: - case MOB_SHARPSHOOTER_GUARD: - case MOB_REAVER_GUARD: - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - summoned->AI()->AttackStart(pTarget); + case NPC_HEARTHEN_GUARD: + case NPC_SHARPSHOOTER_GUARD: + case NPC_REAVER_GUARD: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); - adds.push_back(summoned->GetGUID()); + m_vAddGuids.push_back(pSummoned->GetObjectGuid()); break; - case MOB_SHATTERED_ASSASSIN: - assassins.push_back(summoned->GetGUID()); + case NPC_SHATTERED_ASSASSIN: + m_vAssassinGuids.push_back(pSummoned->GetObjectGuid()); break; } } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* pVictim) override { - if (victim->GetTypeId() == TYPEID_PLAYER) + if (pVictim->GetTypeId() == TYPEID_PLAYER) DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - removeAdds(); + DoDespawnAdds(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BLADEFIST, DONE); } - void MovementInform(uint32 type, uint32 id) + void JustReachedHome() override { - if (InBlade) + DoDespawnAdds(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BLADEFIST, FAIL); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (m_bInBlade) { - if (type != POINT_MOTION_TYPE) + if (uiType != POINT_MOTION_TYPE) return; - if (id != 1) + if (uiPointId != 1) return; - if (target_num > 0) // to prevent loops + if (m_uiTargetNum > 0) // to prevent loops { - Wait_Timer = 1; + m_uiWaitTimer = 1; DoCastSpellIfCan(m_creature, SPELL_BLADE_DANCE, CAST_TRIGGERED); - --target_num; + --m_uiTargetNum; } } } - void removeAdds() + // Note: this should be done by creature linkin in core + void DoDespawnAdds() { - if (!m_pInstance) - return; - - for(std::vector::iterator itr = adds.begin(); itr!= adds.end(); ++itr) + for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) { - if (Creature* pTemp = m_pInstance->instance->GetCreature(*itr)) + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) pTemp->ForcedDespawn(); } - adds.clear(); + m_vAddGuids.clear(); - for(std::vector::iterator itr = assassins.begin(); itr!= assassins.end(); ++itr) + for (GuidVector::const_iterator itr = m_vAssassinGuids.begin(); itr != m_vAssassinGuids.end(); ++itr) { - if (Creature* pTemp = m_pInstance->instance->GetCreature(*itr)) + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) pTemp->ForcedDespawn(); } - assassins.clear(); + m_vAssassinGuids.clear(); } void SpawnAssassin() { - m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassEntrance[0],AssassEntrance[1]+8, AssassEntrance[2], 0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); - m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassEntrance[0],AssassEntrance[1]-8, AssassEntrance[2], 0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); - m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassExit[0],AssassExit[1]+8, AssassExit[2], 0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); - m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassExit[0],AssassExit[1]-8, AssassExit[2], 0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); + 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Assassins_Timer) - if (Assassins_Timer <= diff) + // Check if out of range + if (EnterEvadeIfOutOfCombatArea(uiDiff)) + { + DoScriptText(SAY_EVADE, m_creature); + return; + } + + if (m_uiAssassinsTimer) + { + if (m_uiAssassinsTimer <= uiDiff) { SpawnAssassin(); - Assassins_Timer = 0; - }else Assassins_Timer -= diff; + m_uiAssassinsTimer = 0; + } + else + m_uiAssassinsTimer -= uiDiff; + } - if (InBlade) + if (m_bInBlade) { - if (Wait_Timer) - if (Wait_Timer <= diff) + if (m_uiWaitTimer) + { + if (m_uiWaitTimer <= uiDiff) { - if (target_num <= 0) + if (m_uiTargetNum == 0) { // stop bladedance - InBlade = false; + m_bInBlade = false; m_creature->SetSpeedRate(MOVE_RUN, 2.0f); - (*m_creature).GetMotionMaster()->MoveChase(m_creature->getVictim()); - Wait_Timer = 0; + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiWaitTimer = 0; if (!m_bIsRegularMode) - Charge_timer = 5000; + m_uiChargeTimer = 5000; } else { - //move in bladedance - float x,y,randx,randy; - randx = (rand()%40); - randy = (rand()%40); - x = 210+ randx ; - y = -60- randy ; - (*m_creature).GetMotionMaster()->MovePoint(1,x,y,m_creature->GetPositionZ()); - Wait_Timer = 0; + // move in bladedance + float x, y, randx, 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; } - }else Wait_Timer -= diff; + } + else + m_uiWaitTimer -= uiDiff; + } } - else + else // !m_bInBlade { - if (Blade_Dance_Timer < diff) + if (m_uiBladeDanceTimer < uiDiff) { - target_num = TARGET_NUM; - Wait_Timer = 1; - InBlade = true; - Blade_Dance_Timer = 30000; + m_uiTargetNum = TARGET_NUM; + m_uiWaitTimer = 1; + m_bInBlade = true; + m_uiBladeDanceTimer = 30000; m_creature->SetSpeedRate(MOVE_RUN, 4.0f); return; - }else Blade_Dance_Timer -= diff; + } + else + m_uiBladeDanceTimer -= uiDiff; - if (Charge_timer) - if (Charge_timer <= diff) + if (m_uiChargeTimer) + { + if (m_uiChargeTimer <= uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget, H_SPELL_CHARGE); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_CHARGE_H); - Charge_timer = 0; - }else Charge_timer -= diff; + m_uiChargeTimer = 0; + } + else + m_uiChargeTimer -= uiDiff; + } - if (Summon_Assistant_Timer < diff) + if (m_uiSummonAssistantTimer < uiDiff) { - Unit* target = NULL; - - for(uint32 i = 0; i < summoned; ++i) + for (uint32 i = 0; i < m_uiSummoned; ++i) { - switch(urand(0, 2)) + switch (urand(0, 2)) { - case 0: m_creature->SummonCreature(MOB_HEARTHEN_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); break; - case 1: m_creature->SummonCreature(MOB_SHARPSHOOTER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); break; - case 2: m_creature->SummonCreature(MOB_REAVER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); 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; } } if (!urand(0, 4)) - ++summoned; + ++m_uiSummoned; - Summon_Assistant_Timer = urand(25000, 35000); + m_uiSummonAssistantTimer = urand(25000, 35000); } - else Summon_Assistant_Timer -= diff; + else + m_uiSummonAssistantTimer -= uiDiff; DoMeleeAttackIfReady(); } - - if (resetcheck_timer < diff) - { - uint32 tempx,tempy; - tempx = uint32(m_creature->GetPositionX()); - tempy = uint32(m_creature->GetPositionY()); - if (tempx > 255 || tempx < 205) - { - EnterEvadeMode(); - } - resetcheck_timer = 5000; - }else resetcheck_timer -= diff; } }; @@ -288,9 +309,10 @@ CreatureAI* GetAI_boss_warchief_kargath_bladefist(Creature* pCreature) void AddSC_boss_warchief_kargath_bladefist() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_warchief_kargath_bladefist"; - newscript->GetAI = &GetAI_boss_warchief_kargath_bladefist; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_warchief_kargath_bladefist"; + pNewScript->GetAI = &GetAI_boss_warchief_kargath_bladefist; + pNewScript->RegisterSelf(); } 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 ed3bd7bda3..edbe8074f8 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,87 +24,299 @@ EndScriptData */ #include "precompiled.h" #include "shattered_halls.h" -struct MANGOS_DLL_DECL instance_shattered_halls : public ScriptedInstance +instance_shattered_halls::instance_shattered_halls(Map* pMap) : ScriptedInstance(pMap), + m_uiExecutionTimer(55 * MINUTE* IN_MILLISECONDS), + m_uiTeam(0), + m_uiExecutionStage(0) { - instance_shattered_halls(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} + +void instance_shattered_halls::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +void instance_shattered_halls::OnPlayerEnter(Player* pPlayer) +{ + // Only on heroic + if (instance->IsRegularDifficulty() || m_uiTeam) + return; - uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint64 m_uiNethekurseGUID; - uint64 m_uiNethekurseDoorGUID; + m_uiTeam = pPlayer->GetTeam(); - void Initialize() + 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); +} + +void instance_shattered_halls::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + case GO_NETHEKURSE_DOOR: + if (m_auiEncounter[TYPE_NETHEKURSE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_NETHEKURSE_ENTER_DOOR: + if (m_auiEncounter[TYPE_NETHEKURSE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; - m_uiNethekurseGUID = 0; - m_uiNethekurseDoorGUID = 0; + default: + return; } - bool IsEncounterInProgress() const + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_shattered_halls::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - for(uint8 i = 0; i < MAX_ENCOUNTER; i++) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - return false; + case NPC_NETHEKURSE: + case NPC_KARGATH_BLADEFIST: + case NPC_EXECUTIONER: + case NPC_SOLDIER_ALLIANCE_2: + case NPC_SOLDIER_ALLIANCE_3: + case NPC_OFFICER_ALLIANCE: + case NPC_SOLDIER_HORDE_2: + case NPC_SOLDIER_HORDE_3: + case NPC_OFFICER_HORDE: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void OnObjectCreate(GameObject* pGo) +void instance_shattered_halls::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - if (pGo->GetEntry() == GO_NETHEKURSE_DOOR) - m_uiNethekurseDoorGUID = pGo->GetGUID(); + case TYPE_NETHEKURSE: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoUseDoorOrButton(GO_NETHEKURSE_DOOR); + DoUseDoorOrButton(GO_NETHEKURSE_ENTER_DOOR); + } + break; + case TYPE_OMROGG: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_BLADEFIST: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + // Make executioner attackable only after the final boss is dead + if (Creature* pExecutioner = GetSingleCreatureFromStorage(NPC_EXECUTIONER, true)) + pExecutioner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + } + break; + case TYPE_EXECUTION: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS && !GetSingleCreatureFromStorage(NPC_EXECUTIONER, true)) + { + if (Player* pPlayer = GetPlayerInMap()) + { + // summon the 3 npcs for execution + 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; 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 + DoCastGroupDebuff(SPELL_KARGATH_EXECUTIONER_1); + } + } + if (uiData == DONE) + { + // 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)) + { + 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; } - void OnCreatureCreate(Creature* pCreature) + if (uiData == DONE) { - if (pCreature->GetEntry() == NPC_NETHEKURSE) - m_uiNethekurseGUID = pCreature->GetGUID(); + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_shattered_halls::Load(const char* chrIn) +{ + if (!chrIn) { - switch(uiType) - { - case TYPE_NETHEKURSE: - m_auiEncounter[0] = uiData; - if (uiData == DONE) - DoUseDoorOrButton(m_uiNethekurseDoorGUID); - break; - case TYPE_OMROGG: - m_auiEncounter[1] = uiData; - break; - } + OUT_LOAD_INST_DATA_FAIL; + return; } - uint32 GetData(uint32 uiType) + 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) { - switch(uiType) - { - case TYPE_NETHEKURSE: - return m_auiEncounter[0]; - case TYPE_OMROGG: - return m_auiEncounter[1]; - } - return 0; + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } - uint64 GetData64(uint32 uiData) + OUT_LOAD_INST_DATA_COMPLETE; +} + +uint32 instance_shattered_halls::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_shattered_halls::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_EXECUTIONER) + SetData(TYPE_EXECUTION, DONE); +} + +void instance_shattered_halls::OnCreatureEnterCombat(Creature* pCreature) +{ + // Set data to special in order to pause the event timer + // This is according to the blizz comments which say that it is possible to complete the event if you engage the npc while you have only a few seconds left + if (pCreature->GetEntry() == NPC_EXECUTIONER) + SetData(TYPE_EXECUTION, SPECIAL); +} + +void instance_shattered_halls::OnCreatureEvade(Creature* pCreature) +{ + // If npc evades continue the counting + if (pCreature->GetEntry() == NPC_EXECUTIONER) + SetData(TYPE_EXECUTION, IN_PROGRESS); +} + +bool instance_shattered_halls::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource conditionSourceType) const +{ + switch (uiInstanceConditionId) { - switch(uiData) + 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) + return; + + if (m_uiExecutionTimer < uiDiff) + { + switch (m_uiExecutionStage) { - case NPC_NETHEKURSE: - return m_uiNethekurseGUID; - case GO_NETHEKURSE_DOOR: - return m_uiNethekurseDoorGUID; + case 0: + // Kill the officer + if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_OFFICER_ALLIANCE : NPC_OFFICER_HORDE)) + pSoldier->DealDamage(pSoldier, pSoldier->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + // Make Kargath yell + DoOrSimulateScriptTextForThisInstance(m_uiTeam == ALLIANCE ? SAY_KARGATH_EXECUTE_ALLY : SAY_KARGATH_EXECUTE_HORDE, NPC_KARGATH_BLADEFIST); + + // Set timer for the next execution + DoCastGroupDebuff(SPELL_KARGATH_EXECUTIONER_2); + 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; + break; + case 2: + if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_SOLDIER_ALLIANCE_3 : NPC_SOLDIER_HORDE_3)) + pSoldier->DealDamage(pSoldier, pSoldier->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + SetData(TYPE_EXECUTION, FAIL); + m_uiExecutionTimer = 0; + break; } - return 0; + ++m_uiExecutionStage; + } + else + m_uiExecutionTimer -= uiDiff; +} + +// Add debuff to all players in the instance +void instance_shattered_halls::DoCastGroupDebuff(uint32 uiSpellId) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + Player* pPlayer = itr->getSource(); + if (pPlayer && !pPlayer->HasAura(uiSpellId)) + pPlayer->CastSpell(pPlayer, uiSpellId, true); } -}; +} InstanceData* GetInstanceData_instance_shattered_halls(Map* pMap) { return new instance_shattered_halls(pMap); } +bool AreaTrigger_at_shattered_halls(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) +{ + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; + + instance_shattered_halls* pInstance = (instance_shattered_halls*)pPlayer->GetInstanceData(); + + if (!pInstance) + return false; + + // Only on heroic + if (pInstance->instance->IsRegularDifficulty()) + return false; + + // Don't allow players to cheat + if (pInstance->GetData(TYPE_BLADEFIST) == DONE || pInstance->GetData(TYPE_OMROGG) == DONE) + return false; + + if (pInstance->GetData(TYPE_EXECUTION) == NOT_STARTED) + pInstance->SetData(TYPE_EXECUTION, IN_PROGRESS); + + return true; +} + void AddSC_instance_shattered_halls() { Script* pNewScript; @@ -113,4 +325,9 @@ void AddSC_instance_shattered_halls() pNewScript->Name = "instance_shattered_halls"; pNewScript->GetInstanceData = &GetInstanceData_instance_shattered_halls; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_shattered_halls"; + pNewScript->pAreaTrigger = &AreaTrigger_at_shattered_halls; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h b/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h index 7dba5b8481..24d9b48ac3 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,12 +7,93 @@ enum { - MAX_ENCOUNTER = 2, + MAX_ENCOUNTER = 4, - TYPE_NETHEKURSE = 0, - TYPE_OMROGG = 1, + TYPE_NETHEKURSE = 0, + TYPE_OMROGG = 1, + TYPE_BLADEFIST = 2, // Note: if players skip Omrogg and go straight to Karagth then Omrogg comes to aid Karagth + TYPE_EXECUTION = 3, - GO_NETHEKURSE_DOOR = 182540, - NPC_NETHEKURSE = 16807 + NPC_NETHEKURSE = 16807, + NPC_KARGATH_BLADEFIST = 16808, + NPC_EXECUTIONER = 17301, // must be killed for the executioner event + + NPC_SOLDIER_ALLIANCE_1 = 17288, // quest giver for 9524 + NPC_SOLDIER_ALLIANCE_2 = 17289, + NPC_SOLDIER_ALLIANCE_3 = 17292, + NPC_OFFICER_ALLIANCE = 17290, // quest objective + + NPC_SOLDIER_HORDE_1 = 17294, // quest giver for 9525 + NPC_SOLDIER_HORDE_2 = 17295, + NPC_SOLDIER_HORDE_3 = 17297, + NPC_OFFICER_HORDE = 17296, // quest objective + + GO_NETHEKURSE_DOOR = 182540, + GO_NETHEKURSE_ENTER_DOOR = 182539, + + SPELL_KARGATH_EXECUTIONER_1 = 39288, // 55 min - first prisoner - officer + SPELL_KARGATH_EXECUTIONER_2 = 39289, // 10 min - second prisoner + SPELL_KARGATH_EXECUTIONER_3 = 39290, // 15 min - last prisoner + + // I'm not sure if these texts are used at the execution but this is most likely they are used to + SAY_KARGATH_EXECUTE_ALLY = -1540049, + SAY_KARGATH_EXECUTE_HORDE = -1540050, + + // AT_NETHEKURSE = 4524, // Area trigger used for the execution event +}; + +struct sSpawnLocation +{ + uint32 m_uiAllianceEntry, m_uiHordeEntry; + float m_fX, m_fY, m_fZ, m_fO; +}; + +const float afExecutionerLoc[4] = {151.443f, -84.439f, 1.938f, 6.283f}; + +static sSpawnLocation aSoldiersLocs[] = +{ + {0, NPC_SOLDIER_HORDE_1, 119.609f, 256.127f, -45.254f, 5.133f}, + {NPC_SOLDIER_ALLIANCE_1, 0, 131.106f, 254.520f, -45.236f, 3.951f}, + {NPC_SOLDIER_ALLIANCE_3, NPC_SOLDIER_HORDE_3, 151.040f, -91.558f, 1.936f, 1.559f}, + {NPC_SOLDIER_ALLIANCE_2, NPC_SOLDIER_HORDE_2, 150.669f, -77.015f, 1.933f, 4.705f}, + {NPC_OFFICER_ALLIANCE, NPC_OFFICER_HORDE, 138.241f, -84.198f, 1.907f, 0.055f} +}; + +class MANGOS_DLL_DECL instance_shattered_halls : public ScriptedInstance +{ + public: + instance_shattered_halls(Map* pMap); + + void Initialize() 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) override; + void OnCreatureEnterCombat(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; + + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, ConditionSource conditionSourceType) const override; + + void Update(uint32 uiDiff) override; + + private: + void DoCastGroupDebuff(uint32 uiSpellId); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiExecutionTimer; + uint32 m_uiTeam; + uint8 m_uiExecutionStage; }; + #endif diff --git a/scripts/outland/hellfire_peninsula.cpp b/scripts/outland/hellfire_peninsula.cpp index e9fcf978fc..f642496969 100644 --- a/scripts/outland/hellfire_peninsula.cpp +++ b/scripts/outland/hellfire_peninsula.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,71 +17,70 @@ /* ScriptData SDName: Hellfire_Peninsula SD%Complete: 100 -SDComment: Quest support: 9375, 9410, 9418, 10129, 10146, 10162, 10163, 10340, 10346, 10347, 10382 (Special flight paths), 10838 +SDComment: Quest support: 9375, 9410, 9418, 10629, 10838, 10935. SDCategory: Hellfire Peninsula EndScriptData */ /* ContentData npc_aeranas -go_haaleshi_altar npc_ancestral_wolf npc_demoniac_scryer -npc_gryphoneer_windbellow -npc_naladu -npc_tracy_proudwell -npc_trollbane -npc_wing_commander_dabiree -npc_wing_commander_brack npc_wounded_blood_elf +npc_fel_guard_hound +npc_anchorite_barada +npc_colonel_jules EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "pet_ai.h" /*###### ## npc_aeranas ######*/ -#define SAY_SUMMON -1000138 -#define SAY_FREE -1000139 - -#define FACTION_HOSTILE 16 -#define FACTION_FRIENDLY 35 +enum +{ + SAY_SUMMON = -1000138, + SAY_FREE = -1000139, -#define SPELL_ENVELOPING_WINDS 15535 -#define SPELL_SHOCK 12553 + FACTION_HOSTILE = 16, + FACTION_FRIENDLY = 35, -#define C_AERANAS 17085 + SPELL_ENVELOPING_WINDS = 15535, + SPELL_SHOCK = 12553, +}; struct MANGOS_DLL_DECL 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()) @@ -89,7 +88,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(); @@ -98,17 +96,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(); } @@ -119,16 +121,6 @@ CreatureAI* GetAI_npc_aeranas(Creature* pCreature) return new npc_aeranasAI(pCreature); } -/*###### -## go_haaleshi_altar -######*/ - -bool GOHello_go_haaleshi_altar(Player* pPlayer, GameObject* pGo) -{ - pGo->SummonCreature(C_AERANAS, -1321.79f, 4043.80f, 116.24f, 1.25f, TEMPSUMMON_TIMED_DESPAWN, 180000); - return false; -} - /*###### ## npc_ancestral_wolf ######*/ @@ -149,32 +141,21 @@ struct MANGOS_DLL_DECL npc_ancestral_wolfAI : public npc_escortAI npc_ancestral_wolfAI(Creature* pCreature) : npc_escortAI(pCreature) { if (pCreature->GetOwner() && pCreature->GetOwner()->GetTypeId() == TYPEID_PLAYER) - Start(false, pCreature->GetOwner()->GetGUID()); + 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(); } - Unit* pRyga; - - void Reset() + void Reset() override { - pRyga = NULL; m_creature->CastSpell(m_creature, SPELL_ANCESTRAL_WOLF_BUFF, true); } - void MoveInLineOfSight(Unit* pWho) + void WaypointReached(uint32 uiPointId) override { - if (!pRyga && pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_RYGA && m_creature->IsWithinDistInMap(pWho, 15.0f)) - pRyga = pWho; - - npc_escortAI::MoveInLineOfSight(pWho); - } - - void WaypointReached(uint32 uiPointId) - { - switch(uiPointId) + switch (uiPointId) { case 0: DoScriptText(EMOTE_WOLF_LIFT_HEAD, m_creature); @@ -183,6 +164,7 @@ struct MANGOS_DLL_DECL npc_ancestral_wolfAI : public npc_escortAI DoScriptText(EMOTE_WOLF_HOWL, m_creature); break; case 50: + Creature* pRyga = GetClosestCreatureWithEntry(m_creature, NPC_RYGA, 30.0f); if (pRyga && pRyga->isAlive() && !pRyga->isInCombat()) DoScriptText(SAY_WOLF_WELCOME, pRyga); break; @@ -208,21 +190,21 @@ 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 +// script is basic support, details like end event are not implemented struct MANGOS_DLL_DECL npc_demoniac_scryerAI : public ScriptedAI { npc_demoniac_scryerAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -240,23 +222,23 @@ 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() { ++m_uiButtressCount; - float fAngle; + 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; } @@ -272,10 +254,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) { @@ -292,13 +274,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; @@ -349,16 +331,16 @@ bool GossipHello_npc_demoniac_scryer(Player* pPlayer, Creature* pCreature) if (pPlayer->GetQuestStatus(QUEST_DEMONIAC) == QUEST_STATUS_INCOMPLETE) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ATTUNE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ATTUNED, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ATTUNED, pCreature->GetObjectGuid()); return true; } } - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_PROTECT, pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_PROTECT, pCreature->GetObjectGuid()); 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) { @@ -370,444 +352,570 @@ bool GossipSelect_npc_demoniac_scryer(Player* pPlayer, Creature* pCreature, uint } /*###### -## npc_gryphoneer_windbellow +## npc_wounded_blood_elf ######*/ enum { - QUEST_ABYSSAL_A = 10163, - QUEST_RETURN_ABYSSAL_A = 10346, - QUEST_TO_THE_FRONT = 10382, - SPELL_TAXI_AERIAL_ASSULT = 33899, - SPELL_TAXI_TO_BEACH_HEAD = 35065 -}; + 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 GOSSIP_ITEM1_WIN "Fly me to The Abyssal Shelf" -#define GOSSIP_ITEM2_WIN "Fly me to Honor Point" + NPC_WINDWALKER = 16966, + NPC_TALONGUARD = 16967, + + QUEST_ROAD_TO_FALCON_WATCH = 9375, +}; -bool GossipHello_npc_gryphoneer_windbellow(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_wounded_blood_elfAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} - //Mission: The Abyssal Shelf || Return to the Abyssal Shelf - if (pPlayer->GetQuestStatus(QUEST_ABYSSAL_A) == QUEST_STATUS_INCOMPLETE || - pPlayer->GetQuestStatus(QUEST_RETURN_ABYSSAL_A) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1_WIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + void WaypointReached(uint32 uiPointId) override + { + Player* pPlayer = GetPlayerForEscort(); - //Go to the Front - if (pPlayer->GetQuestStatus(QUEST_TO_THE_FRONT) == QUEST_STATUS_COMPLETE || - pPlayer->GetQuestRewardStatus(QUEST_TO_THE_FRONT)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM2_WIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + if (!pPlayer) + return; - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + switch (uiPointId) + { + case 0: + DoScriptText(SAY_ELF_START, m_creature, pPlayer); + break; + case 9: + DoScriptText(SAY_ELF_SUMMON1, m_creature, pPlayer); + // Spawn two Haal'eshi Talonguard + 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); + break; + case 14: + DoScriptText(SAY_ELF_SUMMON2, m_creature, pPlayer); + // Spawn two Haal'eshi Windwalker + 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); + // Award quest credit + pPlayer->GroupEventHappens(QUEST_ROAD_TO_FALCON_WATCH, m_creature); + break; + } + } -bool GossipSelect_npc_gryphoneer_windbellow(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + void Reset() override { } + + void Aggro(Unit* /*pWho*/) override { - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 589 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_AERIAL_ASSULT,true); + if (HasEscortState(STATE_ESCORT_ESCORTING)) + DoScriptText(SAY_ELF_AGGRO, m_creature); } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + + void JustSummoned(Creature* pSummoned) override { - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 607 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_TO_BEACH_HEAD,true); + pSummoned->AI()->AttackStart(m_creature); } - return true; -} - -/*###### -## npc_naladu -######*/ - -#define GOSSIP_NALADU_ITEM1 "Why don't you escape?" - -enum -{ - GOSSIP_TEXTID_NALADU1 = 9788 }; -bool GossipHello_npc_naladu(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_wounded_blood_elf(Creature* pCreature) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_NALADU_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; + return new npc_wounded_blood_elfAI(pCreature); } -bool GossipSelect_npc_naladu(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestAccept_npc_wounded_blood_elf(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_NALADU1, pCreature->GetGUID()); + if (pQuest->GetQuestId() == QUEST_ROAD_TO_FALCON_WATCH) + { + // Change faction so mobs attack + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + + if (npc_wounded_blood_elfAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest); + } return true; } /*###### -## npc_tracy_proudwell +## npc_fel_guard_hound ######*/ -#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 + SPELL_CREATE_POODAD = 37688, + SPELL_FAKE_DOG_SPART = 37692, + SPELL_INFORM_DOG = 37689, + + NPC_DERANGED_HELBOAR = 16863, }; -bool GossipHello_npc_tracy_proudwell(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_fel_guard_houndAI : public ScriptedPetAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_fel_guard_houndAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_REDEEM_MARKS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + uint32 m_uiPoodadTimer; - 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); + bool m_bIsPooActive; - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + void Reset() override + { + m_uiPoodadTimer = 0; + m_bIsPooActive = false; + } -bool GossipSelect_npc_tracy_proudwell(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - break; - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (DoCastSpellIfCan(m_creature, SPELL_FAKE_DOG_SPART) == CAST_OK) + m_uiPoodadTimer = 2000; } - return true; -} + // Function to allow the boar to move to target + void DoMoveToCorpse(Unit* pBoar) + { + if (!pBoar) + return; -/*###### -## npc_trollbane -######*/ + m_bIsPooActive = true; + m_creature->GetMotionMaster()->MovePoint(1, pBoar->GetPositionX(), pBoar->GetPositionY(), pBoar->GetPositionZ()); + } -#define GOSSIP_TROLLBANE_ITEM1 "Tell me of the Sons of Lothar." -#define GOSSIP_TROLLBANE_ITEM2 "" -#define GOSSIP_TROLLBANE_ITEM3 "Tell me of your homeland." + 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; + } -enum -{ - GOSSIP_TEXTID_TROLLBANE1 = 9932, - GOSSIP_TEXTID_TROLLBANE2 = 9933, - GOSSIP_TEXTID_TROLLBANE3 = 8772 + if (!m_bIsPooActive) + ScriptedPetAI::UpdateAI(uiDiff); + } }; -bool GossipHello_npc_trollbane(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_fel_guard_hound(Creature* pCreature) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TROLLBANE_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TROLLBANE_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; + return new npc_fel_guard_houndAI(pCreature); } -bool GossipSelect_npc_trollbane(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool EffectDummyCreature_npc_fel_guard_hound(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - switch(uiAction) + // always check spellid and effectindex + if (uiSpellId == SPELL_INFORM_DOG && uiEffIndex == EFFECT_INDEX_0) { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TROLLBANE_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_TROLLBANE1, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_TROLLBANE2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_TROLLBANE3, pCreature->GetGUID()); - break; + 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 true; + return false; } /*###### -## npc_wing_commander_dabiree +## npc_anchorite_barada ######*/ enum { - SPELL_TAXI_TO_GATEWAYS = 33768, - SPELL_TAXI_TO_SHATTER = 35069, - QUEST_MISSION_GATEWAYS_A = 10146, - QUEST_SHATTER_POINT = 10340 -}; + SAY_EXORCISM_1 = -1000981, + SAY_EXORCISM_2 = -1000982, + SAY_EXORCISM_3 = -1000983, + SAY_EXORCISM_4 = -1000984, + SAY_EXORCISM_5 = -1000985, + SAY_EXORCISM_6 = -1000986, -#define GOSSIP_ITEM1_DAB "Fly me to Murketh and Shaadraz Gateways" -#define GOSSIP_ITEM2_DAB "Fly me to Shatter Point" + SPELL_BARADA_COMMANDS = 39277, + SPELL_BARADA_FALTERS = 39278, -bool GossipHello_npc_wing_commander_dabiree(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + SPELL_JULES_THREATENS = 39284, + SPELL_JULES_GOES_UPRIGHT = 39294, + SPELL_JULES_VOMITS = 39295, + SPELL_JULES_RELEASE_DARKNESS = 39306, // periodic trigger missing spell 39305 - //Mission: The Murketh and Shaadraz Gateways - if (pPlayer->GetQuestStatus(QUEST_MISSION_GATEWAYS_A) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1_DAB, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + NPC_ANCHORITE_BARADA = 22431, + NPC_COLONEL_JULES = 22432, + NPC_DARKNESS_RELEASED = 22507, // summoned by missing spell 39305 - //Shatter Point - if (pPlayer->GetQuestStatus(QUEST_SHATTER_POINT) == QUEST_STATUS_COMPLETE || - pPlayer->GetQuestRewardStatus(QUEST_SHATTER_POINT)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM2_DAB, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + GOSSIP_ITEM_EXORCISM = -3000111, + QUEST_ID_EXORCISM = 10935, - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + 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 }; -bool GossipSelect_npc_wing_commander_dabiree(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +// Note: script is highly dependent on DBscript implementation +struct MANGOS_DLL_DECL npc_anchorite_baradaAI : public ScriptedAI, private DialogueHelper { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + npc_anchorite_baradaAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aExorcismDialogue) { - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 585 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_TO_GATEWAYS,true); + Reset(); } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + + bool m_bEventComplete; + bool m_bEventInProgress; + + ObjectGuid m_colonelGuid; + + void Reset() override { - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 612 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_TO_SHATTER,true); + m_bEventComplete = false; + m_bEventInProgress = false; } - return true; -} - -/*###### -## npc_wing_commander_brack -######*/ -enum -{ - QUEST_MISSION_GATEWAYS_H = 10129, - QUEST_ABYSSAL_H = 10162, - QUEST_RETURN_ABYSSAL_H = 10347, - QUEST_SPINEBREAKER = 10242, - SPELL_TAXI_GATEWAYS_H = 33659, - SPELL_TAXI_ASSULT_H = 33825, - SPELL_TAXI_SPINEBREAKER = 34578 -}; + void AttackStart(Unit* pWho) override + { + // no attack during the exorcism + if (m_bEventInProgress) + return; -#define GOSSIP_ITEM1_BRA "I'm on a bombing mission for Forward Commander To'arch. I need a wyvern destroyer!" -#define GOSSIP_ITEM2_BRA "Fly me to The Abyssal Shelf" -#define GOSSIP_ITEM3_BRA "Lend me a Wind Rider, I'm going to Spinebreaker Post." + ScriptedAI::AttackStart(pWho); + } -bool GossipHello_npc_wing_commander_brack(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + void EnterEvadeMode() override + { + // no evade during the exorcism + if (m_bEventInProgress) + return; - //Mission: The Murketh and Shaadraz Gateways - if (pPlayer->GetQuestStatus(QUEST_MISSION_GATEWAYS_H) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + ScriptedAI::EnterEvadeMode(); + } - //Mission: The Abyssal Shelf || Return to the Abyssal Shelf - if (pPlayer->GetQuestStatus(QUEST_ABYSSAL_H) == QUEST_STATUS_INCOMPLETE || - pPlayer->GetQuestStatus(QUEST_RETURN_ABYSSAL_H) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM2_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + bool IsExorcismComplete() { return m_bEventComplete; } - //Spinebreaker Post - if (pPlayer->GetQuestStatus(QUEST_SPINEBREAKER) == QUEST_STATUS_COMPLETE || - pPlayer->GetQuestRewardStatus(QUEST_SPINEBREAKER)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM3_BRA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + 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(); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); -bool GossipSelect_npc_wing_commander_brack(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 584 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_GATEWAYS_H,true); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 587 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_ASSULT_H,true); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->CLOSE_GOSSIP_MENU(); - //TaxiPath 604 - pPlayer->CastSpell(pPlayer,SPELL_TAXI_SPINEBREAKER,true); - break; + StartNextDialogueText(SAY_EXORCISM_1); + } } - return true; -} -/*###### -## npc_wounded_blood_elf -######*/ + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != WAYPOINT_MOTION_TYPE) + return; -#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 + 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; -#define QUEST_ROAD_TO_FALCON_WATCH 9375 + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + m_creature->SetFacingToObject(pColonel); + pColonel->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } -struct MANGOS_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI -{ - npc_wounded_blood_elfAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} + 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 WaypointReached(uint32 i) + void JustDidDialogueStep(int32 iEntry) override { - Player* pPlayer = GetPlayerForEscort(); - - if (!pPlayer) - return; - - switch (i) + switch (iEntry) { - case 0: - DoScriptText(SAY_ELF_START, m_creature, pPlayer); + case QUEST_ID_EXORCISM: + m_creature->GetMotionMaster()->MoveWaypoint(); break; - 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); + case SPELL_BARADA_COMMANDS: + DoCastSpellIfCan(m_creature, SPELL_BARADA_COMMANDS); break; - case 13: - DoScriptText(SAY_ELF_RESTING, m_creature, pPlayer); + 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 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); + 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 27: - DoScriptText(SAY_ELF_COMPLETE, m_creature, pPlayer); - // Award quest credit - pPlayer->GroupEventHappens(QUEST_ROAD_TO_FALCON_WATCH, m_creature); + 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; } } - void Reset() { } - - void Aggro(Unit* who) + Creature* GetSpeakerByEntry(uint32 uiEntry) override { - if (HasEscortState(STATE_ESCORT_ESCORTING)) - DoScriptText(SAY_ELF_AGGRO, m_creature); + switch (uiEntry) + { + case NPC_ANCHORITE_BARADA: return m_creature; + case NPC_COLONEL_JULES: return m_creature->GetMap()->GetCreature(m_colonelGuid); + + default: + return NULL; + } } - void JustSummoned(Creature* summoned) + void UpdateAI(const uint32 uiDiff) override { - summoned->AI()->AttackStart(m_creature); + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_npc_wounded_blood_elf(Creature* pCreature) +CreatureAI* GetAI_npc_anchorite_barada(Creature* pCreature) { - return new npc_wounded_blood_elfAI(pCreature); + return new npc_anchorite_baradaAI(pCreature); } -bool QuestAccept_npc_wounded_blood_elf(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool GossipHello_npc_anchorite_barada(Player* pPlayer, Creature* pCreature) { - if (pQuest->GetQuestId() == QUEST_ROAD_TO_FALCON_WATCH) + // 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) { - // Change faction so mobs attack - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); + pCreature->AI()->SendAIEvent(AI_EVENT_START_EVENT, pPlayer, pCreature); + pPlayer->CLOSE_GOSSIP_MENU(); + } - if (npc_wounded_blood_elfAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + 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; +} + void AddSC_hellfire_peninsula() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_aeranas"; - newscript->GetAI = &GetAI_npc_aeranas; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_haaleshi_altar"; - newscript->pGOHello = &GOHello_go_haaleshi_altar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_ancestral_wolf"; - newscript->GetAI = &GetAI_npc_ancestral_wolf; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_demoniac_scryer"; - newscript->GetAI = &GetAI_npc_demoniac_scryer; - newscript->pGossipHello = &GossipHello_npc_demoniac_scryer; - newscript->pGossipSelect = &GossipSelect_npc_demoniac_scryer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_gryphoneer_windbellow"; - newscript->pGossipHello = &GossipHello_npc_gryphoneer_windbellow; - newscript->pGossipSelect = &GossipSelect_npc_gryphoneer_windbellow; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_naladu"; - newscript->pGossipHello = &GossipHello_npc_naladu; - newscript->pGossipSelect = &GossipSelect_npc_naladu; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tracy_proudwell"; - newscript->pGossipHello = &GossipHello_npc_tracy_proudwell; - newscript->pGossipSelect = &GossipSelect_npc_tracy_proudwell; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_trollbane"; - newscript->pGossipHello = &GossipHello_npc_trollbane; - newscript->pGossipSelect = &GossipSelect_npc_trollbane; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_wing_commander_dabiree"; - newscript->pGossipHello = &GossipHello_npc_wing_commander_dabiree; - newscript->pGossipSelect = &GossipSelect_npc_wing_commander_dabiree; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_wing_commander_brack"; - newscript->pGossipHello = &GossipHello_npc_wing_commander_brack; - newscript->pGossipSelect = &GossipSelect_npc_wing_commander_brack; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_wounded_blood_elf"; - newscript->GetAI = &GetAI_npc_wounded_blood_elf; - newscript->pQuestAccept = &QuestAccept_npc_wounded_blood_elf; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_aeranas"; + pNewScript->GetAI = &GetAI_npc_aeranas; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ancestral_wolf"; + pNewScript->GetAI = &GetAI_npc_ancestral_wolf; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_demoniac_scryer"; + pNewScript->GetAI = &GetAI_npc_demoniac_scryer; + pNewScript->pGossipHello = &GossipHello_npc_demoniac_scryer; + pNewScript->pGossipSelect = &GossipSelect_npc_demoniac_scryer; + 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(); } diff --git a/scripts/outland/nagrand.cpp b/scripts/outland/nagrand.cpp index e7e6dd87e4..d2f94e6314 100644 --- a/scripts/outland/nagrand.cpp +++ b/scripts/outland/nagrand.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,80 +17,30 @@ /* ScriptData SDName: Nagrand SD%Complete: 90 -SDComment: Quest support: 9849, 9868, 9874, 9918, 9991, 10044, 10085, 10107, 10108, 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_shattered_rumbler mob_lump -mob_sunspring_villager -npc_altruis_the_sufferer -npc_greatmother_geyah -npc_lantresor_of_the_blade -npc_maghar_captive +npc_nagrand_captive npc_creditmarker_visit_with_ancestors +npc_rethhedron EndContentData */ #include "precompiled.h" #include "escort_ai.h" /*###### -## mob_shattered_rumbler - this should be done with ACID -######*/ - -struct MANGOS_DLL_DECL mob_shattered_rumblerAI : public ScriptedAI -{ - bool Spawn; - - mob_shattered_rumblerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - Spawn = false; - } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - if (Spellkind->Id == 32001 && !Spawn) - { - float x = m_creature->GetPositionX(); - float y = m_creature->GetPositionY(); - float z = m_creature->GetPositionZ(); - - Hitter->SummonCreature(18181,x+(0.7 * (rand()%30)),y+(rand()%5),z,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,60000); - Hitter->SummonCreature(18181,x+(rand()%5),y-(rand()%5),z,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,60000); - Hitter->SummonCreature(18181,x-(rand()%5),y+(0.5 *(rand()%60)),z,0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,60000); - m_creature->SetDeathState(CORPSE); - Spawn = true; - } - return; - } -}; -CreatureAI* GetAI_mob_shattered_rumbler(Creature* pCreature) -{ - return new mob_shattered_rumblerAI(pCreature); -} - -/*###### -## mob_lump - TODO: remove gossip, can be done in database +## mob_lump ######*/ enum { - QUEST_NOT_ON_MY_WATCH = 9918, - NPC_LUMPS_QUEST_CREDIT = 18354, - SAY_LUMP_AGGRO_1 = -1000190, SAY_LUMP_AGGRO_2 = -1000191, SAY_LUMP_DEFEAT = -1000192, - TEXT_ID_LUMP_1 = 9352, - TEXT_ID_LUMP_2 = 9353, - TEXT_ID_LUMP_3 = 9354, - TEXT_ID_LUMP_4 = 9355, - TEXT_ID_LUMP_5 = 9356, - SPELL_VISUAL_SLEEP = 16093, SPELL_SPEAR_THROW = 32248, @@ -109,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; @@ -129,31 +76,27 @@ 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) { - Player* pPlayer = pDealer->GetCharmerOrOwnerPlayerOrPlayerItself(); - if (!m_bReset && pPlayer && pPlayer->GetQuestStatus(QUEST_NOT_ON_MY_WATCH) == QUEST_STATUS_INCOMPLETE) - { - uiDamage = 0; //Take 0 damage + uiDamage = 0; // Take 0 damage - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); + 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); + // 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->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME); - m_creature->SetStandState(UNIT_STAND_STATE_SIT); - DoScriptText(SAY_LUMP_DEFEAT, m_creature, pPlayer); + m_creature->SetStandState(UNIT_STAND_STATE_SIT); + DoScriptText(SAY_LUMP_DEFEAT, m_creature); - m_bReset = true; - } + m_bReset = true; } } - 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); @@ -164,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) @@ -200,306 +143,8 @@ CreatureAI* GetAI_mob_lump(Creature* pCreature) return new mob_lumpAI(pCreature); } -bool GossipHello_mob_lump(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(QUEST_NOT_ON_MY_WATCH) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I need answers, ogre!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_LUMP_1, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_mob_lump(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Why are Boulderfist out this far? You know that this is Kurenai territory.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_LUMP_2, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "And you think you can just eat anything you want? You're obviously trying to eat the Broken of Telaar.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_LUMP_3, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "This means war, Lump! War I say!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_LUMP_4, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_LUMP_5, pCreature->GetGUID()); - pPlayer->TalkedToCreature(NPC_LUMPS_QUEST_CREDIT, pCreature->GetGUID()); - break; - } - return true; -} - -/*#### -# mob_sunspring_villager - should be done with ACID -####*/ - -struct MANGOS_DLL_DECL mob_sunspring_villagerAI : public ScriptedAI -{ - mob_sunspring_villagerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - } - - void SpellHit(Unit *caster, const SpellEntry *spell) - { - if (spell->Id == 32146) - { - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_creature->RemoveCorpse(); - } - } -}; -CreatureAI* GetAI_mob_sunspring_villager(Creature* pCreature) -{ - return new mob_sunspring_villagerAI(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->GetGUID()); - - //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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+14: - pPlayer->SEND_GOSSIP_MENU(9424, pCreature->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - - 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->GetGUID()); - } - 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->GetGUID()); - } - else - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 15: - pPlayer->AreaExploredOrEventHappens(10172); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - } - return true; -} - /*###### -## npc_lantresor_of_the_blade -######*/ - -bool GossipHello_npc_lantresor_of_the_blade(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(10107) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(10108) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I have killed many of your ogres, Lantresor. I have no fear.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(9361, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_lantresor_of_the_blade(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Should I know? You look like an orc to me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(9362, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "And the other half?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(9363, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I have heard of your kind, but I never thought to see the day when I would meet a half-breed.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(9364, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "My apologies. I did not mean to offend. I am here on behalf of my people.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(9365, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "My people ask that you pull back your Boulderfist ogres and cease all attacks on our territories. In return, we will also pull back our forces.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(9366, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "We will fight you until the end, then, Lantresor. We will not stand idly by as you pillage our towns and kill our people.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(9367, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What do I need to do?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - pPlayer->SEND_GOSSIP_MENU(9368, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->SEND_GOSSIP_MENU(9369, pCreature->GetGUID()); - if (pPlayer->GetQuestStatus(10107) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(10107); - if (pPlayer->GetQuestStatus(10108) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(10108); - break; - } - return true; -} - -/*##### -## npc_maghar_captive +## npc_nagrand_captive #####*/ enum @@ -512,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, @@ -525,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 MANGOS_DLL_DECL 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 + { + DoCastSpellIfCan(m_creature, SPELL_EARTHBIND_TOTEM); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override { - m_creature->CastSpell(m_creature, SPELL_EARTHBIND_TOTEM, false); + 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) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + 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); @@ -582,11 +273,11 @@ struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI if (pSummoned->IsTotem()) return; - pSummoned->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + pSummoned->SetWalk(false); 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) { @@ -597,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; @@ -614,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; @@ -623,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; @@ -633,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->GetGUID(), 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); } /*###### @@ -672,9 +353,9 @@ struct MANGOS_DLL_DECL npc_creditmarker_visit_with_ancestorsAI : public Scripted { 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)) { @@ -685,7 +366,7 @@ struct MANGOS_DLL_DECL npc_creditmarker_visit_with_ancestorsAI : public Scripted { // 18840: Sunspring, 18841: Laughing, 18842: Garadar, 18843: Bleeding if (!((Player*)pWho)->GetReqKillOrCastCurrentCount(QUEST_VISIT_WITH_ANCESTORS, creditMarkerId)) - ((Player*)pWho)->KilledMonsterCredit(creditMarkerId, m_creature->GetGUID()); + ((Player*)pWho)->KilledMonsterCredit(creditMarkerId, m_creature->GetObjectGuid()); } } } @@ -698,57 +379,195 @@ CreatureAI* GetAI_npc_creditmarker_visit_with_ancestors(Creature* pCreature) } /*###### -## AddSC +## npc_rethhedron ######*/ -void AddSC_nagrand() +enum { - Script* pNewScript; + SAY_LOW_HP = -1000966, + SAY_EVENT_END = -1000967, - pNewScript = new Script; - pNewScript->Name = "mob_shattered_rumbler"; - pNewScript->GetAI = &GetAI_mob_shattered_rumbler; - pNewScript->RegisterSelf(); + 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 - pNewScript = new Script; - pNewScript->Name = "mob_lump"; - pNewScript->GetAI = &GetAI_mob_lump; - pNewScript->pGossipHello = &GossipHello_mob_lump; - pNewScript->pGossipSelect = &GossipSelect_mob_lump; - pNewScript->RegisterSelf(); + SPELL_COSMETIC_LEGION_RING = 41339, + SPELL_QUEST_COMPLETE = 41340, - pNewScript = new Script; - pNewScript->Name = "mob_sunspring_villager"; - pNewScript->GetAI = &GetAI_mob_sunspring_villager; - pNewScript->RegisterSelf(); + NPC_SPELLBINDER = 22342, + NPC_RETHHEDRONS_TARGET = 23416, - pNewScript = new Script; - pNewScript->Name = "npc_altruis_the_sufferer"; - pNewScript->pGossipHello = &GossipHello_npc_altruis_the_sufferer; - pNewScript->pGossipSelect = &GossipSelect_npc_altruis_the_sufferer; - pNewScript->pQuestAccept = &QuestAccept_npc_altruis_the_sufferer; - pNewScript->RegisterSelf(); + POINT_ID_PORTAL_FRONT = 0, + POINT_ID_PORTAL = 1, +}; - pNewScript = new Script; - pNewScript->Name = "npc_greatmother_geyah"; - pNewScript->pGossipHello = &GossipHello_npc_greatmother_geyah; - pNewScript->pGossipSelect = &GossipSelect_npc_greatmother_geyah; - pNewScript->RegisterSelf(); +static const float afRethhedronPos[2][3] = +{ + { -1502.39f, 9772.33f, 200.421f}, + { -1557.93f, 9834.34f, 200.949f} +}; + +struct MANGOS_DLL_DECL 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; pNewScript = new Script; - pNewScript->Name = "npc_lantresor_of_the_blade"; - pNewScript->pGossipHello = &GossipHello_npc_lantresor_of_the_blade; - pNewScript->pGossipSelect = &GossipSelect_npc_lantresor_of_the_blade; + pNewScript->Name = "mob_lump"; + pNewScript->GetAI = &GetAI_mob_lump; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_maghar_captive"; - pNewScript->GetAI = &GetAI_npc_maghar_captive; - pNewScript->pQuestAccept = &QuestAccept_npc_maghar_captive; + 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_creditmarker_visit_with_ancestors"; pNewScript->GetAI = &GetAI_npc_creditmarker_visit_with_ancestors; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_rethhedron"; + pNewScript->GetAI = &GetAI_npc_rethhedron; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/netherstorm.cpp b/scripts/outland/netherstorm.cpp index f9ec680923..29a31441e5 100644 --- a/scripts/outland/netherstorm.cpp +++ b/scripts/outland/netherstorm.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Netherstorm SD%Complete: 80 -SDComment: Quest support: 10438, 10652 (special flight paths), 10299, 10321, 10322, 10323, 10329, 10330, 10337, 10338, 10365(Shutting Down Manaforge), 10198, 10191 +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,14 +25,17 @@ EndScriptData */ npc_manaforge_control_console go_manaforge_control_console npc_commander_dawnforge -npc_protectorate_nether_drake -npc_veronia npc_bessy npc_maxx_a_million +npc_zeppit +npc_protectorate_demolitionist +npc_captured_vanguard +npc_drijya EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "pet_ai.h" /*###### ## npc_manaforge_control_console @@ -81,120 +84,114 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI { npc_manaforge_control_consoleAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint64 m_uiPlayerGUID; - uint64 m_uiConsoleGUID; + ObjectGuid m_playerGuid; + ObjectGuid m_consoleGuid; uint32 m_uiEventTimer; uint32 m_uiWaveTimer; uint32 m_uiPhase; bool m_bWave; - void Reset() + void Reset() override { - m_uiPlayerGUID = 0; - m_uiConsoleGUID = 0; + m_playerGuid.Clear(); + m_consoleGuid.Clear(); m_uiEventTimer = 3000; m_uiWaveTimer = 0; m_uiPhase = 1; 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); - if (m_uiPlayerGUID) - { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); - if (pPlayer) + if (pPlayer) + { + switch (m_creature->GetEntry()) { - switch(m_creature->GetEntry()) - { - case NPC_BNAAR_C_CONSOLE: - pPlayer->FailQuest(QUEST_SHUTDOWN_BNAAR_ALDOR); - pPlayer->FailQuest(QUEST_SHUTDOWN_BNAAR_SCRYERS); - break; - case NPC_CORUU_C_CONSOLE: - pPlayer->FailQuest(QUEST_SHUTDOWN_CORUU_ALDOR); - pPlayer->FailQuest(QUEST_SHUTDOWN_CORUU_SCRYERS); - break; - case NPC_DURO_C_CONSOLE: - pPlayer->FailQuest(QUEST_SHUTDOWN_DURO_ALDOR); - pPlayer->FailQuest(QUEST_SHUTDOWN_DURO_SCRYERS); - break; - case NPC_ARA_C_CONSOLE: - pPlayer->FailQuest(QUEST_SHUTDOWN_ARA_ALDOR); - pPlayer->FailQuest(QUEST_SHUTDOWN_ARA_SCRYERS); - break; - } + case NPC_BNAAR_C_CONSOLE: + pPlayer->FailQuest(QUEST_SHUTDOWN_BNAAR_ALDOR); + pPlayer->FailQuest(QUEST_SHUTDOWN_BNAAR_SCRYERS); + break; + case NPC_CORUU_C_CONSOLE: + pPlayer->FailQuest(QUEST_SHUTDOWN_CORUU_ALDOR); + pPlayer->FailQuest(QUEST_SHUTDOWN_CORUU_SCRYERS); + break; + case NPC_DURO_C_CONSOLE: + pPlayer->FailQuest(QUEST_SHUTDOWN_DURO_ALDOR); + pPlayer->FailQuest(QUEST_SHUTDOWN_DURO_SCRYERS); + break; + case NPC_ARA_C_CONSOLE: + pPlayer->FailQuest(QUEST_SHUTDOWN_ARA_ALDOR); + pPlayer->FailQuest(QUEST_SHUTDOWN_ARA_SCRYERS); + break; } } - if (m_uiConsoleGUID) - { - if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_uiConsoleGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - } + if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_consoleGuid)) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); } void DoWaveSpawnForCreature(Creature* pCreature) { 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; @@ -206,50 +203,54 @@ 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) { - if (!m_uiPlayerGUID) - return; - - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pPlayer) + { + // Reset Event + if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_consoleGuid)) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + + m_creature->ForcedDespawn(); return; + } - switch(m_uiPhase) + switch (m_uiPhase) { case 1: DoScriptText(EMOTE_START, m_creature, pPlayer); @@ -276,13 +277,12 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI break; case 5: DoScriptText(EMOTE_COMPLETE, m_creature, pPlayer); - pPlayer->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetGUID()); + pPlayer->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); DoCastSpellIfCan(m_creature, SPELL_DISABLE_VISUAL); - if (m_uiConsoleGUID) - { - if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_uiConsoleGUID)) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - } + + if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_consoleGuid)) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + ++m_uiPhase; break; } @@ -311,41 +311,41 @@ CreatureAI* GetAI_npc_manaforge_control_console(Creature* pCreature) ######*/ // TODO: clean up this workaround when mangos adds support to do it properly (with gossip selections instead of instant summon) -bool GOHello_go_manaforge_control_console(Player* pPlayer, GameObject* pGo) +bool GOUse_go_manaforge_control_console(Player* pPlayer, GameObject* pGo) { if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) { - pPlayer->PrepareQuestMenu(pGo->GetGUID()); - pPlayer->SendPreparedQuest(pGo->GetGUID()); + pPlayer->PrepareQuestMenu(pGo->GetObjectGuid()); + pPlayer->SendPreparedQuest(pGo->GetObjectGuid()); } 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; } @@ -353,8 +353,8 @@ bool GOHello_go_manaforge_control_console(Player* pPlayer, GameObject* pGo) { if (npc_manaforge_control_consoleAI* pManaforgeAI = dynamic_cast(pManaforge->AI())) { - pManaforgeAI->m_uiPlayerGUID = pPlayer->GetGUID(); - pManaforgeAI->m_uiConsoleGUID = pGo->GetGUID(); + pManaforgeAI->m_playerGuid = pPlayer->GetObjectGuid(); + pManaforgeAI->m_consoleGuid = pGo->GetObjectGuid(); } pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); @@ -391,22 +391,22 @@ enum struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI { - npc_commander_dawnforgeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset (); } + npc_commander_dawnforgeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 m_uiPlayerGUID; - uint64 m_uiArdonisGUID; - uint64 m_uiPathaleonGUID; + ObjectGuid m_playerGuid; + ObjectGuid m_ardonisGuid; + ObjectGuid m_pathaleonGuid; uint32 m_uiPhase; uint32 m_uiPhaseSubphase; uint32 m_uiPhaseTimer; bool m_bIsEvent; - void Reset() + void Reset() override { - m_uiPlayerGUID = 0; - m_uiArdonisGUID = 0; - m_uiPathaleonGUID = 0; + m_playerGuid.Clear(); + m_ardonisGuid.Clear(); + m_pathaleonGuid.Clear(); m_uiPhase = 1; m_uiPhaseSubphase = 0; @@ -414,17 +414,17 @@ 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_uiPathaleonGUID = pSummoned->GetGUID(); + m_pathaleonGuid = pSummoned->GetObjectGuid(); } void TurnToPathaleonsImage() { - Creature* pArdonis = m_creature->GetMap()->GetCreature(m_uiArdonisGUID); - Creature* pPathaleon = m_creature->GetMap()->GetCreature(m_uiPathaleonGUID); - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Creature* pArdonis = m_creature->GetMap()->GetCreature(m_ardonisGuid); + Creature* pPathaleon = m_creature->GetMap()->GetCreature(m_pathaleonGuid); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pArdonis || !pPathaleon || !pPlayer) return; @@ -439,9 +439,9 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI void TurnToEachOther() { - if (Creature* pArdonis = m_creature->GetMap()->GetCreature(m_uiArdonisGUID)) + if (Creature* pArdonis = m_creature->GetMap()->GetCreature(m_ardonisGuid)) { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pPlayer) return; @@ -464,8 +464,8 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI if (!pArdonis) return false; - m_uiArdonisGUID = pArdonis->GetGUID(); - m_uiPlayerGUID = pPlayer->GetGUID(); + m_ardonisGuid = pArdonis->GetObjectGuid(); + m_playerGuid = pPlayer->GetObjectGuid(); m_bIsEvent = true; @@ -477,7 +477,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) @@ -490,9 +490,9 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI return; } - Creature* pArdonis = m_creature->GetMap()->GetCreature(m_uiArdonisGUID); - Creature* pPathaleon = m_creature->GetMap()->GetCreature(m_uiPathaleonGUID); - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Creature* pArdonis = m_creature->GetMap()->GetCreature(m_ardonisGuid); + Creature* pPathaleon = m_creature->GetMap()->GetCreature(m_pathaleonGuid); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pArdonis || !pPlayer) { @@ -535,7 +535,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(); @@ -551,7 +551,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); @@ -599,7 +599,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)) @@ -617,81 +617,10 @@ bool AreaTrigger_at_commander_dawnforge(Player* pPlayer, AreaTriggerEntry const* pDawnforgeAI->CanStartEvent(pPlayer); return true; } - - } 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->GetGUID()); - 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_veronia -######*/ - -enum -{ - QUEST_BEHIND_ENEMY_LINES = 10652, - SPELL_STEALTH_FLIGHT = 34905 -}; - -#define GOSSIP_ITEM_FLY_CORUU "Fly me to Manaforge Coruu please" - -bool GossipHello_npc_veronia(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - // Behind Enemy Lines - if (pPlayer->GetQuestStatus(QUEST_BEHIND_ENEMY_LINES) && !pPlayer->GetQuestRewardStatus(QUEST_BEHIND_ENEMY_LINES)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FLY_CORUU, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_veronia(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_STEALTH_FLIGHT, true);//TaxiPath 606 - } - return true; -} - /*###### ## npc_bessy ######*/ @@ -709,18 +638,18 @@ struct MANGOS_DLL_DECL 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()) @@ -729,30 +658,29 @@ 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->GetGUID(), pQuest); + pBessyAI->Start(true, pPlayer, pQuest); } return true; } CreatureAI* GetAI_npc_bessy(Creature* pCreature) { - return new npc_bessyAI(pCreature); + return new npc_bessyAI(pCreature); } /*###### @@ -777,37 +705,30 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI uint8 m_uiSubEvent; uint32 m_uiSubEventTimer; - uint64 m_uiAlleyGUID; - uint64 m_uiLastDraeneiMachineGUID; + ObjectGuid m_alleyGuid; + ObjectGuid m_lastDraeneiMachineGuid; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { m_uiSubEvent = 0; m_uiSubEventTimer = 0; - m_uiAlleyGUID = 0; - m_uiLastDraeneiMachineGUID = 0; + m_alleyGuid.Clear(); + m_lastDraeneiMachineGuid.Clear(); // 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; @@ -818,26 +739,26 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI if (GameObject* pMachine = GetClosestGameObjectWithEntry(m_creature, GO_DRAENEI_MACHINE, INTERACTION_DISTANCE)) { m_creature->SetFacingToObject(pMachine); - m_uiLastDraeneiMachineGUID = pMachine->GetGUID(); + m_lastDraeneiMachineGuid = pMachine->GetObjectGuid(); m_uiSubEvent = 2; m_uiSubEventTimer = 1000; } else - m_uiLastDraeneiMachineGUID = 0; + m_lastDraeneiMachineGuid.Clear(); break; case 36: if (Player* pPlayer = GetPlayerForEscort()) pPlayer->GroupEventHappens(QUEST_MARK_V_IS_ALIVE, m_creature); - if (Creature* pAlley = m_creature->GetMap()->GetCreature(m_uiAlleyGUID)) + if (Creature* pAlley = m_creature->GetMap()->GetCreature(m_alleyGuid)) DoScriptText(SAY_ALLEY_FINISH, pAlley); break; } } - void WaypointStart(uint32 uiPoint) + void WaypointStart(uint32 uiPoint) override { switch (uiPoint) { @@ -849,7 +770,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()) { @@ -860,9 +781,9 @@ 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_uiAlleyGUID = pAlley->GetGUID(); + m_alleyGuid = pAlley->GetObjectGuid(); DoScriptText(SAY_ALLEY_FAREWELL, pAlley); } m_uiSubEventTimer = 0; @@ -874,10 +795,10 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI m_uiSubEvent = 3; break; case 3: // Despawn machine after 2s - if (GameObject* pMachine = m_creature->GetMap()->GetGameObject(m_uiLastDraeneiMachineGUID)) + if (GameObject* pMachine = m_creature->GetMap()->GetGameObject(m_lastDraeneiMachineGuid)) pMachine->Use(m_creature); - m_uiLastDraeneiMachineGUID = 0; + m_lastDraeneiMachineGuid.Clear(); m_uiSubEventTimer = 0; m_uiSubEvent = 0; break; @@ -907,25 +828,583 @@ 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->GetGUID(), pQuest, true); + pEscortAI->Start(false, pPlayer, pQuest, true); + } + } + return true; +} + +/*###### +## npc_zeppit +######*/ + +enum +{ + EMOTE_GATHER_BLOOD = -1000625, + NPC_WARP_CHASER = 18884, + SPELL_GATHER_WARP_BLOOD = 39244, // for quest 10924 +}; + +struct MANGOS_DLL_DECL npc_zeppitAI : public ScriptedPetAI +{ + npc_zeppitAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + void Reset() override { } + + void OwnerKilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetEntry() == NPC_WARP_CHASER) + { + // Distance not known, be assumed to be ~10 yards, possibly a bit less. + if (m_creature->IsWithinDistInMap(pVictim, 10.0f)) + { + DoScriptText(EMOTE_GATHER_BLOOD, m_creature); + m_creature->CastSpell(m_creature, SPELL_GATHER_WARP_BLOOD, false); + } + } + } +}; + +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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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; +} + void AddSC_netherstorm() { Script* pNewScript; pNewScript = new Script; pNewScript->Name = "go_manaforge_control_console"; - pNewScript->pGOHello = &GOHello_go_manaforge_control_console; + pNewScript->pGOUse = &GOUse_go_manaforge_control_console; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -944,26 +1423,36 @@ void AddSC_netherstorm() 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->Name = "npc_bessy"; + pNewScript->GetAI = &GetAI_npc_bessy; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_bessy; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_maxx_a_million"; + pNewScript->GetAI = &GetAI_npc_maxx_a_million; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_maxx_a_million; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_veronia"; - pNewScript->pGossipHello = &GossipHello_npc_veronia; - pNewScript->pGossipSelect = &GossipSelect_npc_veronia; + pNewScript->Name = "npc_zeppit"; + pNewScript->GetAI = &GetAI_npc_zeppit; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_bessy"; - pNewScript->GetAI = &GetAI_npc_bessy; - pNewScript->pQuestAccept = &QuestAccept_npc_bessy; + pNewScript->Name = "npc_protectorate_demolitionist"; + pNewScript->GetAI = &GetAI_npc_protectorate_demolitionist; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_maxx_a_million"; - pNewScript->GetAI = &GetAI_npc_maxx_a_million; - pNewScript->pQuestAccept = &QuestAccept_npc_maxx_a_million; + 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(); } diff --git a/scripts/outland/shadowmoon_valley.cpp b/scripts/outland/shadowmoon_valley.cpp index 1c8d60e6a4..173e0b79b7 100644 --- a/scripts/outland/shadowmoon_valley.cpp +++ b/scripts/outland/shadowmoon_valley.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,27 +17,28 @@ /* ScriptData SDName: Shadowmoon_Valley SD%Complete: 100 -SDComment: Quest support: 10519, 10583, 10601, 10781, 10814, 10804, 10854, 11082. Vendor Drake Dealer Hurlunk. +SDComment: Quest support: 11020, 10458, 10480, 10481, 10514, 10540, 10588, 10781, 10804, 10854. SDCategory: Shadowmoon Valley EndScriptData */ /* ContentData mob_mature_netherwing_drake mob_enslaved_netherwing_drake -npc_drake_dealer_hurlunk -npcs_flanis_swiftwing_and_kagrosh -npc_murkblood_overseer -npc_neltharaku -npc_karynaku -npc_oronok_tornheart +npc_dragonmaw_peon npc_wilda mob_torloth npc_lord_illidan_stormrage +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" #include "escort_ai.h" +#include "pet_ai.h" /*##### # mob_mature_netherwing_drake @@ -50,97 +51,102 @@ 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 { mob_mature_netherwing_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 uiPlayerGUID; - - bool bCanEat; - bool bIsEating; + ObjectGuid m_playerGuid; - uint32 EatTimer; - uint32 CastTimer; + uint32 m_uiEatTimer; + uint32 m_uiCreditTimer; + uint32 m_uiCastTimer; - void Reset() + void Reset() override { - uiPlayerGUID = 0; + 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)) { - uiPlayerGUID = pCaster->GetGUID(); - bCanEat = true; + m_playerGuid = pCaster->GetObjectGuid(); + 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_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (bCanEat || bIsEating) + 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(uiPlayerGUID)) - { - if (GameObject* pGo = pPlayer->GetGameObject(SPELL_PLACE_CARCASS)) - { - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) - m_creature->GetMotionMaster()->MovementExpired(); + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) + m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->StopMoving(); + m_creature->GetMotionMaster()->MoveIdle(); - m_creature->GetMotionMaster()->MovePoint(POINT_ID, pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ()); - } - } - bCanEat = false; + float fX, fY, fZ; + pGo->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); + + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } - else if (bIsEating) - { - DoCastSpellIfCan(m_creature, SPELL_JUST_EATEN); - DoScriptText(SAY_JUST_EATEN, m_creature); + m_uiEatTimer = 0; + } + else + m_uiEatTimer -= uiDiff; - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(uiPlayerGUID)) - pPlayer->KilledMonsterCredit(NPC_EVENT_PINGER, m_creature->GetGUID()); + return; + } - Reset(); - m_creature->GetMotionMaster()->Clear(); - } + 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()); + + Reset(); + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + m_creature->GetMotionMaster()->Clear(); + m_uiCreditTimer = 0; } else - EatTimer -= diff; + m_uiCreditTimer -= uiDiff; return; } @@ -148,11 +154,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(); } @@ -169,7 +177,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, @@ -184,33 +191,25 @@ struct MANGOS_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI { mob_enslaved_netherwing_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) { - PlayerGUID = 0; - Tapped = false; + m_uiFlyTimer = 0; Reset(); } - uint64 PlayerGUID; - uint32 FlyTimer; - bool Tapped; - - void Reset() - { - if (!Tapped) - m_creature->setFaction(FACTION_DEFAULT); + ObjectGuid m_playerGuid; + uint32 m_uiFlyTimer; - FlyTimer = 2500; - } + void Reset() override { } - 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; - PlayerGUID = pPlayer->GetGUID(); + 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); @@ -218,49 +217,50 @@ 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(PlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { if (pPlayer->GetQuestStatus(QUEST_FORCE_OF_NELT) == QUEST_STATUS_INCOMPLETE) { DoCastSpellIfCan(pPlayer, SPELL_FORCE_OF_NELTHARAKU, CAST_TRIGGERED); - PlayerGUID = 0; + 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; } @@ -274,320 +274,166 @@ CreatureAI* GetAI_mob_enslaved_netherwing_drake(Creature* pCreature) } /*##### -# mob_dragonmaw_peon +# npc_dragonmaw_peon #####*/ enum { + SAY_PEON_1 = -1000652, + SAY_PEON_2 = -1000653, + SAY_PEON_3 = -1000654, + SAY_PEON_4 = -1000655, + SAY_PEON_5 = -1000656, + SPELL_SERVING_MUTTON = 40468, NPC_DRAGONMAW_KILL_CREDIT = 23209, - QUEST_SLOW_DEATH = 11020, + EQUIP_ID_MUTTON = 2202, POINT_DEST = 1 }; -struct MANGOS_DLL_DECL mob_dragonmaw_peonAI : public ScriptedAI +struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI { - mob_dragonmaw_peonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_dragonmaw_peonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint64 m_uiPlayerGUID; - bool m_bIsTapped; + ObjectGuid m_playerGuid; uint32 m_uiPoisonTimer; + uint32 m_uiMoveTimer; + uint32 m_uiEatTimer; - void Reset() + void Reset() override { - m_uiPlayerGUID = 0; - m_bIsTapped = false; + m_playerGuid.Clear(); m_uiPoisonTimer = 0; + m_uiMoveTimer = 0; + m_uiEatTimer = 0; + + SetEquipmentSlots(true); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + bool SetPlayerTarget(ObjectGuid playerGuid) { - if (!pCaster) - return; + // Check if event already started + if (m_playerGuid) + return false; - if (pCaster->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_SERVING_MUTTON && !m_bIsTapped) - { - m_uiPlayerGUID = pCaster->GetGUID(); - - m_bIsTapped = true; - - float fX, fY, fZ; - pCaster->GetClosePoint(fX, fY, fZ, m_creature->GetObjectBoundingRadius()); - - m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - m_creature->GetMotionMaster()->MovePoint(POINT_DEST, fX, fY, fZ); - } + m_playerGuid = playerGuid; + m_uiMoveTimer = 500; + return true; } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; if (uiPointId == POINT_DEST) { - m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_EAT); - m_uiPoisonTimer = 15000; + m_uiEatTimer = 2000; + m_uiPoisonTimer = 3000; + + switch (urand(0, 4)) + { + case 0: DoScriptText(SAY_PEON_1, m_creature); break; + case 1: DoScriptText(SAY_PEON_2, m_creature); break; + case 2: DoScriptText(SAY_PEON_3, m_creature); break; + case 3: DoScriptText(SAY_PEON_4, m_creature); break; + case 4: DoScriptText(SAY_PEON_5, m_creature); break; + } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_uiPoisonTimer) + if (m_uiMoveTimer) { - if (m_uiPoisonTimer <= uiDiff) + if (m_uiMoveTimer <= uiDiff) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { - if (pPlayer->GetQuestStatus(QUEST_SLOW_DEATH) == QUEST_STATUS_INCOMPLETE) - pPlayer->KilledMonsterCredit(NPC_DRAGONMAW_KILL_CREDIT, m_creature->GetGUID()); - } - - m_uiPoisonTimer = 0; - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else - m_uiPoisonTimer -= uiDiff; - } - } -}; - -/*###### -## 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->GetGUID()); - - return true; -} + GameObject* pMutton = pPlayer->GetGameObject(SPELL_SERVING_MUTTON); -bool GossipSelect_npc_drake_dealer_hurlunk(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - - return true; -} - -/*###### -## npc_flanis_swiftwing_and_kagrosh -######*/ - -bool GossipHello_npcs_flanis_swiftwing_and_kagrosh(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(10583) == QUEST_STATUS_INCOMPLETE && !pPlayer->HasItemCount(30658,1,true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Take Flanis's Pack", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - if (pPlayer->GetQuestStatus(10601) == QUEST_STATUS_INCOMPLETE && !pPlayer->HasItemCount(30659,1,true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Take Kagrosh's Pack", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npcs_flanis_swiftwing_and_kagrosh(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(30658, 1)) - pPlayer->SendNewItem(pItem, 1, true, false); + // Workaround for broken function GetGameObject + if (!pMutton) + { + SpellEntry const* pSpell = GetSpellStore()->LookupEntry(SPELL_SERVING_MUTTON); - pPlayer->CLOSE_GOSSIP_MENU(); - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - { - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(30659, 1)) - pPlayer->SendNewItem(pItem, 1, true, false); + SpellEffectEntry const* effectEntry = pSpell->GetSpellEffect(EFFECT_INDEX_0); + if (effectEntry) + { + uint32 uiGameobjectEntry = effectEntry->EffectMiscValue; - pPlayer->CLOSE_GOSSIP_MENU(); - } - return true; -} + // this can fail, but very low chance + pMutton = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2 * INTERACTION_DISTANCE); + } + } -/*###### -## npc_murkblood_overseer -######*/ + if (pMutton) + { + float fX, fY, fZ; + pMutton->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); -#define QUEST_11082 11082 + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_DEST, fX, fY, fZ); + } + } -bool GossipHello_npc_murkblood_overseer(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(QUEST_11082) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I am here for you, overseer.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + m_uiMoveTimer = 0; + } + else + m_uiMoveTimer -= uiDiff; + } + else if (m_uiEatTimer) + { + if (m_uiEatTimer <= uiDiff) + { + SetEquipmentSlots(false, EQUIP_ID_MUTTON, EQUIP_UNEQUIP); + m_creature->HandleEmote(EMOTE_ONESHOT_EAT_NOSHEATHE); + m_uiEatTimer = 0; + } + else + m_uiEatTimer -= uiDiff; + } + else if (m_uiPoisonTimer) + { + if (m_uiPoisonTimer <= uiDiff) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->KilledMonsterCredit(NPC_DRAGONMAW_KILL_CREDIT, m_creature->GetObjectGuid()); - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - return true; -} + m_uiPoisonTimer = 0; -bool GossipSelect_npc_murkblood_overseer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "How dare you question an overseer of the Dragonmaw!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - //correct id not known - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Who speaks of me? What are you talking about, broken?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - //correct id not known - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Continue please.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - //correct id not known - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Who are these bidders?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - //correct id not known - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Well... yes.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - //correct id not known - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - //correct id not known - pPlayer->SEND_GOSSIP_MENU(10940, pCreature->GetGUID()); - pCreature->CastSpell(pPlayer,41121,false); - pPlayer->AreaExploredOrEventHappens(QUEST_11082); - break; + // dies + m_creature->SetDeathState(JUST_DIED); + m_creature->SetHealth(0); + } + else + m_uiPoisonTimer -= uiDiff; + } } - return true; -} - -/*###### -## npc_neltharaku -######*/ - -bool GossipHello_npc_neltharaku(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestStatus(10814) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I am listening, dragon", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(10613, pCreature->GetGUID()); - - return true; -} +}; -bool GossipSelect_npc_neltharaku(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +CreatureAI* GetAI_npc_dragonmaw_peon(Creature* pCreature) { - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "But you are dragons! How could orcs do this to you?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(10614, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Your mate?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(10615, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I have battled many beasts, dragon. I will help you.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(10616, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(10814); - break; - } - return true; + return new npc_dragonmaw_peonAI(pCreature); } -/*###### -## npc_oronok -######*/ - -#define GOSSIP_ORONOK1 "I am ready to hear your story, Oronok." -#define GOSSIP_ORONOK2 "How do I find the cipher?" -#define GOSSIP_ORONOK3 "How do you know all of this?" -#define GOSSIP_ORONOK4 "Yet what? What is it, Oronok?" -#define GOSSIP_ORONOK5 "Continue, please." -#define GOSSIP_ORONOK6 "So what of the cipher now? And your boys?" -#define GOSSIP_ORONOK7 "I will find your boys and the cipher, Oronok." - -bool GossipHello_npc_oronok_tornheart(Player* pPlayer, Creature* pCreature) +bool EffectDummyCreature_npc_dragonmaw_peon(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + if (uiEffIndex != EFFECT_INDEX_1 || uiSpellId != SPELL_SERVING_MUTTON || pCaster->GetTypeId() != TYPEID_PLAYER) + return false; - if (pPlayer->GetQuestStatus(10519) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(10312, pCreature->GetGUID()); - }else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + npc_dragonmaw_peonAI* pPeonAI = dynamic_cast(pCreatureTarget->AI()); - return true; -} + if (!pPeonAI) + return false; -bool GossipSelect_npc_oronok_tornheart(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) + if (pPeonAI->SetPlayerTarget(pCaster->GetObjectGuid())) { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(10313, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(10314, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(10315, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(10316, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(10317, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ORONOK7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->SEND_GOSSIP_MENU(10318, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(10519); - break; + pCreatureTarget->HandleEmote(EMOTE_ONESHOT_NONE); + return true; } - 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; + return false; } /*###### @@ -614,29 +460,29 @@ enum QUEST_ESCAPE_COILSCAR = 10451, NPC_COILSKAR_ASSASSIN = 21044, - FACTION_EARTHEN = 1726 //guessed + FACTION_EARTHEN = 1726 // guessed }; -//this script needs verification +// this script needs verification struct MANGOS_DLL_DECL npc_wildaAI : public npc_escortAI { npc_wildaAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } uint32 m_uiHealingTimer; - void Reset() + void Reset() override { m_uiHealingTimer = 0; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(uiPointId) + switch (uiPointId) { case 13: DoScriptText(SAY_WIL_PROGRESS1, m_creature, pPlayer); @@ -688,16 +534,16 @@ struct MANGOS_DLL_DECL npc_wildaAI : public npc_escortAI } } - 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 + // this is very unclear, random say without no real relevance to script/event void DoRandomSay() { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_WIL_PROGRESS2, m_creature); break; case 1: DoScriptText(SAY_WIL_PROGRESS4, m_creature); break; @@ -707,24 +553,24 @@ struct MANGOS_DLL_DECL npc_wildaAI : public npc_escortAI void DoSpawnAssassin() { - //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); - m_creature->SummonCreature(NPC_COILSKAR_ASSASSIN, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + m_creature->SummonCreature(NPC_COILSKAR_ASSASSIN, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { - //don't always use + // don't always use if (urand(0, 4)) return; - //only aggro text if not player + // only aggro text if not player if (pWho->GetTypeId() != TYPEID_PLAYER) { - //appears to be random - switch(urand(0, 3)) + // 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; @@ -732,12 +578,12 @@ struct MANGOS_DLL_DECL npc_wildaAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //TODO: add more abilities + // TODO: add more abilities if (m_creature->GetHealthPercent() <= 30.0f) { if (m_uiHealingTimer < uiDiff) @@ -763,10 +609,10 @@ 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_EARTHEN, TEMPFACTION_RESTORE_RESPAWN); if (npc_wildaAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -782,7 +628,7 @@ enum EVENT_COOLDOWN = 30000, SAY_TORLOTH_DIALOGUE1 = -1000532, - SAY_TORLOTH_DIALOGUE2 = -1000533, + SAY_TORLOTH_DIALOGUE2 = -1000533, SAY_TORLOTH_DIALOGUE3 = -1000534, SAY_ILLIDAN_DIALOGUE = -1000535, SAY_ILLIDAN_SUMMON1 = -1000536, @@ -816,56 +662,48 @@ struct TorlothCinematic uint32 uiTimer; }; -static TorlothCinematic TorlothAnim[]= +static TorlothCinematic TorlothAnim[] = { {SAY_TORLOTH_DIALOGUE1, TORLOTH, 2000}, {SAY_ILLIDAN_DIALOGUE, LORD_ILLIDAN, 7000}, {SAY_TORLOTH_DIALOGUE2, TORLOTH, 3000}, {0, TORLOTH, 2000}, // Torloth stand - {SAY_TORLOTH_DIALOGUE3, TORLOTH, 1000}, + {SAY_TORLOTH_DIALOGUE3, TORLOTH, 1000}, {0, TORLOTH, 3000}, {0, TORLOTH, 0} }; -struct Location -{ - float fLocX; - float fLocY; - float fLocZ; - 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 { uint8 uiSpawnCount; uint8 uiUsedSpawnPoint; - uint32 uiCreatureId; + uint32 uiCreatureId; uint32 uiSpawnTimer; uint32 uiYellTimer; int32 iTextId; }; -static WaveData WavesInfo[]= +static WaveData WavesInfo[] = { // Illidari Soldier {9, 0, NPC_ILLIDARI_SOLDIER, 10000, 7000, SAY_ILLIDAN_SUMMON1}, @@ -892,8 +730,8 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI { mob_torlothAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint64 m_uiLordIllidanGUID; - uint64 m_uiPlayerGUID; + ObjectGuid m_lordIllidanGuid; + ObjectGuid m_playerGuid; uint32 m_uiCleaveTimer; uint32 m_uiShadowfuryTimer; @@ -901,10 +739,10 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI uint8 m_uiAnimationCount; uint32 m_uiAnimationTimer; - void Reset() + void Reset() override { - m_uiLordIllidanGUID = 0; - m_uiPlayerGUID = 0; + m_lordIllidanGuid.Clear(); + m_playerGuid.Clear(); m_uiAnimationCount = 0; m_uiAnimationTimer = 4000; @@ -917,7 +755,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI SetCombatMovement(false); } - void EnterEvadeMode() + void EnterEvadeMode() override { m_creature->ForcedDespawn(); } @@ -928,7 +766,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI if (TorlothAnim[m_uiAnimationCount].uiCreature == LORD_ILLIDAN) { - pCreature = m_creature->GetMap()->GetCreature(m_uiLordIllidanGUID); + pCreature = m_creature->GetMap()->GetCreature(m_lordIllidanGuid); if (!pCreature) { @@ -942,16 +780,16 @@ 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); - break; + break; case 3: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; case 5: - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_playerGuid)) { m_creature->AddThreat(pTarget); m_creature->SetFacingToObject(pTarget); @@ -960,7 +798,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI break; case 6: { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_playerGuid)) { SetCombatMovement(true); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -975,13 +813,13 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI ++m_uiAnimationCount; } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (Player* pPlayer = pKiller->GetCharmerOrOwnerPlayerOrPlayerItself()) { pPlayer->GroupEventHappens(QUEST_BATTLE_OF_THE_CRIMSON_WATCH, m_creature); - - if (Creature* pLordIllidan = m_creature->GetMap()->GetCreature(m_uiLordIllidanGUID)) + + if (Creature* pLordIllidan = m_creature->GetMap()->GetCreature(m_lordIllidanGuid)) { DoScriptText(SAY_EVENT_COMPLETED, pLordIllidan, pPlayer); pLordIllidan->AI()->EnterEvadeMode(); @@ -989,7 +827,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiAnimationCount < 7) { @@ -1045,7 +883,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement { npc_lord_illidan_stormrageAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; uint32 m_uiWaveTimer; uint32 m_uiAnnounceTimer; uint32 m_uiCheckTimer; @@ -1056,9 +894,9 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement bool m_bEventFailed; bool m_bWaveAnnounced; - void Reset() + void Reset() override { - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_uiWaveTimer = 10000; m_uiAnnounceTimer = 7000; @@ -1075,7 +913,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement void StartEvent(Player* pPlayer) { m_bEventStarted = true; - m_uiPlayerGUID = pPlayer->GetGUID(); + m_playerGuid = pPlayer->GetObjectGuid(); } void SummonWave() @@ -1085,13 +923,13 @@ 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; - fLocY = SpawnLocation[uiLocIndex + i].fLocY; - fLocZ = SpawnLocation[uiLocIndex + i].fLocZ; - fOrient = SpawnLocation[uiLocIndex + i].fOrient; + fLocX = SpawnLocation[uiLocIndex + i].x; + fLocY = SpawnLocation[uiLocIndex + i].y; + fLocZ = SpawnLocation[uiLocIndex + i].z; + fOrient = SpawnLocation[uiLocIndex + i].o; if (Creature* pSpawn = m_creature->SummonCreature(WavesInfo[m_uiWaveCount].uiCreatureId, fLocX, fLocY, fLocZ, fOrient, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000)) { @@ -1099,7 +937,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; @@ -1122,25 +960,25 @@ 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; - if (!m_uiPlayerGUID) + if (!m_playerGuid) return; if (pSummoned->GetEntry() == NPC_TORLOTH_THE_MAGNIFICENT) { if (mob_torlothAI* pTorlothAI = dynamic_cast(pSummoned->AI())) { - pTorlothAI->m_uiLordIllidanGUID = m_creature->GetGUID(); - pTorlothAI->m_uiPlayerGUID = m_uiPlayerGUID; + pTorlothAI->m_lordIllidanGuid = m_creature->GetObjectGuid(); + pTorlothAI->m_playerGuid = m_playerGuid; } } else { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_playerGuid)) { float fLocX, fLocY, fLocZ; pTarget->GetPosition(fLocX, fLocY, fLocZ); @@ -1149,7 +987,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; @@ -1160,7 +998,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement void CheckEventFail() { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pPlayer) return; @@ -1170,7 +1008,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()) { @@ -1201,7 +1039,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()) { @@ -1220,9 +1058,9 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_uiPlayerGUID || !m_bEventStarted) + if (!m_playerGuid || !m_bEventStarted) return; if (!m_uiMobCount && m_uiWaveCount < 4) @@ -1254,7 +1092,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); } @@ -1262,9 +1100,9 @@ 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 (pQuest->GetQuestId() == QUEST_BATTLE_OF_THE_CRIMSON_WATCH) if (Creature* pLordIllidan = GetClosestCreatureWithEntry(pPlayer, NPC_LORD_ILLIDAN, 50.0)) if (npc_lord_illidan_stormrageAI* pIllidanAI = dynamic_cast(pLordIllidan->AI())) if (!pIllidanAI->m_bEventStarted) @@ -1273,73 +1111,792 @@ bool GOQuestAccept_GO_crystal_prison(Player* pPlayer, GameObject* pGo, Quest con return true; } +/*###### +## npc_totem_of_spirits +######*/ + +enum +{ + QUEST_SPIRITS_FIRE_AND_EARTH = 10458, + QUEST_SPIRITS_WATER = 10480, + QUEST_SPIRITS_AIR = 10481, + + // quest 10458, 10480, 10481 + SPELL_ELEMENTAL_SIEVE = 36035, + 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 + + 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 +{ + npc_totem_of_spiritsAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + void Reset() override {} + + void UpdateAI(const uint32 /*uiDiff*/) override {} + void AttackedBy(Unit* /*pAttacker*/) override {} + + 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; + + uint32 uiEntry = pVictim->GetEntry(); + + // make elementals cast the sieve is only way to make it work properly, due to the spell target modes 22/7 + 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) +{ + return new npc_totem_of_spiritsAI(pCreature); +} + +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) + { + case SPELL_EARTH_CAPTURED: + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_EARTH_CAPTURED_CREDIT, true); + return true; + } + case SPELL_FIERY_CAPTURED: + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_FIERY_CAPTURED_CREDIT, true); + return true; + } + case SPELL_WATER_CAPTURED: + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_WATER_CAPTURED_CREDIT, true); + return true; + } + case SPELL_AIR_CAPTURED: + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_AIR_CAPTURED_CREDIT, true); + return true; + } + } + + return false; +} + +bool EffectAuraDummy_npc_totem_of_spirits(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() != SPELL_ELEMENTAL_SIEVE) + return true; + + if (pAura->GetEffIndex() != EFFECT_INDEX_0) + return true; + + if (bApply) // possible it should be some visual effects, using "enraged soul" npc and "Cosmetic: ... soul" spell + return true; + + Creature* pCreature = (Creature*)pAura->GetTarget(); + Unit* pCaster = pAura->GetCaster(); + + // aura only affect the spirit totem, since this is the one that need to be in range. + // It is possible though, that player is the one who should actually have the aura + // and check for presense of spirit totem, but then we can't script the dummy. + if (!pCreature || !pCreature->IsPet() || !pCaster) + return true; + + // Summon the soul of the spirit and cast the visual + uint32 uiSoulEntry = 0; + switch (pCaster->GetEntry()) + { + 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) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_UNIT) + { + Player* pOwner = (Player*)((Creature*)pSource)->GetOwner(); + + if (!pOwner) + return true; + + switch (uiEventId) + { + case EVENT_EARTH: + pOwner->KilledMonsterCredit(NPC_CREDIT_MARKER_EARTH); + return true; + case EVENT_FIERY: + pOwner->KilledMonsterCredit(NPC_CREDIT_MARKER_FIERY); + return true; + case EVENT_WATER: + pOwner->KilledMonsterCredit(NPC_CREDIT_MARKER_WATER); + return true; + case EVENT_AIR: + pOwner->KilledMonsterCredit(NPC_CREDIT_MARKER_AIR); + return true; + } + } + + return false; +} + +/*##### +#npc_spawned_oronok_tornheart +#####*/ + +enum +{ + // texts + SAY_ORONOK_TOGETHER = -1000803, + SAY_ORONOK_READY = -1000804, + SAY_ORONOK_ELEMENTS = -1000805, + SAY_ORONOK_EPILOGUE_1 = -1000806, + SAY_TORLOK_EPILOGUE_2 = -1000807, + SAY_ORONOK_EPILOGUE_3 = -1000808, + SAY_EARTH_EPILOGUE_4 = -1000809, + SAY_FIRE_EPILOGUE_5 = -1000810, + SAY_EARTH_EPILOGUE_6 = -1000811, + SAY_ORONOK_EPILOGUE_7 = -1000812, + EMOTE_GIVE_WEAPONS = -1000813, + SAY_ORONOK_EPILOGUE_8 = -1000814, + + GOSSIP_ITEM_FIGHT = -3000109, + GOSSIP_TEXT_ID_ORONOK = 10421, + + // spells - some are already defined above + // SPELL_CHAIN_LIGHTNING = 16006, + SPELL_EARTHBIND_TOTEM = 15786, + // 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_REDEEMED_SPIRIT_OF_EARTH = 21739, + NPC_REDEEMED_SPIRIT_OF_FIRE = 21740, + NPC_REDEEMED_SPIRIT_OF_AIR = 21738, + NPC_REDEEMED_SPIRIT_OF_WATER = 21741, + NPC_EARTHMENDER_TORLOK = 21024, + + GO_MARK_OF_KAELTHAS = 185170, + + QUEST_CIPHER_OF_DAMNATION = 10588, + + POINT_ID_ATTACK_READY = 1, + POINT_ID_ELEMENTS = 2, + POINT_ID_EPILOGUE = 3, +}; + +static const DialogueEntry aOutroDialogue[] = +{ + {QUEST_CIPHER_OF_DAMNATION, 0, 1000}, + {NPC_CYRUKH_THE_FIRELORD, 0, 0}, + {NPC_EARTHMENDER_TORLOK, 0, 1000}, + {SAY_ORONOK_EPILOGUE_1, NPC_ORONOK_TORN_HEART, 5000}, + {SAY_TORLOK_EPILOGUE_2, NPC_EARTHMENDER_TORLOK, 5000}, + {NPC_REDEEMED_SPIRIT_OF_EARTH, 0, 5000}, + {SAY_ORONOK_EPILOGUE_3, NPC_ORONOK_TORN_HEART, 5000}, + {SAY_EARTH_EPILOGUE_4, NPC_REDEEMED_SPIRIT_OF_EARTH, 5000}, + {SAY_FIRE_EPILOGUE_5, NPC_REDEEMED_SPIRIT_OF_FIRE, 14000}, + {SAY_EARTH_EPILOGUE_6, NPC_REDEEMED_SPIRIT_OF_EARTH, 6000}, + {SAY_ORONOK_EPILOGUE_7, NPC_ORONOK_TORN_HEART, 6000}, + {EMOTE_GIVE_WEAPONS, NPC_ORONOK_TORN_HEART, 6000}, + {SAY_ORONOK_EPILOGUE_8, NPC_ORONOK_TORN_HEART, 10000}, + {NPC_ORONOK_TORN_HEART, 0, 0}, + {0, 0, 0}, +}; + +const static EVENTLOCATION 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 +}; + +struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, private DialogueHelper +{ + npc_spawned_oronok_tornheartAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aOutroDialogue) + { + Reset(); + StartNextDialogueText(QUEST_CIPHER_OF_DAMNATION); + } + + uint32 m_uiLightningTimer; + uint32 m_uiTotemTimer; + uint32 m_uiFrostTimer; + uint32 m_uiHealTimer; + + ObjectGuid m_torlokGuid; + ObjectGuid m_fireSpiritGuid; + ObjectGuid m_earthSpiritGuid; + ObjectGuid m_borakGuid; + ObjectGuid m_gromtorGuid; + ObjectGuid m_cyrukhGuid; + + bool m_bHasAttackStart; + + void Reset() override + { + m_uiLightningTimer = 15000; + m_uiTotemTimer = 10000; + m_uiFrostTimer = 20000; + m_uiHealTimer = 8000; + + m_bHasAttackStart = false; + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case NPC_CYRUKH_THE_FIRELORD: + // Set them in motion + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_ATTACK_READY, aDamnationLocations[4].m_fX, aDamnationLocations[4].m_fY, aDamnationLocations[4].m_fZ); + 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); + } + 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); + } + break; + case NPC_EARTHMENDER_TORLOK: + if (Creature* pTorlok = GetClosestCreatureWithEntry(m_creature, NPC_EARTHMENDER_TORLOK, 25.0f)) + { + m_torlokGuid = pTorlok->GetObjectGuid(); + m_creature->SetFacingToObject(pTorlok); + } + break; + case NPC_REDEEMED_SPIRIT_OF_EARTH: + m_creature->SetFacingTo(4.9f); + m_creature->SummonCreature(NPC_REDEEMED_SPIRIT_OF_FIRE, aDamnationLocations[0].m_fX, aDamnationLocations[0].m_fY, aDamnationLocations[0].m_fZ, aDamnationLocations[0].m_fO, TEMPSUMMON_TIMED_DESPAWN, 32000); + m_creature->SummonCreature(NPC_REDEEMED_SPIRIT_OF_EARTH, aDamnationLocations[1].m_fX, aDamnationLocations[1].m_fY, aDamnationLocations[1].m_fZ, aDamnationLocations[1].m_fO, TEMPSUMMON_TIMED_DESPAWN, 32000); + m_creature->SummonCreature(NPC_REDEEMED_SPIRIT_OF_WATER, aDamnationLocations[2].m_fX, aDamnationLocations[2].m_fY, aDamnationLocations[2].m_fZ, aDamnationLocations[2].m_fO, TEMPSUMMON_TIMED_DESPAWN, 32000); + m_creature->SummonCreature(NPC_REDEEMED_SPIRIT_OF_AIR, aDamnationLocations[3].m_fX, aDamnationLocations[3].m_fY, aDamnationLocations[3].m_fZ, aDamnationLocations[3].m_fO, TEMPSUMMON_TIMED_DESPAWN, 32000); + break; + case SAY_ORONOK_EPILOGUE_7: + if (Creature* pTorlok = m_creature->GetMap()->GetCreature(m_torlokGuid)) + m_creature->SetFacingToObject(pTorlok); + break; + case NPC_ORONOK_TORN_HEART: + if (GameObject* pMark = GetClosestGameObjectWithEntry(m_creature, GO_MARK_OF_KAELTHAS, 30.0f)) + { + pMark->SetRespawnTime(5 * MINUTE); + pMark->Refresh(); + } + if (Creature* pBorak = m_creature->GetMap()->GetCreature(m_borakGuid)) + pBorak->ForcedDespawn(); + if (Creature* pGromtor = m_creature->GetMap()->GetCreature(m_gromtorGuid)) + pGromtor->ForcedDespawn(); + m_creature->ForcedDespawn(); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_ORONOK_TORN_HEART: return m_creature; + case NPC_EARTHMENDER_TORLOK: return m_creature->GetMap()->GetCreature(m_torlokGuid); + case NPC_REDEEMED_SPIRIT_OF_EARTH: return m_creature->GetMap()->GetCreature(m_earthSpiritGuid); + case NPC_REDEEMED_SPIRIT_OF_FIRE: return m_creature->GetMap()->GetCreature(m_fireSpiritGuid); + + default: + return NULL; + } + } + + void Aggro(Unit* pWho) override + { + if (!m_bHasAttackStart && pWho->GetEntry() == NPC_EARTH_SPIRIT) + { + // Cyrukh starts to attack + if (Creature* pCyrukh = m_creature->GetMap()->GetCreature(m_cyrukhGuid)) + { + pCyrukh->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pCyrukh->AI()->AttackStart(m_creature); + AttackStart(pCyrukh); + m_bHasAttackStart = true; + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_REDEEMED_SPIRIT_OF_FIRE: + m_fireSpiritGuid = pSummoned->GetObjectGuid(); + break; + case NPC_REDEEMED_SPIRIT_OF_EARTH: + m_earthSpiritGuid = pSummoned->GetObjectGuid(); + break; + } + } + + 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 (Creature* pCyrukh = m_creature->GetMap()->GetCreature(m_cyrukhGuid)) + { + if (!pCyrukh->isAlive()) + m_creature->GetMotionMaster()->MovePoint(POINT_ID_EPILOGUE, aDamnationLocations[6].m_fX, aDamnationLocations[6].m_fY, aDamnationLocations[6].m_fZ); + } + else + { + 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) override + { + if (uiMotionType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case POINT_ID_ATTACK_READY: + // Get Cyrukh guid now, because we are at a closer distance + if (Creature* pCyrukh = GetClosestCreatureWithEntry(m_creature, NPC_CYRUKH_THE_FIRELORD, 70.0f)) + m_cyrukhGuid = pCyrukh->GetObjectGuid(); + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + DoScriptText(SAY_ORONOK_READY, m_creature); + break; + case POINT_ID_ELEMENTS: + // Attack the closest earth element + if (Creature* pElement = GetClosestCreatureWithEntry(m_creature, NPC_EARTH_SPIRIT, 50.0f)) + AttackStart(pElement); + break; + case POINT_ID_EPILOGUE: + StartNextDialogueText(NPC_EARTHMENDER_TORLOK); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiLightningTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiLightningTimer = urand(9000, 15000); + } + } + else + m_uiLightningTimer -= uiDiff; + + if (m_uiTotemTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EARTHBIND_TOTEM) == CAST_OK) + m_uiTotemTimer = urand(40000, 60000); + } + else + m_uiTotemTimer -= uiDiff; + + if (m_uiFrostTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK) == CAST_OK) + m_uiFrostTimer = urand(14000, 18000); + } + else + m_uiFrostTimer -= uiDiff; + + if (m_uiHealTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HEALING_WAVE) == CAST_OK) + m_uiHealTimer = urand(6000, 10000); + } + else + m_uiHealTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_spawned_oronok_tornheart(Creature* pCreature) +{ + return new npc_spawned_oronok_tornheartAI(pCreature); +} + +bool GossipHello_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreature) +{ + 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->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_ORONOK, pCreature->GetObjectGuid()); + } + else + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + // Note: this movement expects MMaps. + DoScriptText(SAY_ORONOK_ELEMENTS, pCreature); + pCreature->GetMotionMaster()->MovePoint(POINT_ID_ELEMENTS, aDamnationLocations[5].m_fX, aDamnationLocations[5].m_fY, aDamnationLocations[5].m_fZ); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + 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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 *newscript; - - newscript = new Script; - newscript->Name = "mob_mature_netherwing_drake"; - newscript->GetAI = &GetAI_mob_mature_netherwing_drake; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_enslaved_netherwing_drake"; - newscript->GetAI = &GetAI_mob_enslaved_netherwing_drake; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_drake_dealer_hurlunk"; - newscript->pGossipHello = &GossipHello_npc_drake_dealer_hurlunk; - newscript->pGossipSelect = &GossipSelect_npc_drake_dealer_hurlunk; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npcs_flanis_swiftwing_and_kagrosh"; - newscript->pGossipHello = &GossipHello_npcs_flanis_swiftwing_and_kagrosh; - newscript->pGossipSelect = &GossipSelect_npcs_flanis_swiftwing_and_kagrosh; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_murkblood_overseer"; - newscript->pGossipHello = &GossipHello_npc_murkblood_overseer; - newscript->pGossipSelect = &GossipSelect_npc_murkblood_overseer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_neltharaku"; - newscript->pGossipHello = &GossipHello_npc_neltharaku; - newscript->pGossipSelect = &GossipSelect_npc_neltharaku; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_karynaku"; - newscript->pQuestAccept = &QuestAccept_npc_karynaku; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_oronok_tornheart"; - newscript->pGossipHello = &GossipHello_npc_oronok_tornheart; - newscript->pGossipSelect = &GossipSelect_npc_oronok_tornheart; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_wilda"; - newscript->GetAI = &GetAI_npc_wilda; - newscript->pQuestAccept = &QuestAccept_npc_wilda; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_lord_illidan_stormrage"; - newscript->GetAI = &GetAI_npc_lord_illidan_stormrage; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_torloth"; - newscript->GetAI = &GetAI_mob_torloth; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_crystal_prison"; - newscript->pGOQuestAccept = &GOQuestAccept_GO_crystal_prison; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_mature_netherwing_drake"; + pNewScript->GetAI = &GetAI_mob_mature_netherwing_drake; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_enslaved_netherwing_drake"; + pNewScript->GetAI = &GetAI_mob_enslaved_netherwing_drake; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dragonmaw_peon"; + pNewScript->GetAI = &GetAI_npc_dragonmaw_peon; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_dragonmaw_peon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_wilda"; + pNewScript->GetAI = &GetAI_npc_wilda; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_wilda; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_lord_illidan_stormrage"; + pNewScript->GetAI = &GetAI_npc_lord_illidan_stormrage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_torloth"; + pNewScript->GetAI = &GetAI_mob_torloth; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_totem_of_spirits"; + pNewScript->GetAI = &GetAI_npc_totem_of_spirits; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_totem_of_spirits; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_totem_of_spirits; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_soul_captured_credit"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_soul_captured_credit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_crystal_prison"; + pNewScript->pQuestAcceptGO = &GOQuestAccept_GO_crystal_prison; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_spawned_oronok_tornheart"; + pNewScript->GetAI = &GetAI_npc_spawned_oronok_tornheart; + 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 a7aaa3e11b..180af0fd4d 100644 --- a/scripts/outland/shattrath_city.cpp +++ b/scripts/outland/shattrath_city.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,19 +17,15 @@ /* ScriptData SDName: Shattrath_City SD%Complete: 100 -SDComment: Quest support: 10004, 10009, 10211, 10231. Flask vendors, Teleport to Caverns of Time +SDComment: Quest support: 10004, 10231. SDCategory: Shattrath City EndScriptData */ /* ContentData npc_dirty_larry npc_ishanah -npc_khadgar npc_khadgars_servant -npc_raliq_the_drunk npc_salsalabim -npc_shattrathflaskvendors -npc_zephyr EndContentData */ #include "precompiled.h" @@ -54,16 +50,14 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI npc_dirty_larryAI(Creature* pCreature) : ScriptedAI(pCreature) { m_uiNpcFlags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); - m_uiCreepjackGUID = 0; - m_uiMaloneGUID = 0; Reset(); } uint32 m_uiNpcFlags; - uint64 m_uiCreepjackGUID; - uint64 m_uiMaloneGUID; - uint64 m_uiPlayerGUID; + ObjectGuid m_creepjackGuid; + ObjectGuid m_maloneGuid; + ObjectGuid m_playerGuid; bool bEvent; bool bActiveAttack; @@ -71,13 +65,13 @@ 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); - m_uiPlayerGUID = 0; - m_uiCreepjackGUID = 0; - m_uiMaloneGUID = 0; + m_playerGuid.Clear(); + m_creepjackGuid.Clear(); + m_maloneGuid.Clear(); bEvent = false; bActiveAttack = false; @@ -85,12 +79,12 @@ 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); } - void SetRuffies(uint64 guid, bool bAttack, bool bReset) + void SetRuffies(ObjectGuid guid, bool bAttack, bool bReset) { Creature* pCreature = m_creature->GetMap()->GetCreature(guid); @@ -117,7 +111,7 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI if (bAttack) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { if (pPlayer->isAlive()) pCreature->AI()->AttackStart(pPlayer); @@ -126,58 +120,61 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI } } - void StartEvent() + void StartEvent(Player* pPlayer) { + m_playerGuid = pPlayer->GetObjectGuid(); + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); if (Creature* pCreepjack = GetClosestCreatureWithEntry(m_creature, ENTRY_CREEPJACK, 20.0f)) - m_uiCreepjackGUID = pCreepjack->GetGUID(); + m_creepjackGuid = pCreepjack->GetObjectGuid(); if (Creature* pMalone = GetClosestCreatureWithEntry(m_creature, ENTRY_MALONE, 20.0f)) - m_uiMaloneGUID = pMalone->GetGUID(); + m_maloneGuid = pMalone->GetObjectGuid(); bEvent = true; } uint32 NextStep(uint32 uiStep) { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); if (!pPlayer) { - SetRuffies(m_uiCreepjackGUID,false,true); - SetRuffies(m_uiMaloneGUID,false,true); + SetRuffies(m_creepjackGuid, false, true); + SetRuffies(m_maloneGuid, false, true); EnterEvadeMode(); return 0; } - switch(uiStep) + switch (uiStep) { case 1: DoScriptText(SAY_START, m_creature, pPlayer); - SetRuffies(m_uiCreepjackGUID,false,false); - SetRuffies(m_uiMaloneGUID,false,false); + SetRuffies(m_creepjackGuid, false, false); + SetRuffies(m_maloneGuid, false, false); return 3000; - case 2: DoScriptText(SAY_COUNT, m_creature, pPlayer); return 5000; + case 2: DoScriptText(SAY_COUNT, m_creature, pPlayer); return 5000; case 3: DoScriptText(SAY_COUNT_1, m_creature, pPlayer); return 3000; case 4: DoScriptText(SAY_COUNT_2, m_creature, pPlayer); return 3000; - case 5: DoScriptText(SAY_ATTACK, m_creature, pPlayer); return 3000; + case 5: DoScriptText(SAY_ATTACK, m_creature, pPlayer); return 3000; case 6: if (!m_creature->isInCombat() && pPlayer->isAlive()) AttackStart(pPlayer); - SetRuffies(m_uiCreepjackGUID,true,false); - SetRuffies(m_uiMaloneGUID,true,false); + SetRuffies(m_creepjackGuid, true, false); + SetRuffies(m_maloneGuid, true, false); bActiveAttack = true; return 2000; - default: return 0; + default: + return 0; } } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -188,29 +185,29 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32 &damage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (damage < m_creature->GetHealth()) + 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) { - damage = 0; + uiDamage = 0; - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { DoScriptText(SAY_GIVEUP, m_creature, pPlayer); pPlayer->GroupEventHappens(QUEST_WHAT_BOOK, m_creature); } - SetRuffies(m_uiCreepjackGUID,false,true); - SetRuffies(m_uiMaloneGUID,false,true); + SetRuffies(m_creepjackGuid, false, true); + SetRuffies(m_maloneGuid, false, true); EnterEvadeMode(); } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { if (bEvent && !bActiveAttack) { @@ -230,24 +227,21 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI bool GossipHello_npc_dirty_larry(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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->GetGUID()); + 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->m_uiPlayerGUID = pPlayer->GetGUID(); - pLarryAI->StartEvent(); - } + pLarryAI->StartEvent(pPlayer); pPlayer->CLOSE_GOSSIP_MENU(); } @@ -260,99 +254,6 @@ CreatureAI* GetAI_npc_dirty_larry(Creature* pCreature) return new npc_dirty_larryAI(pCreature); } -/*###### -## npc_ishanah -######*/ - -#define GOSSIP_ISHANAH_1 "Who are the Sha'tar?" -#define GOSSIP_ISHANAH_2 "Isn't Shattrath a draenei city? Why do you allow others here?" - -bool GossipHello_npc_ishanah(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ISHANAH_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ISHANAH_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_ishanah(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - pPlayer->SEND_GOSSIP_MENU(9458, pCreature->GetGUID()); - else if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - pPlayer->SEND_GOSSIP_MENU(9459, pCreature->GetGUID()); - - return true; -} - -/*###### -## npc_khadgar -######*/ - -enum -{ - QUEST_CITY_LIGHT = 10211, -}; - -#define KHADGAR_GOSSIP_1 "I've heard your name spoken only in whispers, mage. Who are you?" -#define KHADGAR_GOSSIP_2 "Go on, please." -#define KHADGAR_GOSSIP_3 "I see." -#define KHADGAR_GOSSIP_4 "What did you do then?" -#define KHADGAR_GOSSIP_5 "What happened next?" -#define KHADGAR_GOSSIP_7 "There was something else I wanted to ask you." - -bool GossipHello_npc_khadgar(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetQuestRewardStatus(QUEST_CITY_LIGHT)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(9243, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_khadgar(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(9876, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(9877, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(9878, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(9879, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->SEND_GOSSIP_MENU(9880, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); - pPlayer->SEND_GOSSIP_MENU(9881, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(9243, pCreature->GetGUID()); - break; - } - return true; -} - /*###### ## npc_khadgars_servant ######*/ @@ -402,7 +303,9 @@ enum NPC_ADYRIA = 18596, NPC_ANCHORITE = 19142, NPC_ARCANIST = 18547, - NPC_HAGGARD = 19684 + NPC_HAGGARD = 19684, + + QUEST_CITY_LIGHT = 10211 }; struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI @@ -410,9 +313,9 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI npc_khadgars_servantAI(Creature* pCreature) : npc_escortAI(pCreature) { if (pCreature->GetOwner() && pCreature->GetOwner()->GetTypeId() == TYPEID_PLAYER) - Start(false, pCreature->GetOwner()->GetGUID()); + 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(); } @@ -422,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; @@ -430,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()) @@ -455,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)) @@ -490,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) { @@ -512,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); @@ -534,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)) @@ -554,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); @@ -574,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); @@ -588,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); @@ -608,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); @@ -643,124 +546,58 @@ CreatureAI* GetAI_npc_khadgars_servant(Creature* pCreature) } /*###### -## npc_raliq_the_drunk +# npc_salsalabim ######*/ enum { - SPELL_UPPERCUT = 10966, - QUEST_CRACK_SKULLS = 10009, - FACTION_HOSTILE_RD = 45 -}; - -#define GOSSIP_RALIQ "You owe Sim'salabim money. Hand them over or die!" - -struct MANGOS_DLL_DECL npc_raliq_the_drunkAI : public ScriptedAI -{ - npc_raliq_the_drunkAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_uiNormFaction = pCreature->getFaction(); - Reset(); - } - - uint32 m_uiNormFaction; - uint32 m_uiUppercut_Timer; - - void Reset() - { - m_uiUppercut_Timer = 5000; - - if (m_creature->getFaction() != m_uiNormFaction) - m_creature->setFaction(m_uiNormFaction); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiUppercut_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_UPPERCUT); - m_uiUppercut_Timer = 15000; - }else m_uiUppercut_Timer -= diff; + FACTION_HOSTILE_SA = 90, + QUEST_10004 = 10004, - DoMeleeAttackIfReady(); - } + SPELL_MAGNETIC_PULL = 31705, }; -CreatureAI* GetAI_npc_raliq_the_drunk(Creature* pCreature) -{ - return new npc_raliq_the_drunkAI(pCreature); -} - -bool GossipHello_npc_raliq_the_drunk(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_RALIQ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(9440, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_raliq_the_drunk(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->setFaction(FACTION_HOSTILE_RD); - pCreature->AI()->AttackStart(pPlayer); - } - return true; -} - -/*###### -# npc_salsalabim -######*/ - -#define FACTION_HOSTILE_SA 90 -#define FACTION_FRIENDLY_SA 35 -#define QUEST_10004 10004 - -#define SPELL_MAGNETIC_PULL 31705 - struct MANGOS_DLL_DECL 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); @@ -770,142 +607,39 @@ 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->GetGUID()); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - } - return true; -} + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); -/* -################################################## -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->GetGUID()); - } - else - { - pPlayer->SEND_GOSSIP_MENU(11083, pCreature->GetGUID()); - } - } - - 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->GetGUID()); - } - else - { - pPlayer->SEND_GOSSIP_MENU(11084, pCreature->GetGUID()); - } + 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->GetGUID()); - - return true; -} - -/*###### -# npc_zephyr -######*/ - -bool GossipHello_npc_zephyr(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetReputationRank(989) >= REP_REVERED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Take me to the Caverns of Time.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_zephyr(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - pPlayer->CastSpell(pPlayer,37778,false); - - return true; -} - void AddSC_shattrath_city() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_dirty_larry"; - newscript->GetAI = &GetAI_npc_dirty_larry; - newscript->pGossipHello = &GossipHello_npc_dirty_larry; - newscript->pGossipSelect = &GossipSelect_npc_dirty_larry; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_ishanah"; - newscript->pGossipHello = &GossipHello_npc_ishanah; - newscript->pGossipSelect = &GossipSelect_npc_ishanah; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_khadgar"; - newscript->pGossipHello = &GossipHello_npc_khadgar; - newscript->pGossipSelect = &GossipSelect_npc_khadgar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_khadgars_servant"; - newscript->GetAI = &GetAI_npc_khadgars_servant; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_raliq_the_drunk"; - newscript->GetAI = &GetAI_npc_raliq_the_drunk; - newscript->pGossipHello = &GossipHello_npc_raliq_the_drunk; - newscript->pGossipSelect = &GossipSelect_npc_raliq_the_drunk; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_salsalabim"; - newscript->GetAI = &GetAI_npc_salsalabim; - newscript->pGossipHello = &GossipHello_npc_salsalabim; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_shattrathflaskvendors"; - newscript->pGossipHello = &GossipHello_npc_shattrathflaskvendors; - newscript->pGossipSelect = &GossipSelect_npc_shattrathflaskvendors; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_zephyr"; - newscript->pGossipHello = &GossipHello_npc_zephyr; - newscript->pGossipSelect = &GossipSelect_npc_zephyr; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_dirty_larry"; + pNewScript->GetAI = &GetAI_npc_dirty_larry; + pNewScript->pGossipHello = &GossipHello_npc_dirty_larry; + pNewScript->pGossipSelect = &GossipSelect_npc_dirty_larry; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_khadgars_servant"; + pNewScript->GetAI = &GetAI_npc_khadgars_servant; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_salsalabim"; + pNewScript->GetAI = &GetAI_npc_salsalabim; + pNewScript->pGossipHello = &GossipHello_npc_salsalabim; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp b/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp index ac04e3a1ef..f573dc4ad7 100644 --- a/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp +++ b/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -34,87 +34,105 @@ EndContentData */ # npc_millhouse_manastorm #####*/ -#define SAY_INTRO_1 -1552010 -#define SAY_INTRO_2 -1552011 -#define SAY_WATER -1552012 -#define SAY_BUFFS -1552013 -#define SAY_DRINK -1552014 -#define SAY_READY -1552015 -#define SAY_KILL_1 -1552016 -#define SAY_KILL_2 -1552017 -#define SAY_PYRO -1552018 -#define SAY_ICEBLOCK -1552019 -#define SAY_LOWHP -1552020 -#define SAY_DEATH -1552021 -#define SAY_COMPLETE -1552022 - -#define SPELL_CONJURE_WATER 36879 -#define SPELL_ARCANE_INTELLECT 36880 -#define SPELL_ICE_ARMOR 36881 - -#define SPELL_ARCANE_MISSILES 33833 -#define SPELL_CONE_OF_COLD 12611 -#define SPELL_FIRE_BLAST 13341 -#define SPELL_FIREBALL 14034 -#define SPELL_FROSTBOLT 15497 -#define SPELL_PYROBLAST 33975 - -struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI +enum { - npc_millhouse_manastormAI(Creature* pCreature) : ScriptedAI(pCreature) + SAY_INTRO_1 = -1552010, + SAY_INTRO_2 = -1552011, + SAY_WATER = -1552012, + SAY_BUFFS = -1552013, + SAY_DRINK = -1552014, + SAY_READY = -1552015, + SAY_KILL_1 = -1552016, + SAY_KILL_2 = -1552017, + SAY_PYRO = -1552018, + SAY_ICEBLOCK = -1552019, + SAY_LOWHP = -1552020, + SAY_DEATH = -1552021, + + SPELL_CONJURE_WATER = 36879, + SPELL_ARCANE_INTELLECT = 36880, + SPELL_ICE_ARMOR = 36881, + SPELL_DRINK = 30024, + + SPELL_ARCANE_MISSILES = 33833, + SPELL_CONE_OF_COLD = 12611, + SPELL_FIRE_BLAST = 13341, + 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}, +}; + +static const float fRoomCenterCoords[3] = {445.8804f, -158.7055f, 43.06898f}; + +struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI, private DialogueHelper +{ + 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 EventProgress_Timer; - uint32 Phase; - bool Init; - bool LowHp; - - uint32 Pyroblast_Timer; - uint32 Fireball_Timer; + 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 { - EventProgress_Timer = 2000; - LowHp = false; - Init = false; - Phase = 1; - - Pyroblast_Timer = 1000; - Fireball_Timer = 2500; - - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_WARDEN_2) == DONE) - Init = 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 *victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -123,79 +141,112 @@ struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI ->FailQuest();*/ } - void UpdateAI(const uint32 diff) + void EnterEvadeMode() override { - if (!Init) + 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 + { + switch (iEntry) { - if (EventProgress_Timer < diff) - { - if (Phase < 8) - { - switch(Phase) - { - case 1: - DoScriptText(SAY_INTRO_1, m_creature); - EventProgress_Timer = 18000; - break; - case 2: - DoScriptText(SAY_INTRO_2, m_creature); - EventProgress_Timer = 18000; - break; - case 3: - DoScriptText(SAY_WATER, m_creature); - DoCastSpellIfCan(m_creature,SPELL_CONJURE_WATER); - EventProgress_Timer = 7000; - break; - case 4: - DoScriptText(SAY_BUFFS, m_creature); - DoCastSpellIfCan(m_creature,SPELL_ICE_ARMOR); - EventProgress_Timer = 7000; - break; - case 5: - DoScriptText(SAY_DRINK, m_creature); - DoCastSpellIfCan(m_creature,SPELL_ARCANE_INTELLECT); - EventProgress_Timer = 7000; - break; - case 6: - DoScriptText(SAY_READY, m_creature); - EventProgress_Timer = 6000; - break; - case 7: - if (m_pInstance) - m_pInstance->SetData(TYPE_WARDEN_2,DONE); - Init = true; - break; - } - ++Phase; - } - } else EventProgress_Timer -= diff; + 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; - if (!LowHp && m_creature->GetHealthPercent() < 20.0f) + if (!m_bHasLowHp && m_creature->GetHealthPercent() < 20.0f) { DoScriptText(SAY_LOWHP, m_creature); - LowHp = true; + m_bHasLowHp = true; + } + + if (m_uiPyroblastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PYROBLAST) == CAST_OK) + { + m_uiPyroblastTimer = 40000; + DoScriptText(SAY_PYRO, m_creature); + } } + else + m_uiPyroblastTimer -= uiDiff; - if (Pyroblast_Timer < diff) + if (m_uiFireballTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - return; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL) == CAST_OK) + m_uiFireballTimer = 4000; + } + else + m_uiFireballTimer -= uiDiff; - DoScriptText(SAY_PYRO, m_creature); + 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; - DoCastSpellIfCan(m_creature->getVictim(),SPELL_PYROBLAST); - Pyroblast_Timer = 40000; - }else Pyroblast_Timer -=diff; + if (m_uiFireBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIRE_BLAST) == CAST_OK) + m_uiFireBlastTimer = urand(5000, 16000); + } + else + m_uiFireBlastTimer -= uiDiff; - if (Fireball_Timer < diff) + if (m_uiArcaneMissileTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FIREBALL); - Fireball_Timer = 4000; - }else Fireball_Timer -=diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_MISSILES) == CAST_OK) + m_uiArcaneMissileTimer = urand(5000, 8000); + } + else + m_uiArcaneMissileTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -210,36 +261,11 @@ CreatureAI* GetAI_npc_millhouse_manastorm(Creature* pCreature) # npc_warden_mellichar #####*/ -#define YELL_INTRO1 -1552023 -#define YELL_INTRO2 -1552024 -#define YELL_RELEASE1 -1552025 -#define YELL_RELEASE2A -1552026 -#define YELL_RELEASE2B -1552027 -#define YELL_RELEASE3 -1552028 -#define YELL_RELEASE4 -1552029 -#define YELL_WELCOME -1552030 - -//phase 2(acid mobs) -#define ENTRY_TRICKSTER 20905 -#define ENTRY_PH_HUNTER 20906 -//phase 3 -#define ENTRY_MILLHOUSE 20977 -//phase 4(acid mobs) -#define ENTRY_AKKIRIS 20908 -#define ENTRY_SULFURON 20909 -//phase 5(acid mobs) -#define ENTRY_TW_DRAK 20910 -#define ENTRY_BL_DRAK 20911 -//phase 6 -#define ENTRY_SKYRISS 20912 - -//TARGET_SCRIPT -#define SPELL_TARGET_ALPHA 36856 -#define SPELL_TARGET_BETA 36854 -#define SPELL_TARGET_DELTA 36857 -#define SPELL_TARGET_GAMMA 36858 -#define SPELL_TARGET_OMEGA 36852 -#define SPELL_BUBBLE_VISUAL 36849 +enum +{ + SPELL_BUBBLE_VISUAL = 36849, + SPELL_SIMPLE_TELEPORT = 12980, +}; struct MANGOS_DLL_DECL npc_warden_mellicharAI : public ScriptedAI { @@ -251,217 +277,68 @@ struct MANGOS_DLL_DECL npc_warden_mellicharAI : public ScriptedAI ScriptedInstance* m_pInstance; - bool IsRunning; - bool CanSpawn; - - uint32 EventProgress_Timer; - uint32 Phase; + uint32 m_uiIntroTimer; + ObjectGuid m_targetPlayerGuid; - void Reset() + void Reset() override { - IsRunning = false; - CanSpawn = false; - - EventProgress_Timer = 22000; - Phase = 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* who) { } + void AttackStart(Unit* /*pWho*/) override {} - void MoveInLineOfSight(Unit *who) + void Aggro(Unit* pWho) override { - if (IsRunning) - return; - - if (!m_creature->getVictim() && who->isTargetableForAttack() && (m_creature->IsHostileTo(who)) && who->isInAccessablePlaceFor(m_creature)) - { - if (!m_creature->CanFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetFacingToObject(pWho); + m_targetPlayerGuid = pWho->GetObjectGuid(); - if (who->GetTypeId() != TYPEID_PLAYER) - return; + DoCastSpellIfCan(m_creature, SPELL_BUBBLE_VISUAL); - float attackRadius = m_creature->GetAttackDistance(who)/10; - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) - Aggro(who); - } - } - - void Aggro(Unit *who) - { - 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->instance->GetGameObject(m_pInstance->GetData64(DATA_SPHERE_SHIELD))) - pSphere->SetGoState(GO_STATE_READY); - - IsRunning = true; - } + m_pInstance->SetData(TYPE_HARBINGERSKYRISS, IN_PROGRESS); } - 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 (Phase == 7 && m_pInstance->GetData(TYPE_WARDEN_4) == DONE) - return true; - if (Phase == 6 && m_pInstance->GetData(TYPE_WARDEN_3) == DONE) - return true; - if (Phase == 5 && m_pInstance->GetData(TYPE_WARDEN_2) == DONE) - return true; - if (Phase == 4) - return true; - if (Phase == 3 && m_pInstance->GetData(TYPE_WARDEN_1) == DONE) - return true; - if (Phase == 2 && m_pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS) - return true; - if (Phase == 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(Phase) + 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); } - CanSpawn = true; } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!IsRunning) - return; - - if (EventProgress_Timer < diff) + // Set the visual intro on OOC timer + if (m_uiIntroTimer) { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_HARBINGERSKYRISS) == FAIL) - Reset(); - } - - if (CanSpawn) - { - //continue beam omega pod, unless we are about to summon skyriss - if (Phase != 7) - DoCastSpellIfCan(m_creature,SPELL_TARGET_OMEGA); - - switch(Phase) - { - case 2: - switch(urand(0, 1)) - { - case 0: m_creature->SummonCreature(ENTRY_TRICKSTER, 478.326f, -148.505f, 42.56f, 3.19f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - case 1: m_creature->SummonCreature(ENTRY_PH_HUNTER, 478.326f, -148.505f, 42.56f, 3.19f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - } - break; - case 3: - m_creature->SummonCreature(ENTRY_MILLHOUSE, 413.292f, -148.378f, 42.56f, 6.27f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - break; - case 4: - DoScriptText(YELL_RELEASE2B, m_creature); - break; - case 5: - switch(urand(0, 1)) - { - case 0: m_creature->SummonCreature(ENTRY_AKKIRIS, 420.179f, -174.396f, 42.58f, 0.02f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - case 1: m_creature->SummonCreature(ENTRY_SULFURON, 420.179f, -174.396f, 42.58f, 0.02f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - } - break; - case 6: - switch(urand(0, 1)) - { - case 0: m_creature->SummonCreature(ENTRY_TW_DRAK, 471.795f, -174.58f, 42.58f, 3.06f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - case 1: m_creature->SummonCreature(ENTRY_BL_DRAK, 471.795f, -174.58f, 42.58f, 3.06f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); break; - } - break; - case 7: - m_creature->SummonCreature(ENTRY_SKYRISS, 445.763f, -191.639f, 44.64f, 1.60f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); - DoScriptText(YELL_WELCOME, m_creature); - break; - } - CanSpawn = false; - ++Phase; - } - if (CanProgress()) + if (m_uiIntroTimer <= uiDiff) { - switch(Phase) - { - case 1: - DoScriptText(YELL_INTRO2, m_creature); - EventProgress_Timer = 10000; - ++Phase; - break; - case 2: - DoScriptText(YELL_RELEASE1, m_creature); - DoPrepareForPhase(); - EventProgress_Timer = 7000; - break; - case 3: - DoScriptText(YELL_RELEASE2A, m_creature); - DoPrepareForPhase(); - EventProgress_Timer = 10000; - break; - case 4: - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - case 5: - DoScriptText(YELL_RELEASE3, m_creature); - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - case 6: - DoScriptText(YELL_RELEASE4, m_creature); - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - case 7: - DoPrepareForPhase(); - EventProgress_Timer = 15000; - break; - } + DoCastSpellIfCan(m_creature, SPELL_TARGET_OMEGA); + m_uiIntroTimer = 0; } - } else EventProgress_Timer -= diff; + else + m_uiIntroTimer -= uiDiff; + } } }; @@ -470,46 +347,17 @@ 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') -#####*/ - -#define SPELL_VOID_ZONE_DAMAGE 36120 - -struct MANGOS_DLL_DECL mob_zerekethvoidzoneAI : public ScriptedAI +void AddSC_arcatraz() { - mob_zerekethvoidzoneAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + Script* pNewScript; - 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); -} + pNewScript = new Script; + pNewScript->Name = "npc_millhouse_manastorm"; + pNewScript->GetAI = &GetAI_npc_millhouse_manastorm; + pNewScript->RegisterSelf(); -void AddSC_arcatraz() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_millhouse_manastorm"; - newscript->GetAI = &GetAI_npc_millhouse_manastorm; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_warden_mellichar"; - newscript->GetAI = &GetAI_npc_warden_mellichar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_zerekethvoidzone"; - newscript->GetAI = &GetAI_mob_zerekethvoidzoneAI; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_warden_mellichar"; + pNewScript->GetAI = &GetAI_npc_warden_mellichar; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/arcatraz/arcatraz.h b/scripts/outland/tempest_keep/arcatraz/arcatraz.h index c5b73afc43..bda689500d 100644 --- a/scripts/outland/tempest_keep/arcatraz/arcatraz.h +++ b/scripts/outland/tempest_keep/arcatraz/arcatraz.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,31 +7,103 @@ enum { - MAX_ENCOUNTER = 9, - - 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 - GO_SEAL_SPHERE = 184802, //shield 'protecting' mellichar - GO_POD_ALPHA = 183961, //pod first boss wave - GO_POD_BETA = 183963, //pod second boss wave - GO_POD_DELTA = 183964, //pod third boss wave - GO_POD_GAMMA = 183962, //pod fourth boss wave - GO_POD_OMEGA = 183965, //pod fifth boss wave - - NPC_MELLICHAR = 20904, //skyriss will kill this unit + MAX_ENCOUNTER = 10, + MAX_WARDENS = 7, + TYPE_ENTRANCE = 0, TYPE_ZEREKETH = 1, TYPE_DALLIAH = 2, TYPE_SOCCOTHRATES = 3, - TYPE_HARBINGERSKYRISS = 4, - TYPE_WARDEN_1 = 5, + 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, - TYPE_WARDEN_3 = 7, - TYPE_WARDEN_4 = 8, + TYPE_WARDEN_3 = 7, // Handled with ACID (20908 - Akkiris Lightning-Waker, 20909 - Sulfuron Magma-Thrower) + TYPE_WARDEN_4 = 8, // Handled with ACID (20910 - Twilight Drakonaar, 20911 - Blackwing Drakonaar) TYPE_WARDEN_5 = 9, - DATA_MELLICHAR = 10, - DATA_SPHERE_SHIELD = 11 + 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 + GO_SEAL_SPHERE = 184802, // Shield 'protecting' mellichar + GO_POD_ALPHA = 183961, // Pod first boss wave + GO_POD_BETA = 183963, // Pod second boss wave + 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 +}; + +static const EVENTLOCATION 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 +}; + +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 MANGOS_DLL_DECL instance_arcatraz : public ScriptedInstance, private DialogueHelper +{ + public: + instance_arcatraz(Map* pMap); + + 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; + + 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 0000000000..32846cc024 --- /dev/null +++ b/scripts/outland/tempest_keep/arcatraz/boss_dalliah.cpp @@ -0,0 +1,217 @@ +/* Copyright (C) 2006 - 2013 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_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 MANGOS_DLL_DECL 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 ced7ad021a..d48a9422cf 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,42 +16,34 @@ /* ScriptData SDName: Boss_Harbinger_Skyriss -SD%Complete: 45 -SDComment: CombatAI not fully implemented. Timers will need adjustments. Need more docs on how event fully work. Reset all event and force start over if fail at one point? +SD%Complete: 95 +SDComment: Timers will need adjustments. SDCategory: Tempest Keep, The Arcatraz EndScriptData */ -/* ContentData -boss_harbinger_skyriss -boss_harbinger_skyriss_illusion -EndContentData */ - #include "precompiled.h" #include "arcatraz.h" -#define SAY_INTRO -1552000 -#define SAY_AGGRO -1552001 -#define SAY_KILL_1 -1552002 -#define SAY_KILL_2 -1552003 -#define SAY_MIND_1 -1552004 -#define SAY_MIND_2 -1552005 -#define SAY_FEAR_1 -1552006 -#define SAY_FEAR_2 -1552007 -#define SAY_IMAGE -1552008 -#define SAY_DEATH -1552009 - -#define SPELL_FEAR 39415 - -#define SPELL_MIND_REND 36924 -#define H_SPELL_MIND_REND 39017 - -#define SPELL_DOMINATION 37162 -#define H_SPELL_DOMINATION 39019 - -#define H_SPELL_MANA_BURN 39020 - -#define SPELL_66_ILLUSION 36931 //entry 21466 -#define SPELL_33_ILLUSION 36932 //entry 21467 +enum +{ + SAY_KILL_1 = -1552002, + SAY_KILL_2 = -1552003, + SAY_MIND_1 = -1552004, + SAY_MIND_2 = -1552005, + SAY_FEAR_1 = -1552006, + SAY_FEAR_2 = -1552007, + SAY_IMAGE = -1552008, + SAY_DEATH = -1552009, + + SPELL_FEAR = 39415, + SPELL_MIND_REND = 36924, + SPELL_MIND_REND_H = 39017, + SPELL_DOMINATION = 37162, + SPELL_DOMINATION_H = 39019, + SPELL_MANA_BURN_H = 39020, + SPELL_66_ILLUSION = 36931, // Summons 21466 + SPELL_33_ILLUSION = 36932, // Summons 21467 +}; struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI { @@ -59,188 +51,123 @@ struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Intro = false; Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - bool Intro; - bool IsImage33; - bool IsImage66; - - uint32 Intro_Phase; - uint32 Intro_Timer; - uint32 MindRend_Timer; - uint32 Fear_Timer; - uint32 Domination_Timer; - uint32 ManaBurn_Timer; + uint8 m_uiSplitPhase; + uint32 m_uiMindRendTimer; + uint32 m_uiFearTimer; + uint32 m_uiDominationTimer; + uint32 m_uiManaBurnTimer; - void Reset() + void Reset() override { - IsImage33 = false; - IsImage66 = false; - - Intro_Phase = 1; - Intro_Timer = 5000; - MindRend_Timer = 3000; - Fear_Timer = 15000; - Domination_Timer = 30000; - ManaBurn_Timer = 25000; + m_uiSplitPhase = 1; + m_uiMindRendTimer = 3000; + m_uiFearTimer = 15000; + m_uiDominationTimer = 30000; + m_uiManaBurnTimer = 25000; } - void MoveInLineOfSight(Unit *who) + void JustDied(Unit* /*pKiller*/) override { - if (!Intro) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void AttackStart(Unit* who) - { - if (!Intro) - return; + DoScriptText(SAY_DEATH, m_creature); - ScriptedAI::AttackStart(who); + if (m_pInstance) + m_pInstance->SetData(TYPE_HARBINGERSKYRISS, DONE); } - void JustDied(Unit* Killer) + 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* victim) + void KilledUnit(Unit* pVictim) override { - //won't yell killing pet/other unit - if (victim->GetTypeId() != TYPEID_PLAYER) + // 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 *summoned) + void JustSummoned(Creature* pSummoned) override { - summoned->AI()->AttackStart(m_creature->getVictim()); + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void DoSplit() + void UpdateAI(const uint32 uiDiff) override { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(SAY_IMAGE, m_creature); - - DoCastSpellIfCan(m_creature, IsImage33 ? SPELL_33_ILLUSION : SPELL_66_ILLUSION); - } - - void UpdateAI(const uint32 diff) - { - if (!Intro && !m_creature->isInCombat()) - { - if (!m_pInstance) - return; - - if (Intro_Timer < diff) - { - switch(Intro_Phase) - { - case 1: - DoScriptText(SAY_INTRO, m_creature); - if (GameObject* pSphere = m_pInstance->instance->GetGameObject(m_pInstance->GetData64(DATA_SPHERE_SHIELD))) - pSphere->SetGoState(GO_STATE_ACTIVE); - ++Intro_Phase; - Intro_Timer = 25000; - break; - case 2: - DoScriptText(SAY_AGGRO, m_creature); - if (Creature *mellic = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_MELLICHAR))) - { - //should have a better way to do this. possibly spell exist. - mellic->SetDeathState(JUST_DIED); - mellic->SetHealth(0); - } - ++Intro_Phase; - Intro_Timer = 3000; - break; - case 3: - Intro = true; - break; - } - }else Intro_Timer -=diff; - } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!IsImage66 && 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) { - IsImage66 = 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 (!IsImage33 && m_creature->GetHealthPercent() <= 33.0f) + if (m_uiMindRendTimer < uiDiff) { - IsImage33 = true; - DoSplit(); - } + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - if (MindRend_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_MIND_REND : H_SPELL_MIND_REND); - else - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MIND_REND : H_SPELL_MIND_REND); - - MindRend_Timer = 8000; - }else MindRend_Timer -=diff; + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_MIND_REND : SPELL_MIND_REND_H) == CAST_OK) + m_uiMindRendTimer = 8000; + } + else + m_uiMindRendTimer -= uiDiff; - if (Fear_Timer < diff) + if (m_uiFearTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - return; - - DoScriptText(urand(0, 1) ? SAY_FEAR_1 : SAY_FEAR_2, m_creature); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target,SPELL_FEAR); - else - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FEAR); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - Fear_Timer = 25000; - }else Fear_Timer -=diff; + if (DoCastSpellIfCan(pTarget, SPELL_FEAR) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_FEAR_1 : SAY_FEAR_2, m_creature); + m_uiFearTimer = 25000; + } + } + else + m_uiFearTimer -= uiDiff; - if (Domination_Timer < diff) + if (m_uiDominationTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - return; - - DoScriptText(urand(0, 1) ? SAY_MIND_1 : SAY_MIND_2, m_creature); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_DOMINATION : H_SPELL_DOMINATION); - else - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_DOMINATION : H_SPELL_DOMINATION); - - Domination_Timer = urand(16000, 32000); - }else Domination_Timer -=diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_PLAYER)) + { + 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; if (!m_bIsRegularMode) { - if (ManaBurn_Timer < diff) + if (m_uiManaBurnTimer < uiDiff) { - if (m_creature->IsNonMeleeSpellCasted(false)) - return; + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target,H_SPELL_MANA_BURN); - - ManaBurn_Timer = urand(16000, 32000); - }else ManaBurn_Timer -=diff; + if (DoCastSpellIfCan(pTarget, SPELL_MANA_BURN_H) == CAST_OK) + m_uiManaBurnTimer = urand(16000, 32000); + } + else + m_uiManaBurnTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -252,40 +179,12 @@ CreatureAI* GetAI_boss_harbinger_skyriss(Creature* pCreature) return new boss_harbinger_skyrissAI(pCreature); } -#define SPELL_MIND_REND_IMAGE 36929 -#define H_SPELL_MIND_REND_IMAGE 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 *newscript; - - newscript = new Script; - newscript->Name = "boss_harbinger_skyriss"; - newscript->GetAI = &GetAI_boss_harbinger_skyriss; - newscript->RegisterSelf(); + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_harbinger_skyriss_illusion"; - newscript->GetAI = &GetAI_boss_harbinger_skyriss_illusion; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_harbinger_skyriss"; + pNewScript->GetAI = &GetAI_boss_harbinger_skyriss; + 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 0000000000..eb5dc1d65f --- /dev/null +++ b/scripts/outland/tempest_keep/arcatraz/boss_soccothrates.cpp @@ -0,0 +1,252 @@ +/* Copyright (C) 2006 - 2013 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_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 MANGOS_DLL_DECL 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 d13b44927e..e42a2cb731 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -31,164 +31,434 @@ EndScriptData */ 4 - Harbinger Skyriss event, 5 sub-events */ -struct MANGOS_DLL_DECL instance_arcatraz : public ScriptedInstance +enum { - instance_arcatraz(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + SAY_SOCCOTHRATES_AGGRO = -1552039, + SAY_SOCCOTHRATES_DEATH = -1552043, - uint32 m_auiEncounter[MAX_ENCOUNTER]; + 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, - uint64 m_uiCore_Security_Field_AlphaGUID; - uint64 m_uiCore_Security_Field_BetaGUID; - uint64 m_uiPod_AlphaGUID; - uint64 m_uiPod_GammaGUID; - uint64 m_uiPod_BetaGUID; - uint64 m_uiPod_DeltaGUID; - uint64 m_uiPod_OmegaGUID; + // 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; +} - uint64 m_uiGoSphereGUID; - uint64 m_uiMellicharGUID; +void instance_arcatraz::OnObjectCreate(GameObject* pGo) +{ + 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: + break; + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} - void Initialize() +void instance_arcatraz::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiCore_Security_Field_AlphaGUID = 0; - m_uiCore_Security_Field_BetaGUID = 0; - m_uiPod_AlphaGUID = 0; - m_uiPod_BetaGUID = 0; - m_uiPod_DeltaGUID = 0; - m_uiPod_GammaGUID = 0; - m_uiPod_OmegaGUID = 0; - - m_uiGoSphereGUID = 0; - m_uiMellicharGUID = 0; + 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; } +} - bool IsEncounterInProgress() const +void instance_arcatraz::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; + case TYPE_ENTRANCE: + case TYPE_ZEREKETH: + 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); + + // 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[uiType] = uiData; + break; + + case TYPE_HARBINGERSKYRISS: + if (uiData == FAIL) + { + 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; + + case TYPE_WARDEN_1: + if (uiData == IN_PROGRESS) + DoUseDoorOrButton(GO_POD_ALPHA); + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE2); + m_auiEncounter[uiType] = uiData; + break; + + case TYPE_WARDEN_2: + if (uiData == IN_PROGRESS) + DoUseDoorOrButton(GO_POD_BETA); + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE3); + m_auiEncounter[uiType] = uiData; + break; - return false; + case TYPE_WARDEN_3: + if (uiData == IN_PROGRESS) + DoUseDoorOrButton(GO_POD_DELTA); + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE4); + m_auiEncounter[uiType] = uiData; + break; + + case TYPE_WARDEN_4: + if (uiData == IN_PROGRESS) + DoUseDoorOrButton(GO_POD_GAMMA); + 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[uiType] = uiData; + break; } - void OnObjectCreate(GameObject* pGo) + if (uiData == DONE) { - switch(pGo->GetEntry()) - { - case GO_CORE_SECURITY_FIELD_ALPHA: m_uiCore_Security_Field_AlphaGUID = pGo->GetGUID(); break; - case GO_CORE_SECURITY_FIELD_BETA: m_uiCore_Security_Field_BetaGUID = pGo->GetGUID(); break; - case GO_SEAL_SPHERE: m_uiGoSphereGUID = pGo->GetGUID(); break; - case GO_POD_ALPHA: m_uiPod_AlphaGUID = pGo->GetGUID(); break; - case GO_POD_BETA: m_uiPod_BetaGUID = pGo->GetGUID(); break; - case GO_POD_DELTA: m_uiPod_DeltaGUID = pGo->GetGUID(); break; - case GO_POD_GAMMA: m_uiPod_GammaGUID = pGo->GetGUID(); break; - case GO_POD_OMEGA: m_uiPod_OmegaGUID = pGo->GetGUID(); break; - } + 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 OnCreatureCreate(Creature* pCreature) +void instance_arcatraz::Load(const char* chrIn) +{ + if (!chrIn) { - if (pCreature->GetEntry() == NPC_MELLICHAR) - m_uiMellicharGUID = pCreature->GetGUID(); + OUT_LOAD_INST_DATA_FAIL; + return; } - void SetData(uint32 uiType, uint32 uiData) + 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) { - switch(uiType) + 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; + } +} + +void instance_arcatraz::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_ARCATRAZ_WARDEN || pCreature->GetEntry() == NPC_ARCATRAZ_DEFENDER) + { + ++m_uiKilledWardens; + + // Stop the intro spawns when the wardens are killed + if (m_uiKilledWardens == MAX_WARDENS) { - case TYPE_ZEREKETH: - m_auiEncounter[0] = uiData; - break; - - case TYPE_DALLIAH: - if (uiData == DONE) - DoUseDoorOrButton(m_uiCore_Security_Field_BetaGUID); - m_auiEncounter[1] = uiData; - break; - - case TYPE_SOCCOTHRATES: - if (uiData == DONE) - DoUseDoorOrButton(m_uiCore_Security_Field_AlphaGUID); - m_auiEncounter[2] = uiData; - break; - - case TYPE_HARBINGERSKYRISS: - if (uiData == NOT_STARTED || 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; - } - m_auiEncounter[3] = uiData; - break; - - case TYPE_WARDEN_1: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiPod_AlphaGUID); - m_auiEncounter[4] = uiData; - break; - - case TYPE_WARDEN_2: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiPod_BetaGUID); - m_auiEncounter[5] = uiData; - break; - - case TYPE_WARDEN_3: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiPod_DeltaGUID); - m_auiEncounter[6] = uiData; - break; - - case TYPE_WARDEN_4: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiPod_GammaGUID); - m_auiEncounter[7] = uiData; - break; - - case TYPE_WARDEN_5: - if (uiData == IN_PROGRESS) - DoUseDoorOrButton(m_uiPod_OmegaGUID); - m_auiEncounter[8] = uiData; - break; + SetData(TYPE_ENTRANCE, DONE); + m_uiEntranceEventTimer = 0; } } +} + +void instance_arcatraz::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); - uint32 GetData(uint32 uiType) + if (m_uiResetDelayTimer) { - switch(uiType) + if (m_uiResetDelayTimer <= uiDiff) { - 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]; + if (Creature* pMellichar = GetSingleCreatureFromStorage(NPC_MELLICHAR)) + pMellichar->Respawn(); + m_uiResetDelayTimer = 0; } - return 0; + else + m_uiResetDelayTimer -= uiDiff; } - uint64 GetData64(uint32 uiData) + if (m_uiEntranceEventTimer) { - switch(uiData) + if (m_uiEntranceEventTimer <= uiDiff) { - case DATA_MELLICHAR: - return m_uiMellicharGUID; - case DATA_SPHERE_SHIELD: - return m_uiGoSphereGUID; + 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); } - return 0; + else + m_uiEntranceEventTimer -= uiDiff; } -}; +} InstanceData* GetInstanceData_instance_arcatraz(Map* pMap) { @@ -197,9 +467,10 @@ InstanceData* GetInstanceData_instance_arcatraz(Map* pMap) void AddSC_instance_arcatraz() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_arcatraz"; - newscript->GetInstanceData = &GetInstanceData_instance_arcatraz; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_arcatraz"; + pNewScript->GetInstanceData = &GetInstanceData_instance_arcatraz; + pNewScript->RegisterSelf(); } 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 68d535c26f..cf7da8ca6a 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,158 +17,175 @@ /* ScriptData SDName: Boss_High_Botanist_Freywinn SD%Complete: 90 -SDComment: some strange visual related to tree form(if aura lost before normal duration end). possible make summon&transform -process smoother(transform after delay) +SDComment: Timers may need some fine adjustments SDCategory: Tempest Keep, The Botanica EndScriptData */ #include "precompiled.h" -#define SAY_AGGRO -1553000 -#define SAY_KILL_1 -1553001 -#define SAY_KILL_2 -1553002 -#define SAY_TREE_1 -1553003 -#define SAY_TREE_2 -1553004 -#define SAY_DEATH -1553005 - -#define SPELL_TRANQUILITY 34550 -#define SPELL_TREE_FORM 34551 - -#define SPELL_SUMMON_FRAYER 34557 -#define ENTRY_FRAYER 19953 - -#define SPELL_PLANT_WHITE 34759 -#define SPELL_PLANT_GREEN 34761 -#define SPELL_PLANT_BLUE 34762 -#define SPELL_PLANT_RED 34763 +enum +{ + SAY_AGGRO = -1553000, + SAY_KILL_1 = -1553001, + SAY_KILL_2 = -1553002, + SAY_TREE_1 = -1553003, + SAY_TREE_2 = -1553004, + SAY_DEATH = -1553005, + + SPELL_TRANQUILITY = 34550, + SPELL_TREE_FORM = 34551, + SPELL_SUMMON_FRAYER = 34557, + SPELL_PLANT_WHITE = 34759, + SPELL_PLANT_GREEN = 34761, + SPELL_PLANT_BLUE = 34762, + SPELL_PLANT_RED = 34763, + + NPC_FRAYER_PROTECTOR = 19953, +}; struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI { boss_high_botanist_freywinnAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - std::list Adds_List; + uint32 m_uiSummonSeedlingTimer; + uint32 m_uiTreeFormTimer; + uint32 m_uiFrayerTimer; + uint32 m_uiTreeFormEndTimer; + uint8 m_uiFrayerAddsCount; + bool m_bCanMoveFree; - uint32 SummonSeedling_Timer; - uint32 TreeForm_Timer; - uint32 MoveCheck_Timer; - uint32 DeadAddsCount; - bool MoveFree; - - void Reset() + void Reset() override { - Adds_List.clear(); - - SummonSeedling_Timer = 6000; - TreeForm_Timer = 30000; - MoveCheck_Timer = 1000; - DeadAddsCount = 0; - MoveFree = true; + m_uiSummonSeedlingTimer = 6000; + m_uiTreeFormTimer = 30000; + m_uiTreeFormEndTimer = 0; + m_uiFrayerAddsCount = 0; + m_uiFrayerTimer = 0; + m_bCanMoveFree = true; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustSummoned(Creature *summoned) + void JustSummoned(Creature* pSummoned) override { - if (summoned->GetEntry() == ENTRY_FRAYER) - Adds_List.push_back(summoned->GetGUID()); + if (pSummoned->GetEntry() == NPC_FRAYER_PROTECTOR) + ++m_uiFrayerAddsCount; + + // Attack players + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FRAYER_PROTECTOR) + { + --m_uiFrayerAddsCount; + + // When all 3 Frayers are killed stop the tree form action (if not done this already) + if (!m_uiFrayerAddsCount && !m_bCanMoveFree) + { + m_uiTreeFormEndTimer = 0; + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + // Interrupt all spells and remove auras + m_creature->InterruptNonMeleeSpells(true); + m_creature->RemoveAllAuras(); + m_bCanMoveFree = true; + } + } } + // 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; - case 2: DoCastSpellIfCan(m_creature,SPELL_PLANT_BLUE); break; - case 3: DoCastSpellIfCan(m_creature,SPELL_PLANT_RED); break; + case 0: DoCastSpellIfCan(m_creature, SPELL_PLANT_WHITE); break; + case 1: DoCastSpellIfCan(m_creature, SPELL_PLANT_GREEN); break; + case 2: DoCastSpellIfCan(m_creature, SPELL_PLANT_BLUE); break; + case 3: DoCastSpellIfCan(m_creature, SPELL_PLANT_RED); break; } } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (TreeForm_Timer < diff) + if (m_uiTreeFormTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_TREE_1 : SAY_TREE_2, m_creature); - - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - m_creature->RemoveAllAuras(); + if (DoCastSpellIfCan(m_creature, SPELL_TRANQUILITY) == CAST_OK) + { + // Note: This should remove only negative auras + m_creature->RemoveAllAuras(); - DoCastSpellIfCan(m_creature, SPELL_SUMMON_FRAYER, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_TRANQUILITY, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_TREE_FORM, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TREE_FORM, CAST_TRIGGERED); + DoScriptText(urand(0, 1) ? SAY_TREE_1 : SAY_TREE_2, m_creature); - m_creature->GetMotionMaster()->MoveIdle(); - MoveFree = false; + m_creature->GetMotionMaster()->MoveIdle(); + m_bCanMoveFree = false; + m_uiFrayerTimer = 1000; + m_uiTreeFormEndTimer = 45000; + m_uiTreeFormTimer = 75000; + } + } + else + m_uiTreeFormTimer -= uiDiff; - TreeForm_Timer = 75000; - }else TreeForm_Timer -= diff; + // The Frayer is summoned after one second in the tree phase + if (m_uiFrayerTimer) + { + if (m_uiFrayerTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FRAYER, CAST_TRIGGERED) == CAST_OK) + m_uiFrayerTimer = 0; + } + else + m_uiFrayerTimer -= uiDiff; + } - if (!MoveFree) + // Tree phase will be removed when the timer expires; + if (m_uiTreeFormEndTimer) { - if (MoveCheck_Timer < diff) + if (m_uiTreeFormEndTimer <= uiDiff) { - if (!Adds_List.empty()) - { - for(std::list::iterator itr = Adds_List.begin(); itr != Adds_List.end(); ++itr) - { - if (Creature *temp = m_creature->GetMap()->GetCreature(*itr)) - { - if (!temp->isAlive()) - { - Adds_List.erase(itr); - ++DeadAddsCount; - break; - } - } - } - } - - if (DeadAddsCount < 3 && TreeForm_Timer-30000 < diff) - DeadAddsCount = 3; - - if (DeadAddsCount >= 3) - { - Adds_List.clear(); - DeadAddsCount = 0; - - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); + if (m_creature->getVictim()) m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - MoveFree = true; - } - MoveCheck_Timer = 500; + m_bCanMoveFree = true; + m_uiTreeFormEndTimer = 0; } - else MoveCheck_Timer -= diff; - - return; + else + m_uiTreeFormEndTimer -= uiDiff; } - /*if (m_creature->HasAura(SPELL_TREE_FORM, EFFECT_INDEX_0) || m_creature->HasAura(SPELL_TRANQUILITY, EFFECT_INDEX_0)) - return;*/ + // Don't do any other actions during tree form + if (!m_bCanMoveFree) + return; - //one random seedling every 5 secs, but not in tree form - if (SummonSeedling_Timer < diff) + // one random seedling every 5 secs, but not in tree form + if (m_uiSummonSeedlingTimer < uiDiff) { DoSummonSeedling(); - SummonSeedling_Timer = 6000; - }else SummonSeedling_Timer -= diff; + m_uiSummonSeedlingTimer = 6000; + } + else + m_uiSummonSeedlingTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -181,10 +198,10 @@ CreatureAI* GetAI_boss_high_botanist_freywinn(Creature* pCreature) void AddSC_boss_high_botanist_freywinn() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_high_botanist_freywinn"; - newscript->GetAI = &GetAI_boss_high_botanist_freywinn; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_high_botanist_freywinn"; + pNewScript->GetAI = &GetAI_boss_high_botanist_freywinn; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/botanica/boss_laj.cpp b/scripts/outland/tempest_keep/botanica/boss_laj.cpp index 20cd4486a1..4c9e0cb96b 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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 { 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(); } @@ -185,10 +218,10 @@ CreatureAI* GetAI_boss_laj(Creature* pCreature) void AddSC_boss_laj() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_laj"; - newscript->GetAI = &GetAI_boss_laj; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_laj"; + pNewScript->GetAI = &GetAI_boss_laj; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp b/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp index 0a3b733a3a..29e33d82fd 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,201 +16,151 @@ /* ScriptData SDName: Boss_Warp_Splinter -SD%Complete: 80 -SDComment: Includes Sapling (need some better control with these). Spells for boss possibly need some rework. +SD%Complete: 90 +SDComment: Timers may need adjustments SDCategory: Tempest Keep, The Botanica EndScriptData */ #include "precompiled.h" -/*##### -# mob_treant (Sapling) -#####*/ - -struct MANGOS_DLL_DECL mob_treantAI : public ScriptedAI -{ - mob_treantAI (Creature* pCreature) : ScriptedAI(pCreature) - { - WarpGuid = 0; - Reset(); - } - - uint64 WarpGuid; - - void Reset() - { - m_creature->SetSpeedRate(MOVE_RUN, 0.5f); - } - - void MoveInLineOfSight(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_creature->getVictim()->GetGUID() != WarpGuid) - DoMeleeAttackIfReady(); - } -}; - /*##### # boss_warp_splinter #####*/ -#define SAY_AGGRO -1553007 -#define SAY_SLAY_1 -1553008 -#define SAY_SLAY_2 -1553009 -#define SAY_SUMMON_1 -1553010 -#define SAY_SUMMON_2 -1553011 -#define SAY_DEATH -1553012 - -#define WAR_STOMP 34716 -#define SUMMON_TREANTS 34727 // DBC: 34727, 34731, 34733, 34734, 34736, 34739, 34741 (with Ancestral Life spell 34742) // won't work (guardian summon) -#define ARCANE_VOLLEY 36705 //37078, 34785 //must additional script them (because Splinter eats them after 20 sec ^) -#define SPELL_HEAL_FATHER 6262 - -#define CREATURE_TREANT 19949 -#define TREANT_SPAWN_DIST 50 //50 yards from Warp Splinter's spawn point - -float treant_pos[6][3] = +enum { - {24.301233f, 427.221100f, -27.060635f}, - {16.795492f, 359.678802f, -27.355425f}, - {53.493484f, 345.381470f, -26.196192f}, - {61.867096f, 439.362732f, -25.921030f}, - {109.86187f, 423.201630f, -27.356019f}, - {106.78015f, 355.582580f, -27.593357f} + SAY_AGGRO = -1553007, + SAY_SLAY_1 = -1553008, + SAY_SLAY_2 = -1553009, + SAY_SUMMON_1 = -1553010, + SAY_SUMMON_2 = -1553011, + SAY_DEATH = -1553012, + + SPELL_WAR_STOMP = 34716, + SPELL_SUMMON_SAPLINGS = 34741, // this will leech the health from all saplings + SPELL_ARCANE_VOLLEY = 36705, + SPELL_ARCANE_VOLLEY_H = 39133, + + NPC_SAPLING = 19949, }; +// Summon Saplings spells (too many to declare them above) +static const uint32 aSaplingsSummonSpells[10] = {34727, 34730, 34731, 34732, 34733, 34734, 34735, 34736, 34737, 34739}; + struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI { boss_warp_splinterAI(Creature* pCreature) : ScriptedAI(pCreature) { - Treant_Spawn_Pos_X = pCreature->GetPositionX(); - Treant_Spawn_Pos_Y = pCreature->GetPositionY(); + // Add the summon spells to a vector for better handling + for (uint8 i = 0; i < 10; ++i) + m_vSummonSpells.push_back(aSaplingsSummonSpells[i]); + + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - uint32 War_Stomp_Timer; - uint32 Summon_Treants_Timer; - uint32 Arcane_Volley_Timer; - uint32 CheckTreantLOS_Timer; - uint32 TreantLife_Timer; - uint64 Treant_GUIDs[6]; + bool m_bIsRegularMode; - float Treant_Spawn_Pos_X; - float Treant_Spawn_Pos_Y; + uint32 m_uiWarStompTimer; + uint32 m_uiSummonTreantsTimer; + uint32 m_uiArcaneVolleyTimer; - void Reset() - { - War_Stomp_Timer = urand(25000, 40000); - Summon_Treants_Timer = 45000; - Arcane_Volley_Timer = urand(8000, 20000); - CheckTreantLOS_Timer = 1000; - TreantLife_Timer = 999999; - - for(int i = 0; i < 6; ++i) - Treant_GUIDs[i] = 0; + std::vector m_vSummonSpells; - m_creature->SetSpeedRate(MOVE_RUN, 0.7f); + void Reset() override + { + m_uiWarStompTimer = urand(6000, 7000); + m_uiSummonTreantsTimer = urand(25000, 35000); + m_uiArcaneVolleyTimer = urand(12000, 14500); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void SummonTreants() + void JustSummoned(Creature* pSummoned) override { - for(int i = 0; i < 6; ++i) - { - float angle = (M_PI / 3) * i; - - float X = Treant_Spawn_Pos_X + TREANT_SPAWN_DIST * cos(angle); - float Y = Treant_Spawn_Pos_Y + TREANT_SPAWN_DIST * sin(angle); - //float Z = m_creature->GetMap()->GetHeight(X,Y, m_creature->GetPositionZ()); - //float Z = m_creature->GetPositionZ(); - float O = - m_creature->GetAngle(X,Y); - - if (Creature* pTreant = m_creature->SummonCreature(CREATURE_TREANT,treant_pos[i][0],treant_pos[i][1],treant_pos[i][2],O,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,40000)) - { - //pTreant->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); - pTreant->AddThreat(m_creature); - Treant_GUIDs[i] = pTreant->GetGUID(); - - if (mob_treantAI* pTreantAI = dynamic_cast(pTreant->AI())) - pTreantAI->WarpGuid = m_creature->GetGUID(); - } - } - - DoScriptText(urand(0, 1) ? SAY_SUMMON_1 : SAY_SUMMON_2, m_creature); + if (pSummoned->GetEntry() == NPC_SAPLING) + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); } - // Warp Splinter eat treants if they are near him - void EatTreant() + // Wrapper to summon all Saplings + void SummonTreants() { - for(int i=0; i<6; ++i) - { - Creature* pTreant = m_creature->GetMap()->GetCreature(Treant_GUIDs[i]); - - if (pTreant) - { - if (m_creature->IsWithinDistInMap(pTreant, 5)) - { - // 2) Heal Warp Splinter - int32 CurrentHP_Treant = (int32)pTreant->GetHealth(); - m_creature->CastCustomSpell(m_creature,SPELL_HEAL_FATHER,&CurrentHP_Treant, 0, 0, true,0 ,0, m_creature->GetGUID()); - - // 3) Kill Treant - pTreant->DealDamage(pTreant, pTreant->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - } - } + // Choose 6 random spells out of 10 + std::random_shuffle(m_vSummonSpells.begin(), m_vSummonSpells.end()); + for (uint8 i = 0; i < 6; ++i) + DoCastSpellIfCan(m_creature, m_vSummonSpells[i], CAST_TRIGGERED); + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SAPLINGS, CAST_TRIGGERED); + DoScriptText(urand(0, 1) ? SAY_SUMMON_1 : SAY_SUMMON_2, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Check for War Stomp - if (War_Stomp_Timer < diff) + // War Stomp + if (m_uiWarStompTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),WAR_STOMP); - War_Stomp_Timer = urand(25000, 40000); - } else War_Stomp_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP) == CAST_OK) + m_uiWarStompTimer = urand(17000, 38000); + } + else + m_uiWarStompTimer -= uiDiff; - //Check for Arcane Volley - if (Arcane_Volley_Timer < diff) + // Arcane Volley + if (m_uiArcaneVolleyTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),ARCANE_VOLLEY); - Arcane_Volley_Timer = urand(20000, 35000); - } else Arcane_Volley_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY_H) == CAST_OK) + m_uiArcaneVolleyTimer = urand(16000, 38000); + } + else + m_uiArcaneVolleyTimer -= uiDiff; - //Check for Summon Treants - if (Summon_Treants_Timer < diff) + // Summon Treants + if (m_uiSummonTreantsTimer < uiDiff) { SummonTreants(); - Summon_Treants_Timer = 45000; - } else Summon_Treants_Timer -= diff; + m_uiSummonTreantsTimer = urand(37000, 55000); + } + else + m_uiSummonTreantsTimer -= uiDiff; - // I check if there is a Treant in Warp Splinter's LOS, so he can eat them - if (CheckTreantLOS_Timer < diff) - { - EatTreant(); - CheckTreantLOS_Timer = 1000; - } else CheckTreantLOS_Timer -= diff; + DoMeleeAttackIfReady(); + } +}; + +/*##### +# mob_treant (Sapling) +#####*/ +struct MANGOS_DLL_DECL npc_saplingAI : public ScriptedAI +{ + npc_saplingAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override + { + // ToDo: This one may need further reserch + // m_creature->SetSpeedRate(MOVE_RUN, 0.5f); + } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; DoMeleeAttackIfReady(); } @@ -221,22 +171,22 @@ CreatureAI* GetAI_boss_warp_splinter(Creature* pCreature) return new boss_warp_splinterAI(pCreature); } -CreatureAI* GetAI_mob_treant(Creature* pCreature) +CreatureAI* GetAI_npc_sapling(Creature* pCreature) { - return new mob_treantAI(pCreature); + return new npc_saplingAI(pCreature); } void AddSC_boss_warp_splinter() { - Script *newscript; + Script* pNewScript; - newscript = new Script; - newscript->Name = "boss_warp_splinter"; - newscript->GetAI = &GetAI_boss_warp_splinter; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_warp_splinter"; + pNewScript->GetAI = &GetAI_boss_warp_splinter; + pNewScript->RegisterSelf(); - newscript = new Script; - newscript->Name = "mob_warp_splinter_treant"; - newscript->GetAI = &GetAI_mob_treant; - newscript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "mob_warp_splinter_treant"; + pNewScript->GetAI = &GetAI_npc_sapling; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/the_eye/boss_alar.cpp b/scripts/outland/tempest_keep/the_eye/boss_alar.cpp new file mode 100644 index 0000000000..dfbbc18e94 --- /dev/null +++ b/scripts/outland/tempest_keep/the_eye/boss_alar.cpp @@ -0,0 +1,439 @@ +/* Copyright (C) 2006 - 2013 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_alar +SD%Complete: 90 +SDComment: Boss movement should be improved. +SDCategory: Tempest Keep, The Eye +EndScriptData */ + +#include "precompiled.h" +#include "the_eye.h" + +enum +{ + // spells + // phase 1 + SPELL_FLAME_BUFFET = 34121, // if nobody is in range + SPELL_FLAME_QUILLS = 34229, + SPELL_EMBER_BLAST = 34341, // usee when the boss dies first time + SPELL_REBIRTH = 34342, + + // phase 2 + SPELL_MELT_ARMOR = 35410, + 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, // 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 + NPC_FLAME_PATCH = 20602, + SPELL_FLAME_PATCH = 35380, + + MAX_PLATFORMS = 4, + + POINT_ID_RESSURRECT = 0, // center of the hall + POINT_ID_PLATFORM = 1, // platform points + POINT_ID_QUILLS = 2, // center of the hall - in air + + PHASE_ONE = 1, + PHASE_REBIRTH = 2, + PHASE_TWO = 3, + PHASE_DIVE_BOMB = 4, +}; + +// Platform locations from left to right (as standing at the entrance) +static const EVENTLOCATION aPlatformLocation[MAX_PLATFORMS] = +{ + {340.15f, 58.65f, 17.71f}, + {388.09f, 31.54f, 20.18f}, + {388.18f, -32.85f, 20.18f}, + {340.29f, -60.19f, 17.72f} +}; + +static const EVENTLOCATION aCenterLocation[] = +{ + {331.0f, 0.01f, 39.0f}, + {331.0, 0.01f, -2.39f}, +}; + +struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI +{ + boss_alarAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiCurrentPlatformId; + uint32 m_uiRangeCheckTimer; + uint32 m_uiBerserkTimer; + + uint32 m_uiPlatformMoveTimer; + uint32 m_uiFlameQuillsTimer; + uint32 m_uiFlamePatchTimer; + uint32 m_uiDiveBombTimer; + uint32 m_uiChargeTimer; + uint32 m_uiRebirthTimer; + uint32 m_uiMeltArmorTimer; + + bool m_bCanSummonEmber; + + void Reset() override + { + // Start phase one and move to the closest platform + m_uiPhase = PHASE_ONE; + SetCombatMovement(false); + + m_uiRangeCheckTimer = 0; + m_uiCurrentPlatformId = 0; + m_uiPlatformMoveTimer = 35000; + m_uiFlameQuillsTimer = 170000; // at the 5th platform + + 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*/) override + { + 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 + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PLATFORM, aPlatformLocation[m_uiCurrentPlatformId].m_fX, aPlatformLocation[m_uiCurrentPlatformId].m_fY, aPlatformLocation[m_uiCurrentPlatformId].m_fZ); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ALAR, FAIL); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ALAR, DONE); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FLAME_PATCH) + pSummoned->CastSpell(pSummoned, SPELL_FLAME_PATCH, true); + else + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // drain 3% of boss health when the ember dies + if (pSummoned->GetEntry() == NPC_EMBER_OF_ALAR) + { + // Check first if we have enough health to drain + if (m_creature->GetMaxHealth()*.03f > m_creature->GetHealth()) + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth()*.03f, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + void EnterEvadeMode() override + { + // Don't evade if the boss has the ember blast invisibility aura + if (m_creature->HasAura(SPELL_EMBER_BLAST)) + return; + + ScriptedAI::EnterEvadeMode(); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case POINT_ID_QUILLS: + if (m_uiPhase == PHASE_ONE) + { + 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: + // When we reach the platform we start the range check and we can summon the embers + m_bCanSummonEmber = true; + m_uiRangeCheckTimer = 2000; + break; + case POINT_ID_RESSURRECT: + // remove the invisibility aura + if (m_creature->HasAura(SPELL_EMBER_BLAST)) + m_creature->RemoveAurasDueToSpell(SPELL_EMBER_BLAST); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + // cast rebirth and remove fake death + if (DoCastSpellIfCan(m_creature, SPELL_REBIRTH) == CAST_OK) + { + DoResetThreat(); + + // start following target + SetCombatMovement(true); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + m_uiPhase = PHASE_TWO; + } + break; + } + } + + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override + { + // Only init fake in phase one + if (m_uiPhase != PHASE_ONE) + return; + + if (uiDamage < m_creature->GetHealth()) + return; + + m_creature->InterruptNonMeleeSpells(true); + // We set the health to 1 in order to avoid the forced death stand flag - this way we can have the ressurrect animation + 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); + + // Stop damage and stop checking for flame buffet. + uiDamage = 0; + m_uiRangeCheckTimer = 0; + + if (DoCastSpellIfCan(m_creature, SPELL_EMBER_BLAST, CAST_TRIGGERED) == CAST_OK) + { + // Move to the center of the hall and ressurrect + m_uiPhase = PHASE_REBIRTH; + m_creature->GetMotionMaster()->MovePoint(POINT_ID_RESSURRECT, aCenterLocation[1].m_fX, aCenterLocation[1].m_fY, aCenterLocation[1].m_fZ); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Platform phase + if (m_uiPhase == PHASE_ONE) + { + if (m_uiFlameQuillsTimer < uiDiff) + { + // Move to Flame Quills position; stop range check, platform moving and ember summoning + m_creature->GetMotionMaster()->MovePoint(POINT_ID_QUILLS, aCenterLocation[0].m_fX, aCenterLocation[0].m_fY, aCenterLocation[0].m_fZ); + m_uiRangeCheckTimer = 0; + m_bCanSummonEmber = false; + m_uiPlatformMoveTimer = 0; + m_uiFlameQuillsTimer = 180000; + } + else + m_uiFlameQuillsTimer -= uiDiff; + + if (m_uiPlatformMoveTimer) + { + if (m_uiPlatformMoveTimer <= uiDiff) + { + // go to next platform + ++m_uiCurrentPlatformId; + + if (m_uiCurrentPlatformId == MAX_PLATFORMS) + m_uiCurrentPlatformId = 0; + + // move to next platform and summon one ember only if moving on platforms (we avoid the summoning during the Flame Quills move) + if (m_bCanSummonEmber) + m_creature->SummonCreature(NPC_EMBER_OF_ALAR, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PLATFORM, aPlatformLocation[m_uiCurrentPlatformId].m_fX, aPlatformLocation[m_uiCurrentPlatformId].m_fY, aPlatformLocation[m_uiCurrentPlatformId].m_fZ); + + m_uiRangeCheckTimer = 0; + m_uiPlatformMoveTimer = 35000; + } + else + m_uiPlatformMoveTimer -= uiDiff; + } + } + // Combat phase + else if (m_uiPhase == PHASE_TWO) + { + if (m_uiBerserkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + } + else + m_uiBerserkTimer -= uiDiff; + + if (m_uiFlamePatchTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + m_creature->SummonCreature(NPC_FLAME_PATCH, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30000); + m_uiFlamePatchTimer = 30000; + } + } + else + m_uiFlamePatchTimer -= uiDiff; + + if (m_uiMeltArmorTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MELT_ARMOR) == CAST_OK) + m_uiMeltArmorTimer = 60000; + } + 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 + if (m_uiRangeCheckTimer) + { + if (m_uiRangeCheckTimer <= uiDiff) + { + if (!m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + DoCastSpellIfCan(m_creature, SPELL_FLAME_BUFFET); + m_uiRangeCheckTimer = 2000; + } + else + m_uiRangeCheckTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_alar(Creature* pCreature) +{ + return new boss_alarAI(pCreature); +} + +void AddSC_boss_alar() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_alar"; + pNewScript->GetAI = &GetAI_boss_alar; + pNewScript->RegisterSelf(); +} diff --git a/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp b/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp index cf9ac7ba05..5b9d3f26b0 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,92 +39,101 @@ 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_SPLIT = 2, + PHASE_VOID = 3, +}; struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI { boss_high_astromancer_solarianAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - - defaultarmor = m_creature->GetArmor(); - defaultsize = m_creature->GetFloatValue(OBJECT_FIELD_SCALE_X); + m_uiDefaultArmor = m_creature->GetArmor(); Reset(); } ScriptedInstance* m_pInstance; - uint32 ArcaneMissiles_Timer; - uint32 m_uiWrathOfTheAstromancer_Timer; - uint32 BlindingLight_Timer; - uint32 Fear_Timer; - uint32 VoidBolt_Timer; - uint32 Phase1_Timer; - uint32 Phase2_Timer; - uint32 Phase3_Timer; - uint32 AppearDelay_Timer; - uint32 defaultarmor; - - float defaultsize; - - bool AppearDelay; + uint32 m_uiArcaneMissilesTimer; + uint32 m_uiWrathOfTheAstromancerTimer; + uint32 m_uiBlindingLightTimer; + uint32 m_uiFearTimer; + uint32 m_uiVoidBoltTimer; + uint32 m_uiSplitTimer; + uint32 m_uiSummonAgentsTimer; + uint32 m_uiSummonPriestsTimer; + uint32 m_uiDelayTimer; + uint32 m_uiDefaultArmor; - uint8 Phase; + Phases m_Phase; - float Portals[3][3]; + GuidVector m_vSpotLightsGuidVector; - void Reset() + void Reset() override { - ArcaneMissiles_Timer = 2000; - m_uiWrathOfTheAstromancer_Timer = 15000; - BlindingLight_Timer = 41000; - Fear_Timer = 20000; - VoidBolt_Timer = 10000; - Phase1_Timer = 50000; - Phase2_Timer = 10000; - Phase3_Timer = 15000; - AppearDelay_Timer = 2000; - AppearDelay = false; - Phase = 1; - - if (m_pInstance) - m_pInstance->SetData(TYPE_ASTROMANCER, 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); + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); - m_creature->SetArmor(defaultarmor); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize); - m_creature->SetDisplayId(MODEL_HUMAN); + SetCombatMovement(true); } - 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_KILL1, m_creature); break; case 1: DoScriptText(SAY_KILL2, m_creature); break; @@ -132,318 +141,329 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI } } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize); - m_creature->SetDisplayId(MODEL_HUMAN); - DoScriptText(SAY_DEATH, m_creature); if (m_pInstance) - m_pInstance->SetData(TYPE_ASTROMANCER, DONE); + m_pInstance->SetData(TYPE_SOLARIAN, DONE); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - m_creature->SetInCombatWithZone(); if (m_pInstance) - m_pInstance->SetData(TYPE_ASTROMANCER, IN_PROGRESS); + m_pInstance->SetData(TYPE_SOLARIAN, IN_PROGRESS); } - void SummonMinion(uint32 entry, float x, float y, float z) + void JustReachedHome() override { - Creature* Summoned = m_creature->SummonCreature(entry, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - if (Summoned) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - Summoned->AI()->AttackStart(target); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_SOLARIAN, FAIL); } - float Portal_X(float radius) + void JustSummoned(Creature* pSummoned) override { - if (urand(0, 1)) - radius = -radius; - - return (radius * (float)(rand()%100)/100.0f + CENTER_X); + 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: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + break; + } } - float Portal_Y(float x, float radius) + void DoSummonSpotlight(float fRadius, float fAngle, uint8 uiRandPoint) { - float z = 0.0f; - - switch(urand(0, 1)) - { - case 0: z = 1; break; - case 1: z = -1; break; - } - return (z*sqrt(radius*radius - (x - CENTER_X)*(x - 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (AppearDelay) + // When Solarian reaches 20% she will transform into a huge void walker. + if (m_Phase != PHASE_VOID && m_creature->GetHealthPercent() < 20.0f) { - m_creature->StopMoving(); - m_creature->AttackStop(); - - if (AppearDelay_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_SOLARIAN_TRANSFORM) == CAST_OK) { - AppearDelay = false; + DoScriptText(SAY_VOIDA, m_creature); + m_uiDelayTimer = 2000; - if (Phase == 2) - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_OFF); - } + m_creature->SetArmor(WV_ARMOR); + m_Phase = PHASE_VOID; + + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); - AppearDelay_Timer = 2000; - }else AppearDelay_Timer -= diff; + // Stop the combat for a small delay + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + } } - if (Phase == 1) + // Handle delays between combat phases + if (m_uiDelayTimer) { - //ArcaneMissiles_Timer - if (ArcaneMissiles_Timer < diff) + if (m_uiDelayTimer <= uiDiff) { - //Solarian casts Arcane Missiles on on random targets in the raid. - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (m_Phase == PHASE_SPLIT) { - if (!m_creature->HasInArc(2.5f, target)) - target = m_creature->getVictim(); - - if (target) - DoCastSpellIfCan(target, SPELL_ARCANE_MISSILES); - } + // 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; - ArcaneMissiles_Timer = 3000; - }else ArcaneMissiles_Timer -= diff; + // 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); - //Wrath of the Astromancer targets a random player which will explode after 6 secondes - if (m_uiWrathOfTheAstromancer_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); + m_creature->SetVisibility(VISIBILITY_OFF); - //Target the tank ? - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - { - if (pTarget->GetTypeId() == TYPEID_PLAYER) - { - DoCastSpellIfCan(pTarget, SPELL_WRATH_OF_THE_ASTROMANCER); - m_uiWrathOfTheAstromancer_Timer = 25000; - } - else - m_uiWrathOfTheAstromancer_Timer = 1000; + DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + m_uiSummonAgentsTimer = 6000; } - }else m_uiWrathOfTheAstromancer_Timer -= diff; + else if (m_Phase == PHASE_VOID) + { + DoScriptText(SAY_VOIDB, m_creature); - //BlindingLight_Timer - if (BlindingLight_Timer < diff) - { - //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. - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLINDING_LIGHT); - BlindingLight_Timer = 45000; - }else BlindingLight_Timer -= diff; + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } - //Phase1_Timer - if (Phase1_Timer < diff) - { - Phase = 2; - Phase1_Timer = 50000; + m_uiDelayTimer = 0; + } + else + m_uiDelayTimer -= uiDiff; - //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->GetMap()->CreatureRelocation(m_creature, CENTER_X, CENTER_Y, CENTER_Z, CENTER_O); + // Combat is still on hold + return; + } - for(int i = 0; i <= 2; ++i) + switch (m_Phase) + { + case PHASE_NORMAL: + // Wrath of the Astromancer targets a random player which will explode after 6 secondes + if (m_uiWrathOfTheAstromancerTimer < uiDiff) { - if (!i) + // Target the tank ? + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_WRATH_OF_THE_ASTROMANCER, SELECT_FLAG_PLAYER)) { - Portals[i][0] = Portal_X(SMALL_PORTAL_RADIUS); - Portals[i][1] = Portal_Y(Portals[i][0], SMALL_PORTAL_RADIUS); - Portals[i][2] = CENTER_Z; + if (DoCastSpellIfCan(pTarget, SPELL_WRATH_OF_THE_ASTROMANCER) == CAST_OK) + m_uiWrathOfTheAstromancerTimer = urand(15000, 25000); } else - { - Portals[i][0] = Portal_X(LARGE_PORTAL_RADIUS); - Portals[i][1] = Portal_Y(Portals[i][0], LARGE_PORTAL_RADIUS); - Portals[i][2] = PORTAL_Z; - } + m_uiWrathOfTheAstromancerTimer = 10000; } + else + m_uiWrathOfTheAstromancerTimer -= uiDiff; - if ((abs(int(Portals[2][0]) - int(Portals[1][0])) < 7) && (abs(int(Portals[2][1]) - int(Portals[1][1])) < 7)) + // Blinding Light Timer + if (m_uiBlindingLightTimer < uiDiff) { - int i = 1; - if (abs(int(CENTER_X) + int(26.0f) - int(Portals[2][0])) < 7) - i = -1; - - Portals[2][0] = Portals[2][0]+7*i; - Portals[2][1] = Portal_Y(Portals[2][0], LARGE_PORTAL_RADIUS); + // 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, SPELL_BLINDING_LIGHT) == CAST_OK) + m_uiBlindingLightTimer = 45000; } + else + m_uiBlindingLightTimer -= uiDiff; - for (int i = 0; i <= 2; ++i) + // Arcane Missiles Timer + if (m_uiArcaneMissilesTimer < uiDiff) { - if (Creature* Summoned = m_creature->SummonCreature(NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT, Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O, TEMPSUMMON_TIMED_DESPAWN, Phase2_Timer+Phase3_Timer+AppearDelay_Timer+1700)) + // Solarian casts Arcane Missiles on on random targets in the raid. + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - Summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Summoned->CastSpell(Summoned, SPELL_SPOTLIGHT, false); + if (!m_creature->HasInArc(2.5f, pTarget)) + pTarget = m_creature->getVictim(); + + if (pTarget) + DoCastSpellIfCan(pTarget, SPELL_ARCANE_MISSILES); } - } - AppearDelay = true; - }else Phase1_Timer -= diff; - } - else if (Phase == 2) - { - m_creature->AttackStop(); - m_creature->StopMoving(); + m_uiArcaneMissilesTimer = urand(3000, 4000); + } + else + m_uiArcaneMissilesTimer -= uiDiff; - //Check Phase2_Timer - if (Phase2_Timer < diff) - { - //10 seconds after Solarian disappears, 12 mobs spawn out of the three portals. - Phase = 3; - for (int i = 0; i <= 2; ++i) + // Phase 1 Timer + if (m_uiSplitTimer < uiDiff) { - for (int j = 1; j <= 4; ++j) - SummonMinion(NPC_SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); + // 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. + // 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_uiDelayTimer = 1000; + m_uiSplitTimer = 50000; + // Do nothing more, if phase switched + return; } + else + m_uiSplitTimer -= uiDiff; - DoScriptText(SAY_SUMMON1, m_creature); - - Phase2_Timer = 10000; - } else Phase2_Timer -= diff; - } - else if (Phase == 3) - { - m_creature->AttackStop(); - m_creature->StopMoving(); - - //Check Phase3_Timer - if (Phase3_Timer < diff) - { - Phase = 1; - - //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, Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O); - - for (int j = 0; j <= 2; ++j) - if (j != i) - SummonMinion(NPC_SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); + DoMeleeAttackIfReady(); + break; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); + case PHASE_SPLIT: - DoScriptText(SAY_SUMMON2, m_creature); + // Summon 4 Agents on each portal + if (m_uiSummonAgentsTimer) + { + if (m_uiSummonAgentsTimer <= uiDiff) + { + 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; + } + else + m_uiSummonAgentsTimer -= uiDiff; + } - AppearDelay = true; - Phase3_Timer = 15000; - }else Phase3_Timer -= diff; - } - else if (Phase == 4) - { - //Fear_Timer - if (Fear_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_FEAR); - Fear_Timer = 20000; - }else Fear_Timer -= diff; + if (m_uiSummonPriestsTimer) + { + 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; + } - //VoidBolt_Timer - if (VoidBolt_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_VOID_BOLT); - VoidBolt_Timer = 10000; - }else VoidBolt_Timer -= diff; - } + break; - //When Solarian reaches 20% she will transform into a huge void walker. - if (Phase != 4 && m_creature->GetHealthPercent() < 20.0f) - { - Phase = 4; - - //To make sure she wont be invisible or not selecatble - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); + case PHASE_VOID: + // Fear Timer + if (m_uiFearTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PSYHIC_SCREAM) == CAST_OK) + m_uiFearTimer = 20000; + } + else + m_uiFearTimer -= uiDiff; - DoScriptText(SAY_VOIDA, m_creature); - DoScriptText(SAY_VOIDB, m_creature); + // Void Bolt Timer + if (m_uiVoidBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_VOID_BOLT) == CAST_OK) + m_uiVoidBoltTimer = 10000; + } + else + m_uiVoidBoltTimer -= uiDiff; - m_creature->SetArmor(WV_ARMOR); - m_creature->SetDisplayId(MODEL_VOIDWALKER); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, defaultsize*2.5f); + DoMeleeAttackIfReady(); + break; } - - DoMeleeAttackIfReady(); } }; struct MANGOS_DLL_DECL mob_solarium_priestAI : public ScriptedAI { - mob_solarium_priestAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + mob_solarium_priestAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - ScriptedInstance* m_pInstance; + uint32 m_uiHealTimer; + uint32 m_uiHolySmiteTimer; + uint32 m_uiAoESilenceTimer; - uint32 healTimer; - uint32 holysmiteTimer; - uint32 aoesilenceTimer; + void Reset() override + { + m_uiHealTimer = 9000; + m_uiHolySmiteTimer = 1; + m_uiAoESilenceTimer = 15000; + } - void Reset() + void AttackStart(Unit* pWho) override { - healTimer = 9000; - holysmiteTimer = 1; - aoesilenceTimer = 15000; + 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 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (healTimer < diff) + if (m_uiHealTimer < uiDiff) { - Creature* target = NULL; - - switch(urand(0, 1)) + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - case 0: - if (m_pInstance) - target = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_ASTROMANCER)); - break; - case 1: - target = m_creature; - break; + if (DoCastSpellIfCan(pTarget, SPELL_SOLARIUM_GREAT_HEAL) == CAST_OK) + m_uiHealTimer = 9000; } + } + else + m_uiHealTimer -= uiDiff; - if (target) + if (m_uiHolySmiteTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target,SPELL_SOLARIUM_GREAT_HEAL); - healTimer = 9000; + if (DoCastSpellIfCan(pTarget, SPELL_SOLARIUM_HOLY_SMITE) == CAST_OK) + m_uiHolySmiteTimer = 4000; } - } else healTimer -= diff; - - if (holysmiteTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOLARIUM_HOLY_SMITE); - holysmiteTimer = 4000; - } else holysmiteTimer -= diff; + } + else + m_uiHolySmiteTimer -= uiDiff; - if (aoesilenceTimer < diff) + if (m_uiAoESilenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOLARIUM_ARCANE_TORRENT); - aoesilenceTimer = 13000; - } else aoesilenceTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SOLARIUM_ARCANE_TORRENT) == CAST_OK) + m_uiAoESilenceTimer = 13000; + } + else + m_uiAoESilenceTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -461,14 +481,15 @@ CreatureAI* GetAI_boss_high_astromancer_solarian(Creature* pCreature) void AddSC_boss_high_astromancer_solarian() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_high_astromancer_solarian"; - newscript->GetAI = &GetAI_boss_high_astromancer_solarian; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_solarium_priest"; - newscript->GetAI = &GetAI_mob_solarium_priest; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_high_astromancer_solarian"; + pNewScript->GetAI = &GetAI_boss_high_astromancer_solarian; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_solarium_priest"; + pNewScript->GetAI = &GetAI_mob_solarium_priest; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp b/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp index e46f383731..bc32c1fb9d 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,1172 +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, }; -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 }; -enum Phases +// teleport spells for gravity lapse event +static const uint32 m_auiSpellGravityLapseTeleport[] = { - 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 + 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 CAPERNIAN_DISTANCE = 20.0f; //she casts away from the target -const float KAEL_VISIBLE_RANGE = 50.0f; - -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 MANGOS_DLL_DECL 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: - uint32 m_uiAdvisor_Speech; - public: ScriptedInstance* m_pInstance; - bool m_bFakeDeath; - bool m_bDoubled_Health; - uint32 m_uiDelayRes_Timer; - uint64 m_uiDelayRes_Target; - - void Reset() - { - if (m_bDoubled_Health) - { - m_creature->SetMaxHealth(m_creature->GetMaxHealth() / 2); - m_bDoubled_Health = false; - } - m_bFakeDeath = false; - m_uiDelayRes_Timer = 0; - m_uiDelayRes_Target = 0; + uint32 m_uiFireballTimer; + uint32 m_uiArcaneDisruptionTimer; + uint32 m_uiPhoenixTimer; + uint32 m_uiFlameStrikeTimer; - 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->instance->GetCreature(m_pInstance->GetData64(DATA_KAELTHAS))) - pKaelthas->AI()->EnterEvadeMode(); - } - } + uint32 m_uiPyroblastTimer; + uint32 m_uiShockBarrierTimer; + uint32 m_uiMindControlTimer; + uint32 m_uiExplodeTimer; - void MoveInLineOfSight(Unit* pWho) - { - if (!pWho || m_bFakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; + uint32 m_uiGravityLapseTimer; + uint32 m_uiGravityExpireTimer; + uint32 m_uiNetherBeamTimer; + uint32 m_uiNetherVaporTimer; + uint8 m_uiGravityIndex; - 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_uiAdvisor_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->SetUInt64Value(UNIT_FIELD_TARGET,0); - 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_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_uiDelayRes_Target); - - if (!pTarget) - pTarget = m_creature->getVictim(); - - DoResetThreat(); - AttackStart(pTarget); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(pTarget); - m_creature->AddThreat(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(); - memset(&m_auiAdvisorGuid, 0, sizeof(m_auiAdvisorGuid)); - 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; - - uint64 m_auiAdvisorGuid[MAX_ADVISORS]; - - 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 { - for(uint8 i = 0; i < MAX_ADVISORS; ++i) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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; - - m_auiAdvisorGuid[0] = m_pInstance->GetData64(DATA_THALADRED); - m_auiAdvisorGuid[1] = m_pInstance->GetData64(DATA_SANGUINAR); - m_auiAdvisorGuid[2] = m_pInstance->GetData64(DATA_CAPERNIAN); - m_auiAdvisorGuid[3] = m_pInstance->GetData64(DATA_TELONICUS); - - if (!m_auiAdvisorGuid[0] || !m_auiAdvisorGuid[1] || !m_auiAdvisorGuid[2] || !m_auiAdvisorGuid[3]) - { - 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; + for (uint8 i = 0; i < MAX_WEAPONS; ++i) + DoCastSpellIfCan(m_creature, m_auiSpellSummonWeapon[i], CAST_TRIGGERED); - 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(); - - pWho->SetInCombatWith(m_creature); - m_creature->AddThreat(pWho); - } - } + m_uiPhase = PHASE_2_WEAPON; + m_uiPhaseTimer = 120000; } } - void Aggro(Unit* pWho) - { - if (m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS_PHASE) == PHASE_0_NOT_BEGUN && !m_uiPhase) - StartEvent(); - } - - void KilledUnit(Unit* pUnit) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - 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->GetGUID()); + 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_pInstance) - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_6_COMPLETE); + if (m_uiPhase != PHASE_1_ADVISOR) + return; - for(uint8 i = 0; i < MAX_ADVISORS; ++i) + // Handle phase 1 end + if (uiEntry == NPC_TELONICUS) { - if (Creature* pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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) - { - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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: - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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) - { - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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: - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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) - { - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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: - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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) - { - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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: - pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[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) - { - Creature* pAdvisor = m_creature->GetMap()->GetCreature(m_auiAdvisorGuid[i]); - - if (!pAdvisor) - error_log("SD2: Kael'Thas Advisor %u does not exist. Possibly despawned? Incorrectly Killed?", i); - else - { - 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 (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (m_uiPhoenixTimer < uiDiff) { - DoCastSpellIfCan(pTarget, SPELL_PHOENIX_ANIMATION); - DoScriptText(urand(0, 1) ? SAY_SUMMON_PHOENIX1 : SAY_SUMMON_PHOENIX2, pTarget); + if (DoCastSpellIfCan(m_creature, SPELL_PHOENIX_ANIMATION) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SUMMON_PHOENIX1 : SAY_SUMMON_PHOENIX2, m_creature); + m_uiPhoenixTimer = 60000; + } } - - m_uiPhoenix_Timer = 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->NearTeleportTo(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0.0f); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, aCenterPos[0], aCenterPos[1], aCenterPos[2]); - 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->GetMap()->CreatureRelocation(m_creature, afGravityPos[0], afGravityPos[1], afGravityPos[2], 0.0f); - m_creature->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], SPLINETYPE_NORMAL, SPLINEFLAG_NONE, 1); - - // 1) Kael'thas will portal the whole raid right into his body - 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->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 - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) - { - if (Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid())) - { - m_creature->CastSpell(pUnit, SPELL_KNOCKBACK, true); - //Gravity lapse - needs an exception in Spell system to work - - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE, true, 0, 0, m_creature->GetGUID()); - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_AURA, true, 0, 0, m_creature->GetGUID()); - } - } - 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 MANGOS_DLL_DECL advisor_base_ai : public ScriptedAI { - boss_thaladred_the_darkenerAI(Creature* pCreature) : advisorbase_ai(pCreature) + advisor_base_ai(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiAdvisor_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() + void Reset() override { - m_uiGaze_Timer = 100; - m_uiSilence_Timer = 20000; - m_uiPsychicBlow_Timer = 10000; + m_bCanFakeDeath = true; + m_bFakeDeath = false; - advisorbase_ai::Reset(); + 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 Aggro(Unit* pWho) + void JustReachedHome() override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + // Reset Kael if needed + if (m_pInstance) + { + if (Creature* pKael = m_pInstance->GetSingleCreatureFromStorage(NPC_KAELTHAS)) + pKael->AI()->EnterEvadeMode(); + + m_pInstance->SetData(TYPE_KAELTHAS, FAIL); + } + } + + void DamageTaken(Unit* /*pDoneby*/, uint32& uiDamage) override + { + // Allow fake death only in the first phase + if (!m_bCanFakeDeath) return; - if (!pWho || m_bFakeDeath) + if (uiDamage < m_creature->GetHealth()) return; + // 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 MANGOS_DLL_DECL 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_uiGazeTimer -= uiDiff; + + if (m_uiRendTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_REND) == CAST_OK) + m_uiRendTimer = urand(7000, 12000); } else - m_uiGaze_Timer -= uiDiff; + m_uiRendTimer -= uiDiff; - //m_uiSilence_Timer - if (m_uiSilence_Timer < uiDiff) + if (m_uiSilenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SILENCE); - m_uiSilence_Timer = 20000; + if (DoCastSpellIfCan(m_creature, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = urand(7000, 13000); } else - m_uiSilence_Timer -= uiDiff; + m_uiSilenceTimer -= uiDiff; - //m_uiPsychicBlow_Timer - if (m_uiPsychicBlow_Timer < uiDiff) + if (m_uiPsychicBlowTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHIC_BLOW); - m_uiPsychicBlow_Timer = urand(20000, 25000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHIC_BLOW) == CAST_OK) + m_uiPsychicBlowTimer = urand(20000, 25000); } else - m_uiPsychicBlow_Timer -= uiDiff; + m_uiPsychicBlowTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Lord Sanguinar AI -struct MANGOS_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai +/*###### +## boss_lord_sanguinar +######*/ + +struct MANGOS_DLL_DECL boss_lord_sanguinarAI : public advisor_base_ai { - boss_lord_sanguinarAI(Creature* pCreature) : advisorbase_ai(pCreature) - { - m_uiAdvisor_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 MANGOS_DLL_DECL boss_grand_astromancer_capernianAI : public advisor_base_ai { - boss_grand_astromancer_capernianAI(Creature* pCreature) : advisorbase_ai(pCreature) - { - m_uiAdvisor_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); @@ -1248,197 +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) { - bool m_bInMeleeRange = false; - Unit* pTarget = NULL; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, SPELL_ARCANE_BURST, SELECT_FLAG_IN_MELEE_RANGE)) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - //if in melee range - if (pUnit && pUnit->IsWithinDistInMap(m_creature, ATTACK_DISTANCE)) - { - m_bInMeleeRange = true; - pTarget = pUnit; - break; - } + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_BURST) == CAST_OK) + m_uiArcaneExplosionTimer = urand(4000, 6000); } - - if (m_bInMeleeRange) - DoCastSpellIfCan(pTarget, SPELL_ARCANE_EXPLOSION); - - m_uiArcaneExplosion_Timer = 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 MANGOS_DLL_DECL boss_master_engineer_telonicusAI : public advisor_base_ai { - boss_master_engineer_telonicusAI(Creature* pCreature) : advisorbase_ai(pCreature) - { - m_uiAdvisor_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 +/*###### +## mob_phoenix_tk +######*/ + struct MANGOS_DLL_DECL mob_phoenix_tkAI : public ScriptedAI { mob_phoenix_tkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 m_uiCycle_Timer; + uint32 m_uiCycleTimer; + + bool m_bFakeDeath; - void Reset() + 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_bFakeDeath) return; - if (m_uiRebirth_Timer <= uiDiff) + // 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 MANGOS_DLL_DECL 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); @@ -1476,39 +1266,41 @@ CreatureAI* GetAI_mob_phoenix_egg_tk(Creature* pCreature) void AddSC_boss_kaelthas() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_kaelthas"; - newscript->GetAI = &GetAI_boss_kaelthas; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_thaladred_the_darkener"; - newscript->GetAI = &GetAI_boss_thaladred_the_darkener; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_lord_sanguinar"; - newscript->GetAI = &GetAI_boss_lord_sanguinar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_grand_astromancer_capernian"; - newscript->GetAI = &GetAI_boss_grand_astromancer_capernian; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_master_engineer_telonicus"; - newscript->GetAI = &GetAI_boss_master_engineer_telonicus; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_phoenix_tk"; - newscript->GetAI = &GetAI_mob_phoenix_tk; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_phoenix_egg_tk"; - newscript->GetAI = &GetAI_mob_phoenix_egg_tk; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_kaelthas"; + pNewScript->GetAI = &GetAI_boss_kaelthas; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_kael_phase_2; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_thaladred_the_darkener"; + pNewScript->GetAI = &GetAI_boss_thaladred_the_darkener; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_lord_sanguinar"; + pNewScript->GetAI = &GetAI_boss_lord_sanguinar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_grand_astromancer_capernian"; + pNewScript->GetAI = &GetAI_boss_grand_astromancer_capernian; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_master_engineer_telonicus"; + pNewScript->GetAI = &GetAI_boss_master_engineer_telonicus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_phoenix_tk"; + pNewScript->GetAI = &GetAI_mob_phoenix_tk; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_phoenix_egg_tk"; + pNewScript->GetAI = &GetAI_mob_phoenix_egg_tk; + pNewScript->RegisterSelf(); } 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 8a9e582bd7..9bdeb455ca 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,29 +16,31 @@ /* 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 { @@ -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,83 +86,98 @@ 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); - m_creature->SetInCombatWithZone(); if (m_pInstance) 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); } }; @@ -171,9 +188,10 @@ CreatureAI* GetAI_boss_void_reaver(Creature* pCreature) void AddSC_boss_void_reaver() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_void_reaver"; - newscript->GetAI = &GetAI_boss_void_reaver; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_void_reaver"; + pNewScript->GetAI = &GetAI_boss_void_reaver; + pNewScript->RegisterSelf(); } 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 774bb6bc51..ecd46a6340 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,127 +24,104 @@ EndScriptData */ #include "precompiled.h" #include "the_eye.h" -/* The Eye encounters: -0 - Kael'thas event -1 - Al' ar event -2 - Solarian Event -3 - Void Reaver event -*/ - -struct MANGOS_DLL_DECL instance_the_eye : public ScriptedInstance +instance_the_eye::instance_the_eye(Map* pMap) : ScriptedInstance(pMap), + m_uiKaelthasEventPhase(0) { - instance_the_eye(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint64 m_uiThaladredGUID; - uint64 m_uiSanguinarGUID; - uint64 m_uiCapernianGUID; - uint64 m_uiTelonicusGUID; - uint64 m_uiKaelthasGUID; - uint64 m_uiAstromancerGUID; + Initialize(); +} - uint32 m_uiKaelthasEventPhase; +void instance_the_eye::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - void Initialize() +bool instance_the_eye::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiThaladredGUID = 0; - m_uiSanguinarGUID = 0; - m_uiCapernianGUID = 0; - m_uiTelonicusGUID = 0; - m_uiKaelthasGUID = 0; - m_uiAstromancerGUID = 0; - - m_uiKaelthasEventPhase = 0; + if (m_auiEncounter[i] == IN_PROGRESS) + return true; } - bool IsEncounterInProgress() const - { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; - - return false; - } + return false; +} - void OnCreatureCreate(Creature* pCreature) +void instance_the_eye::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - switch(pCreature->GetEntry()) - { - case 20064: m_uiThaladredGUID = pCreature->GetGUID(); break; - case 20063: m_uiTelonicusGUID = pCreature->GetGUID(); break; - case 20062: m_uiCapernianGUID = pCreature->GetGUID(); break; - case 20060: m_uiSanguinarGUID = pCreature->GetGUID(); break; - case 19622: m_uiKaelthasGUID = pCreature->GetGUID(); break; - case 18805: m_uiAstromancerGUID = pCreature->GetGUID(); break; - } + case NPC_THALADRED: + case NPC_TELONICUS: + case NPC_CAPERNIAN: + case NPC_SANGUINAR: + case NPC_KAELTHAS: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } +} - void SetData(uint32 uiType, uint32 uiData) +void instance_the_eye::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) { - switch(uiType) - { - case TYPE_ALAR: - m_auiEncounter[0] = uiData; - break; - case TYPE_SOLARIAN: - m_auiEncounter[1] = uiData; - break; - case TYPE_VOIDREAVER: - m_auiEncounter[2] = uiData; - break; - case TYPE_ASTROMANCER: - m_auiEncounter[3] = uiData; - break; - - case TYPE_KAELTHAS_PHASE: - m_uiKaelthasEventPhase = uiData; - break; - } + 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; } +} - uint32 GetData(uint32 uiType) +void instance_the_eye::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - switch(uiType) - { - case TYPE_ALAR: - return m_auiEncounter[0]; - case TYPE_SOLARIAN: - return m_auiEncounter[1]; - case TYPE_VOIDREAVER: - return m_auiEncounter[2]; - case TYPE_ASTROMANCER: - return m_auiEncounter[3]; - - case TYPE_KAELTHAS_PHASE: - return m_uiKaelthasEventPhase; - } - - return 0; + case TYPE_ALAR: + case TYPE_SOLARIAN: + 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(); + + // 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; } +} - uint64 GetData64(uint32 uiData) - { - switch(uiData) - { - case DATA_THALADRED: - return m_uiThaladredGUID; - case DATA_SANGUINAR: - return m_uiSanguinarGUID; - case DATA_CAPERNIAN: - return m_uiCapernianGUID; - case DATA_TELONICUS: - return m_uiTelonicusGUID; - case DATA_KAELTHAS: - return m_uiKaelthasGUID; - case DATA_ASTROMANCER: - return m_uiAstromancerGUID; - } +uint32 instance_the_eye::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - return 0; - } -}; + return 0; +} InstanceData* GetInstanceData_instance_the_eye(Map* pMap) { @@ -153,9 +130,10 @@ InstanceData* GetInstanceData_instance_the_eye(Map* pMap) void AddSC_instance_the_eye() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_the_eye"; - newscript->GetInstanceData = &GetInstanceData_instance_the_eye; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_the_eye"; + pNewScript->GetInstanceData = &GetInstanceData_instance_the_eye; + pNewScript->RegisterSelf(); } 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 ee0cc98745..0000000000 --- a/scripts/outland/tempest_keep/the_eye/the_eye.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 *newscript; - newscript = new Script; - newscript->Name = "mob_crystalcore_devastator"; - newscript->GetAI = &GetAI_mob_crystalcore_devastator; - newscript->RegisterSelf(); -} diff --git a/scripts/outland/tempest_keep/the_eye/the_eye.h b/scripts/outland/tempest_keep/the_eye/the_eye.h index 8797841221..8752c6475c 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,20 +8,54 @@ enum { MAX_ENCOUNTER = 4, + MAX_ADVISORS = 4, - TYPE_ALAR = 1, - TYPE_ASTROMANCER = 2, - TYPE_SOLARIAN = 3, - TYPE_VOIDREAVER = 4, - TYPE_KAELTHAS_PHASE = 5, //not regular encounter, contains phase instead + TYPE_ALAR = 0, + TYPE_SOLARIAN = 1, + TYPE_VOIDREAVER = 2, + TYPE_KAELTHAS = 3, - DATA_ASTROMANCER = 8, - DATA_KAELTHAS = 9, + // NPC_ASTROMANCER = 18805, + NPC_KAELTHAS = 19622, - DATA_CAPERNIAN = 10, - DATA_SANGUINAR = 11, - DATA_TELONICUS = 12, - DATA_THALADRED = 13 + NPC_CAPERNIAN = 20062, + NPC_SANGUINAR = 20060, + NPC_TELONICUS = 20063, + NPC_THALADRED = 20064, + + 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, +}; + +static const uint32 aAdvisors[MAX_ADVISORS] = {NPC_CAPERNIAN, NPC_SANGUINAR, NPC_TELONICUS, NPC_THALADRED}; + +class MANGOS_DLL_DECL instance_the_eye : public ScriptedInstance +{ + public: + instance_the_eye(Map* pMap); + + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + // No Save or Load needed to current knowledge + + private: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + uint32 m_uiKaelthasEventPhase; }; #endif 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 3d1ea8ca7c..0000000000 --- a/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (C) 2006 - 2010 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 H_SPELL_SHADOW_POWER 39193 -#define SPELL_HAMMER_PUNCH 35326 -#define SPELL_JACKHAMMER 35327 -#define H_SPELL_JACKHAMMER 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 : H_SPELL_SHADOW_POWER); - 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 : H_SPELL_JACKHAMMER); - - //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 *newscript; - newscript = new Script; - newscript->Name = "boss_gatewatcher_iron_hand"; - newscript->GetAI = &GetAI_boss_gatewatcher_iron_hand; - newscript->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 66f1e17ff5..49fc4fa7b0 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,29 +16,32 @@ /* ScriptData SDName: Boss_Nethermancer_Sepethrea -SD%Complete: 90 -SDComment: Need adjustments to initial summons +SD%Complete: 95 +SDComment: May need some small adjustments SDCategory: Tempest Keep, The Mechanar EndScriptData */ #include "precompiled.h" #include "mechanar.h" -#define SAY_AGGRO -1554013 -#define SAY_SUMMON -1554014 -#define SAY_DRAGONS_BREATH_1 -1554015 -#define SAY_DRAGONS_BREATH_2 -1554016 -#define SAY_SLAY1 -1554017 -#define SAY_SLAY2 -1554018 -#define SAY_DEATH -1554019 - -#define SPELL_SUMMON_RAGIN_FLAMES 35275 - -#define SPELL_FROST_ATTACK 35263 -#define SPELL_ARCANE_BLAST 35314 -#define SPELL_DRAGONS_BREATH 35250 -#define SPELL_KNOCKBACK 37317 -#define SPELL_SOLARBURN 35267 +enum +{ + SAY_AGGRO = -1554013, + SAY_SUMMON = -1554014, + SAY_DRAGONS_BREATH_1 = -1554015, + SAY_DRAGONS_BREATH_2 = -1554016, + SAY_SLAY1 = -1554017, + SAY_SLAY2 = -1554018, + SAY_DEATH = -1554019, + + SPELL_SUMMON_RAGING_FLAMES = 35275, + SPELL_SUMMON_RAGING_FLAMES_H = 39084, + SPELL_FROST_ATTACK = 45195, + SPELL_ARCANE_BLAST = 35314, + SPELL_DRAGONS_BREATH = 35250, + + NPC_RAGING_FLAMES = 20481, +}; struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI { @@ -52,41 +55,29 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 frost_attack_Timer; - uint32 arcane_blast_Timer; - uint32 dragons_breath_Timer; - uint32 knockback_Timer; - uint32 solarburn_Timer; + uint32 m_uiFrostAttackTimer; + uint32 m_uiArcaneBlastTimer; + uint32 m_uiDragonsBreathTimer; - void Reset() + void Reset() override { - frost_attack_Timer = urand(7000, 10000); - arcane_blast_Timer = urand(12000, 18000); - dragons_breath_Timer = urand(18000, 22000); - knockback_Timer = urand(22000, 28000); - solarburn_Timer = 30000; + m_uiFrostAttackTimer = urand(8000, 17000); + m_uiArcaneBlastTimer = urand(14000, 25000); + m_uiDragonsBreathTimer = urand(20000, 26000); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - - //Summon two guards, three in heroic - uint8 am = (m_bIsRegularMode ? 2 : 1); - for(int i = 0; i < am; ++i) - { - DoCastSpellIfCan(who,SPELL_SUMMON_RAGIN_FLAMES); - } - - DoScriptText(SAY_SUMMON, m_creature); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_RAGING_FLAMES : SPELL_SUMMON_RAGING_FLAMES_H); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -94,154 +85,72 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI m_pInstance->SetData(TYPE_SEPETHREA, DONE); } - void UpdateAI(const uint32 diff) + void JustSummoned(Creature* pSummoned) override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Frost Attack - if (frost_attack_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROST_ATTACK); - frost_attack_Timer = urand(7000, 10000); - }else frost_attack_Timer -= diff; - - //Arcane Blast - if (arcane_blast_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANE_BLAST); - arcane_blast_Timer = 15000; - }else arcane_blast_Timer -= diff; - - //Dragons Breath - if (dragons_breath_Timer < diff) + if (pSummoned->GetEntry() == NPC_RAGING_FLAMES) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DRAGONS_BREATH); - - if (urand(0, 1)) - DoScriptText(urand(0, 1) ? SAY_DRAGONS_BREATH_1 : SAY_DRAGONS_BREATH_2, m_creature); - - dragons_breath_Timer = urand(12000, 22000); - }else dragons_breath_Timer -= diff; - - //Check for Knockback - if (knockback_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKBACK); - knockback_Timer = urand(15000, 25000); - }else knockback_Timer -= diff; - - //Check for Solarburn - if (solarburn_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SOLARBURN); - solarburn_Timer = 30000; - }else solarburn_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_nethermancer_sepethrea(Creature* pCreature) -{ - return new boss_nethermancer_sepethreaAI(pCreature); -} + pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); -#define SPELL_INFERNO 35268 -#define H_SPELL_INFERNO 39346 -#define SPELL_FIRE_TAIL 35278 - -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; - uint32 Check_Timer; - - bool onlyonce; - - void Reset() - { - inferno_Timer = 10000; - flame_timer = 500; - Check_Timer = 2000; - onlyonce = false; - m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); - m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + // ToDo: need to fixate target and make them walk! + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->GetMotionMaster()->MoveChase(pTarget); + } } - 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 (!onlyonce) + // Frost Attack + if (m_uiFrostAttackTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - m_creature->GetMotionMaster()->MoveChase(target); - onlyonce = true; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_ATTACK) == CAST_OK) + m_uiFrostAttackTimer = urand(5000, 17000); } + else + m_uiFrostAttackTimer -= uiDiff; - if (inferno_Timer < diff) + // Arcane Blast + if (m_uiArcaneBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_INFERNO : H_SPELL_INFERNO); - - 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; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BLAST) == CAST_OK) + m_uiArcaneBlastTimer = urand(15000, 30000); + } + else + m_uiArcaneBlastTimer -= uiDiff; - //Check_Timer - if (Check_Timer < diff) + // Dragons Breath + if (m_uiDragonsBreathTimer < uiDiff) { - if (m_pInstance) + if (DoCastSpellIfCan(m_creature, SPELL_DRAGONS_BREATH) == CAST_OK) { - if (m_pInstance->GetData(TYPE_SEPETHREA) == DONE) - { - //remove - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - return; - } - } + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_DRAGONS_BREATH_1 : SAY_DRAGONS_BREATH_2, m_creature); - Check_Timer = 1000; - }else Check_Timer -= diff; + m_uiDragonsBreathTimer = urand(20000, 35000); + } + } + else + m_uiDragonsBreathTimer -= uiDiff; DoMeleeAttackIfReady(); } - }; -CreatureAI* GetAI_mob_ragin_flames(Creature* pCreature) + +CreatureAI* GetAI_boss_nethermancer_sepethrea(Creature* pCreature) { - return new mob_ragin_flamesAI(pCreature); + return new boss_nethermancer_sepethreaAI(pCreature); } + void AddSC_boss_nethermancer_sepethrea() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_nethermancer_sepethrea"; - newscript->GetAI = &GetAI_boss_nethermancer_sepethrea; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_ragin_flames"; - newscript->GetAI = &GetAI_mob_ragin_flames; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_nethermancer_sepethrea"; + pNewScript->GetAI = &GetAI_boss_nethermancer_sepethrea; + 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 72350069dc..293358c4a8 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,209 +16,242 @@ /* ScriptData SDName: Boss Pathaleon the Calculator -SD%Complete: 50 -SDComment: Event missing. Script for himself 99% blizzlike. +SD%Complete: 95 +SDComment: Timers may need update. SDCategory: Tempest Keep, The Mechanar EndScriptData */ #include "precompiled.h" +#include "mechanar.h" -#define SAY_AGGRO -1554020 -#define SAY_DOMINATION_1 -1554021 -#define SAY_DOMINATION_2 -1554022 -#define SAY_SUMMON -1554023 -#define SAY_ENRAGE -1554024 -#define SAY_SLAY_1 -1554025 -#define SAY_SLAY_2 -1554026 -#define SAY_DEATH -1554027 - -// Spells to be casted -#define SPELL_MANA_TAP 36021 -#define SPELL_ARCANE_TORRENT 36022 -#define SPELL_DOMINATION 35280 -#define H_SPELL_ARCANE_EXPLOSION 15453 -#define SPELL_FRENZY 36992 - -#define SPELL_SUMMON_NETHER_WRAITH_1 35285 //Spells work, but not implemented -#define SPELL_SUMMON_NETHER_WRAITH_2 35286 -#define SPELL_SUMMON_NETHER_WRAITH_3 35287 -#define SPELL_SUMMON_NETHER_WRAITH_4 35288 - -// Add Spells -#define SPELL_DETONATION 35058 -#define SPELL_ARCANE_MISSILES 35034 +enum +{ + SAY_AGGRO = -1554020, + SAY_DOMINATION_1 = -1554021, + SAY_DOMINATION_2 = -1554022, + SAY_SUMMON = -1554023, + SAY_ENRAGE = -1554024, + SAY_SLAY_1 = -1554025, + SAY_SLAY_2 = -1554026, + SAY_DEATH = -1554027, + + // Spells to be casted + SPELL_MANA_TAP = 36021, + SPELL_ARCANE_TORRENT = 36022, + SPELL_DOMINATION = 35280, + SPELL_ARCANE_EXPLOSION_H = 15453, + SPELL_FRENZY = 36992, + 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, + SPELL_SUMMON_NETHER_WRAITH_3 = 35287, + SPELL_SUMMON_NETHER_WRAITH_4 = 35288, + + // Add Spells + SPELL_DETONATION = 35058, + SPELL_ARCANE_BOLT = 20720, +}; + +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 { boss_pathaleon_the_calculatorAI(Creature* pCreature) : ScriptedAI(pCreature) { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } + ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 Summon_Timer; - uint32 ManaTap_Timer; - uint32 ArcaneTorrent_Timer; - uint32 Domination_Timer; - uint32 ArcaneExplosion_Timer; - bool Enraged; + uint32 m_uiSummonTimer; + uint32 m_uiAngerTimer; + uint32 m_uiManaTapTimer; + uint32 m_uiArcaneTorrentTimer; + uint32 m_uiDominationTimer; + uint32 m_uiArcaneExplosionTimer; + bool m_bIsEnraged; - uint32 Counter; - - void Reset() + void Reset() override { - Summon_Timer = 30000; - ManaTap_Timer = urand(12000, 20000); - ArcaneTorrent_Timer = urand(16000, 25000); - Domination_Timer = urand(25000, 40000); - ArcaneExplosion_Timer = urand(8000, 13000); - - Enraged = false; - Counter = 0; + 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(18000, 45000); + m_bIsEnraged = false; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_PATHALEON, DONE); } - void UpdateAI(const uint32 diff) + void JustSummoned(Creature* pSummoned) override { - //Return since we have no target + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Summon_Timer < diff) + if (m_uiManaTapTimer < uiDiff) { - for(int i = 0; i < 3; ++i) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANA_TAP, SELECT_FLAG_POWER_MANA)) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - Creature* Wraith = m_creature->SummonCreature(21062,m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - if (target && Wraith) - Wraith->AI()->AttackStart(target); + if (DoCastSpellIfCan(pTarget, SPELL_MANA_TAP) == CAST_OK) + m_uiManaTapTimer = urand(16000, 34000); } + } + else + m_uiManaTapTimer -= uiDiff; - DoScriptText(SAY_SUMMON, m_creature); - - Summon_Timer = urand(30000, 45000); - }else Summon_Timer -= diff; - - if (ManaTap_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MANA_TAP); - ManaTap_Timer = urand(14000, 22000); - }else ManaTap_Timer -= diff; - - if (ArcaneTorrent_Timer < diff) + if (m_uiArcaneTorrentTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANE_TORRENT); - ArcaneTorrent_Timer = urand(12000, 18000); - }else ArcaneTorrent_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_TORRENT) == CAST_OK) + m_uiArcaneTorrentTimer = urand(40000, 52000); + } + else + m_uiArcaneTorrentTimer -= uiDiff; - if (Domination_Timer < diff) + if (m_uiDominationTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) { - DoScriptText(urand(0, 1) ? SAY_DOMINATION_1 : SAY_DOMINATION_2, m_creature); - DoCastSpellIfCan(target,SPELL_DOMINATION); + if (DoCastSpellIfCan(pTarget, SPELL_DOMINATION) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_DOMINATION_1 : SAY_DOMINATION_2, m_creature); + m_uiDominationTimer = urand(25000, 30000); + } } + } + else + m_uiDominationTimer -= uiDiff; - Domination_Timer = urand(25000, 30000); - }else Domination_Timer -= diff; - - //Only casting if Heroic Mode is used + // Only casting if Heroic Mode is used if (!m_bIsRegularMode) { - if (ArcaneExplosion_Timer < diff) + if (m_uiArcaneExplosionTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),H_SPELL_ARCANE_EXPLOSION); - ArcaneExplosion_Timer = urand(10000, 14000); - }else ArcaneExplosion_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION_H) == CAST_OK) + m_uiArcaneExplosionTimer = urand(13000, 25000); + } + else + m_uiArcaneExplosionTimer -= uiDiff; } - if (!Enraged && m_creature->GetHealthPercent() < 21.0f) + if (!m_bIsEnraged && m_creature->GetHealthPercent() < 21.0f) { - DoCastSpellIfCan(m_creature, SPELL_FRENZY); - DoScriptText(SAY_ENRAGE, m_creature); - Enraged = true; + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + 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(); } }; -CreatureAI* GetAI_boss_pathaleon_the_calculator(Creature* pCreature) -{ - return new boss_pathaleon_the_calculatorAI(pCreature); -} struct MANGOS_DLL_DECL mob_nether_wraithAI : public ScriptedAI { mob_nether_wraithAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - ScriptedInstance* m_pInstance; - - uint32 ArcaneMissiles_Timer; - uint32 Detonation_Timer; - uint32 Die_Timer; - bool Detonation; + uint32 m_uiArcaneMissilesTimer; + bool m_bHasDetonated; - void Reset() + void Reset() override { - ArcaneMissiles_Timer = urand(1000, 4000); - Detonation_Timer = 20000; - Die_Timer = 2200; - Detonation = false; + m_uiArcaneMissilesTimer = urand(1000, 4000); + m_bHasDetonated = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (ArcaneMissiles_Timer < diff) + if (m_uiArcaneMissilesTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target,SPELL_ARCANE_MISSILES); - else - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANE_MISSILES); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - ArcaneMissiles_Timer = urand(5000, 10000); - }else ArcaneMissiles_Timer -=diff; - - if (!Detonation) - { - if (Detonation_Timer < diff) + if (pTarget) { - DoCastSpellIfCan(m_creature,SPELL_DETONATION); - Detonation = true; - }else Detonation_Timer -= diff; + if (DoCastSpellIfCan(pTarget, SPELL_ARCANE_BOLT) == CAST_OK) + m_uiArcaneMissilesTimer = urand(5000, 10000); + } } + else + m_uiArcaneMissilesTimer -= uiDiff; - if (Detonation) + if (!m_bHasDetonated && m_creature->GetHealthPercent() < 10.0f) { - if (Die_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_DETONATION, CAST_TRIGGERED) == CAST_OK) { - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - }else Die_Timer -= diff; + // 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; + } } DoMeleeAttackIfReady(); } }; + +CreatureAI* GetAI_boss_pathaleon_the_calculator(Creature* pCreature) +{ + return new boss_pathaleon_the_calculatorAI(pCreature); +} + CreatureAI* GetAI_mob_nether_wraith(Creature* pCreature) { return new mob_nether_wraithAI(pCreature); @@ -226,14 +259,15 @@ CreatureAI* GetAI_mob_nether_wraith(Creature* pCreature) void AddSC_boss_pathaleon_the_calculator() { - Script *newscript; - newscript = new Script; - newscript->Name = "boss_pathaleon_the_calculator"; - newscript->GetAI = &GetAI_boss_pathaleon_the_calculator; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_nether_wraith"; - newscript->GetAI = &GetAI_mob_nether_wraith; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_pathaleon_the_calculator"; + pNewScript->GetAI = &GetAI_boss_pathaleon_the_calculator; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_nether_wraith"; + pNewScript->GetAI = &GetAI_mob_nether_wraith; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp b/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp index 68228ee2c8..b683962e80 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -16,43 +16,210 @@ /* 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" -struct MANGOS_DLL_DECL instance_mechanar : public ScriptedInstance +instance_mechanar::instance_mechanar(Map* pMap) : ScriptedInstance(pMap), + m_uiBridgeEventTimer(0), + m_uiBridgeEventPhase(0) { - instance_mechanar(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + Initialize(); +} + +void instance_mechanar::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} - uint32 m_auiEncounter[MAX_ENCOUNTER]; +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_uiEntry, 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) +{ + if (pGo->GetEntry() == GO_FACTORY_ELEVATOR) + { + // ToDo: activate elevator if TYPE_GYRO_KILL && TYPE_IRON_HAND && TYPE_CAPACITUS are DONE + m_mGoEntryGuidStore[GO_FACTORY_ELEVATOR] = pGo->GetObjectGuid(); + } +} - void Initialize() +void instance_mechanar::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + case TYPE_GYRO_KILL: + case TYPE_IRON_HAND: + case TYPE_CAPACITUS: + m_auiEncounter[uiType] = uiData; + // ToDo: Activate the Elevator when all these 3 are done + break; + case TYPE_SEPETHREA: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + m_uiBridgeEventTimer = 10000; + break; + case TYPE_PATHALEON: + m_auiEncounter[uiType] = uiData; + break; } - void SetData(uint32 uiType, uint32 uiData) + if (uiData == DONE) { - switch(uiType) + 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) const +{ + 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) { - case TYPE_SEPETHREA: - m_auiEncounter[0] = uiData; + // Skip the blank entries + if (aBridgeEventLocs[m_uiBridgeEventPhase][i].m_uiEntry == 0) break; + + if (Creature* pTemp = pPlayer->SummonCreature(aBridgeEventLocs[m_uiBridgeEventPhase][i].m_uiEntry, 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; +} - uint32 GetData(uint32 uiType) +void instance_mechanar::Update(uint32 uiDiff) +{ + if (m_uiBridgeEventTimer) { - if (uiType == TYPE_SEPETHREA) - return m_auiEncounter[0]; - - return 0; + if (m_uiBridgeEventTimer <= uiDiff) + { + DoSpawnBridgeWave(); + m_uiBridgeEventTimer = 0; + } + else + m_uiBridgeEventTimer -= uiDiff; } -}; +} InstanceData* GetInstanceData_instance_mechanar(Map* pMap) { @@ -61,9 +228,10 @@ InstanceData* GetInstanceData_instance_mechanar(Map* pMap) void AddSC_instance_mechanar() { - Script *newscript; - newscript = new Script; - newscript->Name = "instance_mechanar"; - newscript->GetInstanceData = &GetInstanceData_instance_mechanar; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_mechanar"; + pNewScript->GetInstanceData = &GetInstanceData_instance_mechanar; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/the_mechanar/mechanar.h b/scripts/outland/tempest_keep/the_mechanar/mechanar.h index 434b5bdfed..1b281d7a80 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 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,9 +7,108 @@ 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_FACTORY_ELEVATOR = 183788, + + SPELL_ETHEREAL_TELEPORT = 34427, + + SAY_PATHALEON_INTRO = -1554028, +}; + +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 +{ + public: + instance_mechanar(Map* pMap); + + 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; + + 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 9fbd15cb3b..72d978fb18 100644 --- a/scripts/outland/terokkar_forest.cpp +++ b/scripts/outland/terokkar_forest.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,125 +17,114 @@ /* ScriptData SDName: Terokkar_Forest SD%Complete: 80 -SDComment: Quest support: 9889, 10009, 10873, 10896, 10446/10447, 10852, 10887, 10922, 11096. Skettis->Ogri'la Flight +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_skyguard_handler_deesak -npc_slim go_veil_skith_cage npc_captive_child +npc_isla_starmane +npc_skywing +npc_cenarion_sparrowhawk +npc_skyguard_prisoner EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "pet_ai.h" /*###### ## mob_unkor_the_ruthless ######*/ -#define SAY_SUBMIT -1000194 +enum +{ + SAY_SUBMIT = -1000194, -#define FACTION_HOSTILE 45 -#define FACTION_FRIENDLY 35 -#define QUEST_DONTKILLTHEFATONE 9889 + FACTION_FRIENDLY = 35, -#define SPELL_PULVERIZE 2676 -//#define SPELL_QUID9889 32174 + SPELL_PULVERIZE = 2676, + SPELL_QUID9889 = 32174, +}; struct MANGOS_DLL_DECL mob_unkor_the_ruthlessAI : public ScriptedAI { mob_unkor_the_ruthlessAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool CanDoQuest; - uint32 UnkorUnfriendly_Timer; - uint32 Pulverize_Timer; + bool m_bCanDoQuest; + uint32 m_uiUnfriendlyTimer; + uint32 m_uiPulverizeTimer; + uint32 m_uiFriendlyTimer; - void Reset() + void Reset() override { - CanDoQuest = false; - UnkorUnfriendly_Timer = 0; - Pulverize_Timer = 3000; + m_bCanDoQuest = false; + m_uiUnfriendlyTimer = 0; + 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(); m_creature->CombatStop(true); - UnkorUnfriendly_Timer = 60000; + m_uiUnfriendlyTimer = 60000; } - void DamageTaken(Unit *done_by, uint32 &damage) + void UpdateAI(const uint32 uiDiff) override { - if (done_by->GetTypeId() == TYPEID_PLAYER) - if ((m_creature->GetHealth()-damage)*100 / m_creature->GetMaxHealth() < 30) + // Reset npc on timer + if (m_uiUnfriendlyTimer) { - if (Group* pGroup = ((Player*)done_by)->GetGroup()) - { - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pGroupie = itr->getSource(); - if (pGroupie && - pGroupie->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE && - pGroupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10) - { - pGroupie->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE); - if (!CanDoQuest) - CanDoQuest = true; - } - } - } else - if (((Player*)done_by)->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE && - ((Player*)done_by)->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10) - { - ((Player*)done_by)->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE); - CanDoQuest = true; - } + if (m_uiUnfriendlyTimer <= uiDiff) + EnterEvadeMode(); + else + m_uiUnfriendlyTimer -= uiDiff; } - } - void UpdateAI(const uint32 diff) - { - if (CanDoQuest) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Do quest kill credit at 30% + if (!m_bCanDoQuest && m_creature->GetHealthPercent() < 30.0f) { - if (!UnkorUnfriendly_Timer) + DoCastSpellIfCan(m_creature, SPELL_QUID9889, CAST_TRIGGERED); + m_uiFriendlyTimer = 1000; + m_bCanDoQuest = true; + } + + // Set faction right after the spell is casted, in order to avoid any issues + if (m_uiFriendlyTimer) + { + if (m_uiFriendlyTimer <= uiDiff) { - //DoCastSpellIfCan(m_creature,SPELL_QUID9889); //not using spell for now DoNice(); + m_uiFriendlyTimer = 0; } else - { - if (UnkorUnfriendly_Timer <= diff) - { - EnterEvadeMode(); - }else UnkorUnfriendly_Timer -= diff; - } + m_uiFriendlyTimer -= uiDiff; } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (Pulverize_Timer < diff) + if (m_uiPulverizeTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_PULVERIZE); - Pulverize_Timer = 9000; - }else Pulverize_Timer -= diff; + DoCastSpellIfCan(m_creature, SPELL_PULVERIZE); + m_uiPulverizeTimer = 9000; + } + else + m_uiPulverizeTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -146,54 +135,6 @@ CreatureAI* GetAI_mob_unkor_the_ruthless(Creature* pCreature) return new mob_unkor_the_ruthlessAI(pCreature); } -/*###### -## mob_infested_root_walker -######*/ - -struct MANGOS_DLL_DECL mob_infested_root_walkerAI : public ScriptedAI -{ - mob_infested_root_walkerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() { } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (done_by && done_by->GetTypeId() == TYPEID_PLAYER) - if (m_creature->GetHealth() <= damage) - if (urand(0, 3)) - //Summon Wood Mites - m_creature->CastSpell(m_creature,39130,true); - } -}; -CreatureAI* GetAI_mob_infested_root_walker(Creature* pCreature) -{ - return new mob_infested_root_walkerAI(pCreature); -} - -/*###### -## mob_rotting_forest_rager -######*/ - -struct MANGOS_DLL_DECL mob_rotting_forest_ragerAI : public ScriptedAI -{ - mob_rotting_forest_ragerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() { } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (done_by->GetTypeId() == TYPEID_PLAYER) - if (m_creature->GetHealth() <= damage) - if (urand(0, 3)) - //Summon Lots of Wood Mights - m_creature->CastSpell(m_creature,39134,true); - } -}; -CreatureAI* GetAI_mob_rotting_forest_rager(Creature* pCreature) -{ - return new mob_rotting_forest_ragerAI(pCreature); -} - /*###### ## mob_netherweb_victim ######*/ @@ -202,13 +143,14 @@ 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 { mob_netherweb_victimAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -217,22 +159,22 @@ 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 (pKiller->GetTypeId() == TYPEID_PLAYER) + if (Player* pPlayer = pKiller->GetCharmerOrOwnerPlayerOrPlayerItself()) { - if (((Player*)pKiller)->GetQuestStatus(QUEST_TAKEN_IN_NIGHT) == QUEST_STATUS_INCOMPLETE) + if (pPlayer->GetQuestStatus(QUEST_TAKEN_IN_NIGHT) == QUEST_STATUS_INCOMPLETE) { 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); - ((Player*)pKiller)->KilledMonsterCredit(NPC_FREED_WARRIOR, m_creature->GetGUID()); + 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[rand()%6], 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); } } } @@ -261,8 +203,8 @@ 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 { @@ -270,26 +212,26 @@ struct MANGOS_DLL_DECL npc_akunoAI : public npc_escortAI 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(); @@ -304,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; @@ -333,10 +275,10 @@ 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->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } } return true; @@ -348,132 +290,39 @@ CreatureAI* GetAI_npc_akuno(Creature* pCreature) } /*###### -## npc_floon +## npc_hungry_nether_ray ######*/ enum { - SAY_FLOON_ATTACK = -1000195, - - SPELL_SILENCE = 6726, - SPELL_FROSTBOLT = 9672, - SPELL_FROST_NOVA = 11831, - - FACTION_HOSTILE_FL = 1738, - QUEST_CRACK_SKULLS = 10009 + EMOTE_FEED = -1000628, + NPC_BLACK_WARP_CHASER = 23219, + SPELL_FEED_CREDIT = 41427, // credit for quest 11093 }; -#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!" -#define GOSSIP_FLOON2 "Hand over the money or die...again!" - -struct MANGOS_DLL_DECL npc_floonAI : public ScriptedAI +struct MANGOS_DLL_DECL npc_hungry_nether_rayAI : public ScriptedPetAI { - npc_floonAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_uiNormFaction = pCreature->getFaction(); - Reset(); - } + npc_hungry_nether_rayAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } - uint32 m_uiNormFaction; - uint32 m_uiSilence_Timer; - uint32 m_uiFrostbolt_Timer; - uint32 m_uiFrostNova_Timer; + void Reset() override { } - void Reset() + void OwnerKilledUnit(Unit* pVictim) override { - 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) + if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetEntry() == NPC_BLACK_WARP_CHASER) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLT); - m_uiFrostbolt_Timer = 5000; - }else m_uiFrostbolt_Timer -= uiDiff; - - DoMeleeAttackIfReady(); + // Distance expected? + if (m_creature->IsWithinDistInMap(pVictim, 10.0f)) + { + DoScriptText(EMOTE_FEED, m_creature); + m_creature->CastSpell(m_creature, SPELL_FEED_CREDIT, true); + } + } } }; -CreatureAI* GetAI_npc_floon(Creature* pCreature) -{ - return new npc_floonAI(pCreature); -} - -bool GossipHello_npc_floon(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_hungry_nether_ray(Creature* pCreature) { - if (pPlayer->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(9442, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_floon(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(9443, pCreature->GetGUID()); - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->setFaction(FACTION_HOSTILE_FL); - DoScriptText(SAY_FLOON_ATTACK, pCreature, pPlayer); - pCreature->AI()->AttackStart(pPlayer); - } - return true; -} - -/*###### -## npc_skyguard_handler_deesak -######*/ - -#define GOSSIP_SKYGUARD "Fly me to Ogri'la please" - -bool GossipHello_npc_skyguard_handler_deesak(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); - - if (pPlayer->GetReputationRank(1031) >= REP_HONORED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SKYGUARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_skyguard_handler_deesak(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer,41279,true); //TaxiPath 705 (Taxi - Skettis to Skyguard Outpost) - } - return true; + return new npc_hungry_nether_rayAI(pCreature); } /*###### @@ -512,7 +361,7 @@ enum MAX_RESEARCHER = 4 }; -//Some details still missing from here, and will also have issues if followers evade for any reason. +// 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 { npc_letollAI(Creature* pCreature) : npc_escortAI(pCreature) @@ -527,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); @@ -551,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) { @@ -567,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; @@ -580,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()) @@ -604,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(); @@ -620,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()) { @@ -630,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); @@ -677,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); @@ -717,9 +566,9 @@ 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->GetGUID(), pQuest, true); + pEscortAI->Start(false, pPlayer, pQuest, true); } } @@ -755,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; @@ -775,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; @@ -787,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) @@ -834,7 +683,7 @@ CreatureAI* GetAI_npc_mana_bomb_exp_trigger(Creature* pCreature) ## go_mana_bomb ######*/ -bool GOHello_go_mana_bomb(Player* pPlayer, GameObject* pGo) +bool GOUse_go_mana_bomb(Player* pPlayer, GameObject* pGo) { if (Creature* pCreature = GetClosestCreatureWithEntry(pGo, NPC_MANA_BOMB_EXPL_TRIGGER, INTERACTION_DISTANCE)) { @@ -846,36 +695,6 @@ bool GOHello_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->GetGUID()); - } - else - pPlayer->SEND_GOSSIP_MENU(9895, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_slim(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - - return true; -} - -/*##### ## go_veil_skith_cage & npc_captive_child #####*/ @@ -889,16 +708,16 @@ enum SAY_THANKS_4 = -1000593 }; -bool GOHello_veil_skith_cage(Player* pPlayer, GameObject* pGo) +bool GOUse_go_veil_skith_cage(Player* pPlayer, GameObject* pGo) { if (pPlayer->GetQuestStatus(QUEST_MISSING_FRIENDS) == QUEST_STATUS_INCOMPLETE) { 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)->GetGUID()); - switch(urand(0,3)) + pPlayer->KilledMonsterCredit(NPC_CAPTIVE_CHILD, (*itr)->GetObjectGuid()); + switch (urand(0, 3)) { case 0: DoScriptText(SAY_THANKS_1, *itr); break; case 1: DoScriptText(SAY_THANKS_2, *itr); break; @@ -917,12 +736,12 @@ struct MANGOS_DLL_DECL npc_captive_child : public ScriptedAI { npc_captive_child(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void WaypointReached(uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 /*uiPointId*/) override { - // we only have one waypoint - m_creature->ForcedDespawn(); + if (uiMotionType == POINT_MOTION_TYPE) + m_creature->ForcedDespawn(); // we only have one waypoint } }; @@ -931,78 +750,559 @@ CreatureAI* GetAI_npc_captive_child(Creature* pCreature) return new npc_captive_child(pCreature); } +/*##### +## npc_isla_starmane +## +## TODO: Verify SpellIDs, Research Timers, Finish Text? +#####*/ + +enum +{ + QUEST_ESCAPE_FROM_FIREWING_POINT_A = 10051, + QUEST_ESCAPE_FROM_FIREWING_POINT_H = 10052, + + SAY_ISLA_PERIODIC_1 = -1000629, + SAY_ISLA_PERIODIC_2 = -1000630, + SAY_ISLA_PERIODIC_3 = -1000631, + SAY_ISLA_START = -1000632, + SAY_ISLA_WAITING = -1000633, + SAY_ISLA_LEAVE_BUILDING = -1000634, + + GO_CAGE = 182794, + + SPELL_ENTANGLING_ROOTS = 33844, // these spell IDs seem to deal not enough dmg, but are linked + SPELL_MOONFIRE = 15798, + SPELL_WRATH = 9739, + SPELL_TRAVELFORM = 32447 // guesswork +}; + +struct MANGOS_DLL_DECL npc_isla_starmaneAI : public npc_escortAI +{ + npc_isla_starmaneAI(Creature* pCreature) : npc_escortAI(pCreature) + { + Reset(); + } + + uint32 m_uiPeriodicTalkTimer; + uint32 m_uiEntanglingRootsTimer; + uint32 m_uiMoonfireTimer; + uint32 m_uiWrathTimer; + + void Reset() override + { + m_uiPeriodicTalkTimer = urand(20000, 40000); + m_uiEntanglingRootsTimer = 100; + m_uiMoonfireTimer = 1600; + m_uiWrathTimer = 2000; + + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + + 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)) + pCage->Use(m_creature); + } + + void WaypointStart(uint32 uiPointId) override + { + switch (uiPointId) + { + case 7: DoScriptText(SAY_ISLA_LEAVE_BUILDING, m_creature); break; + case 68: DoCastSpellIfCan(m_creature, SPELL_TRAVELFORM); break; + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 6: + DoScriptText(SAY_ISLA_WAITING, m_creature); + break; + case 61: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(pPlayer->GetTeam() == ALLIANCE ? QUEST_ESCAPE_FROM_FIREWING_POINT_A : QUEST_ESCAPE_FROM_FIREWING_POINT_H, m_creature); + break; + case 67: + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + m_creature->HandleEmote(EMOTE_ONESHOT_WAVE); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + if (m_uiPeriodicTalkTimer < uiDiff) + { + m_uiPeriodicTalkTimer = urand(30000, 60000); + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_ISLA_PERIODIC_1, m_creature); break; + case 1: DoScriptText(SAY_ISLA_PERIODIC_2, m_creature); break; + case 2: DoScriptText(SAY_ISLA_PERIODIC_3, m_creature); break; + } + } + else + m_uiPeriodicTalkTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEntanglingRootsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENTANGLING_ROOTS) == CAST_OK) + m_uiEntanglingRootsTimer = urand(8000, 16000); + } + else + m_uiEntanglingRootsTimer -= uiDiff; + + if (m_uiMoonfireTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MOONFIRE) == CAST_OK) + m_uiMoonfireTimer = urand(6000, 12000); + } + else + m_uiMoonfireTimer -= uiDiff; + + if (m_uiWrathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_WRATH) == CAST_OK) + m_uiWrathTimer = 2000; + } + else + m_uiWrathTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +bool QuestAccept_npc_isla_starmane(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ESCAPE_FROM_FIREWING_POINT_A || pQuest->GetQuestId() == QUEST_ESCAPE_FROM_FIREWING_POINT_H) + { + if (npc_isla_starmaneAI* pEscortAI = dynamic_cast(pCreature->AI())) + { + pCreature->SetFactionTemporary(pPlayer->GetTeam() == ALLIANCE ? FACTION_ESCORT_A_NEUTRAL_ACTIVE : FACTION_ESCORT_H_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + pEscortAI->Start(false, pPlayer, pQuest); + } + } + return true; +} + +CreatureAI* GetAI_npc_isla_starmane(Creature* pCreature) +{ + return new npc_isla_starmaneAI(pCreature); +} + +/*###### +## npc_skywing +######*/ + +enum +{ + SAY_SKYWING_START = -1000797, + SAY_SKYWING_TREE_DOWN = -1000798, + SAY_SKYWING_TREE_UP = -1000799, + SAY_SKYWING_JUMP = -1000800, + SAY_SKYWING_SUMMON = -1000801, + SAY_SKYWING_END = -1000802, + + 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}; + +struct MANGOS_DLL_DECL npc_skywingAI : public npc_escortAI +{ + npc_skywingAI(Creature* pCreature) : npc_escortAI(pCreature) { 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) override + { + switch (uiPointId) + { + case 6: + DoScriptText(SAY_SKYWING_TREE_DOWN , m_creature); + break; + case 36: + DoScriptText(SAY_SKYWING_TREE_UP, m_creature); + break; + case 60: + DoScriptText(SAY_SKYWING_JUMP, m_creature); + m_creature->SetLevitate(true); + break; + case 61: + m_creature->SetLevitate(false); + 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_OOC_DESPAWN, 30000); + break; + case 81: + // Start transformation + m_uiCycloneTimer = 100; + break; + case 82: + DoScriptText(SAY_SKYWING_END, m_creature); + + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_SKYWING, m_creature); + } + } + + 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) +{ + if (pQuest->GetQuestId() == QUEST_SKYWING) + { + if (npc_skywingAI* pEscortAI = dynamic_cast(pCreature->AI())) + { + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + DoScriptText(SAY_SKYWING_START, pCreature); + + pEscortAI->Start(false, pPlayer, pQuest); + } + } + return true; +} + +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 MANGOS_DLL_DECL 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 MANGOS_DLL_DECL 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 *newscript; - - newscript = new Script; - newscript->Name = "mob_unkor_the_ruthless"; - newscript->GetAI = &GetAI_mob_unkor_the_ruthless; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_infested_root_walker"; - newscript->GetAI = &GetAI_mob_infested_root_walker; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_rotting_forest_rager"; - newscript->GetAI = &GetAI_mob_rotting_forest_rager; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_netherweb_victim"; - newscript->GetAI = &GetAI_mob_netherweb_victim; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_akuno"; - newscript->GetAI = &GetAI_npc_akuno; - newscript->pQuestAccept = &QuestAccept_npc_akuno; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_floon"; - newscript->GetAI = &GetAI_npc_floon; - newscript->pGossipHello = &GossipHello_npc_floon; - newscript->pGossipSelect = &GossipSelect_npc_floon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_letoll"; - newscript->GetAI = &GetAI_npc_letoll; - newscript->pQuestAccept = &QuestAccept_npc_letoll; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_mana_bomb_exp_trigger"; - newscript->GetAI = &GetAI_npc_mana_bomb_exp_trigger; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_mana_bomb"; - newscript->pGOHello = &GOHello_go_mana_bomb; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_skyguard_handler_deesak"; - newscript->pGossipHello = &GossipHello_npc_skyguard_handler_deesak; - newscript->pGossipSelect = &GossipSelect_npc_skyguard_handler_deesak; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_slim"; - newscript->pGossipHello = &GossipHello_npc_slim; - newscript->pGossipSelect = &GossipSelect_npc_slim; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "go_veil_skith_cage"; - newscript->pGOHello = &GOHello_veil_skith_cage; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_captive_child"; - newscript->GetAI = &GetAI_npc_captive_child; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "mob_unkor_the_ruthless"; + pNewScript->GetAI = &GetAI_mob_unkor_the_ruthless; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_netherweb_victim"; + pNewScript->GetAI = &GetAI_mob_netherweb_victim; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_akuno"; + pNewScript->GetAI = &GetAI_npc_akuno; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_akuno; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_hungry_nether_ray"; + pNewScript->GetAI = &GetAI_npc_hungry_nether_ray; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_letoll"; + pNewScript->GetAI = &GetAI_npc_letoll; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_letoll; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_mana_bomb_exp_trigger"; + pNewScript->GetAI = &GetAI_npc_mana_bomb_exp_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_mana_bomb"; + pNewScript->pGOUse = &GOUse_go_mana_bomb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_veil_skith_cage"; + pNewScript->pGOUse = &GOUse_go_veil_skith_cage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_captive_child"; + pNewScript->GetAI = &GetAI_npc_captive_child; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_isla_starmane"; + pNewScript->GetAI = &GetAI_npc_isla_starmane; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_isla_starmane; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_skywing"; + 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 9ef626cb59..2482e19e10 100644 --- a/scripts/outland/zangarmarsh.cpp +++ b/scripts/outland/zangarmarsh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,101 +17,20 @@ /* ScriptData SDName: Zangarmarsh SD%Complete: 100 -SDComment: Quest support: 9752, 9785, 9803, 10009. Mark Of ... buffs. +SDComment: Quest support: 9729, 9752, 9785, 10009. SDCategory: Zangarmarsh EndScriptData */ /* ContentData -npcs_ashyen_and_keleth npc_cooshcoosh -npc_elder_kuruti npc_kayra_longmane -npc_mortog_steamhead -npc_timothy_daniels 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->GetGUID()); - - 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->GetGUID()); - } - return true; -} - /*###### ## npc_cooshcoosh ######*/ @@ -119,12 +38,8 @@ bool GossipSelect_npcs_ashyen_and_keleth(Player* pPlayer, Creature* pCreature, u enum { SPELL_LIGHTNING_BOLT = 9532, - QUEST_CRACK_SKULLS = 10009, - FACTION_HOSTILE_CO = 45 }; -#define GOSSIP_COOSH "You owe Sim'salabim money. Hand them over or die!" - struct MANGOS_DLL_DECL npc_cooshcooshAI : public ScriptedAI { npc_cooshcooshAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -136,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; @@ -144,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(); } @@ -164,71 +80,6 @@ CreatureAI* GetAI_npc_cooshcoosh(Creature* pCreature) return new npc_cooshcooshAI(pCreature); } -bool GossipHello_npc_cooshcoosh(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_COOSH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(9441, pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_cooshcoosh(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->setFaction(FACTION_HOSTILE_CO); - pCreature->AI()->AttackStart(pPlayer); - } - return true; -} - -/*###### -## npc_elder_kuruti -######*/ - -#define GOSSIP_ITEM_KUR1 "Offer treat" -#define GOSSIP_ITEM_KUR2 "Im a messenger for Draenei" -#define GOSSIP_ITEM_KUR3 "Get message" - -bool GossipHello_npc_elder_kuruti(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetQuestStatus(9803) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KUR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(9226, pCreature->GetGUID()); - - return true; -} - -bool GossipSelect_npc_elder_kuruti(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KUR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(9227, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KUR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(9229, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - { - if (!pPlayer->HasItemCount(24573,1)) - { - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(24573, 1)) - pPlayer->SendNewItem(pItem, 1, true, false); - } - - pPlayer->SEND_GOSSIP_MENU(9231, pCreature->GetGUID()); - break; - } - } - return true; -} - /*##### ## npc_kayra_longmane #####*/ @@ -249,19 +100,19 @@ struct MANGOS_DLL_DECL 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); @@ -269,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); @@ -281,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) @@ -291,7 +142,7 @@ bool QuestAccept_npc_kayra_longmane(Player* pPlayer, Creature* pCreature, const DoScriptText(SAY_START, pCreature, pPlayer); if (npc_kayra_longmaneAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer->GetGUID(), pQuest); + pEscortAI->Start(false, pPlayer, pQuest); } return true; } @@ -302,130 +153,203 @@ CreatureAI* GetAI_npc_kayra_longmane(Creature* pCreature) } /*###### -## npc_mortog_steamhead +## event_stormcrow ######*/ -bool GossipHello_npc_mortog_steamhead(Player* pPlayer, Creature* pCreature) +enum { - if (pCreature->isVendor() && 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(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - - return true; -} + QUEST_AS_THE_CROW_FLIES = 9718, + EVENT_ID_STORMCROW = 11225, +}; -bool GossipSelect_npc_mortog_steamhead(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool ProcessEventId_event_taxi_stormcrow(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool bIsStart) { - if (uiAction == GOSSIP_ACTION_TRADE) + if (uiEventId == EVENT_ID_STORMCROW && !bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); + ((Player*)pSource)->SetDisplayId(((Player*)pSource)->GetNativeDisplayId()); + ((Player*)pSource)->AreaExploredOrEventHappens(QUEST_AS_THE_CROW_FLIES); + return true; } - return true; + return false; } -/*###### -## npc_timothy_daniels -######*/ - -#define GOSSIP_TIMOTHY_DANIELS_ITEM1 "Specialist, eh? Just what kind of specialist are you, anyway?" -#define GOSSIP_TEXT_BROWSE_POISONS "Let me browse your reagents and poison supplies." +/*##### +## npc_fhwoor +#####*/ enum { - GOSSIP_TEXTID_TIMOTHY_DANIELS1 = 9239 + 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, }; -bool GossipHello_npc_timothy_daniels(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_fhwoorAI : public npc_escortAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_fhwoorAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_POISONS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + uint32 m_uiStompTimer; + uint32 m_uiShockTimer; - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TIMOTHY_DANIELS_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + bool m_bIsAmbush; -bool GossipSelect_npc_timothy_daniels(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) + void Reset() override { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_TIMOTHY_DANIELS1, pCreature->GetGUID()); - break; - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; + m_uiStompTimer = urand(3000, 7000); + m_uiShockTimer = urand(7000, 11000); + m_bIsAmbush = false; } - return true; -} + 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); + } + } -/*###### -## event_stormcrow -######*/ + 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); + } + } -enum -{ - EVENT_ID_STORMCROW = 11225, + 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(); + } }; -bool ProcessEventId_event_taxi_stormcrow(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +CreatureAI* GetAI_npc_fhwoor(Creature* pCreature) { - if (uiEventId == EVENT_ID_STORMCROW && !bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + return new npc_fhwoorAI(pCreature); +} + +bool QuestAccept_npc_fhwoor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_FHWOOR_SMASH) { - ((Player*)pSource)->SetDisplayId(((Player*)pSource)->GetNativeDisplayId()); + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); return true; } + return false; } void AddSC_zangarmarsh() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npcs_ashyen_and_keleth"; - newscript->pGossipHello = &GossipHello_npcs_ashyen_and_keleth; - newscript->pGossipSelect = &GossipSelect_npcs_ashyen_and_keleth; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_cooshcoosh"; - newscript->GetAI = &GetAI_npc_cooshcoosh; - newscript->pGossipHello = &GossipHello_npc_cooshcoosh; - newscript->pGossipSelect = &GossipSelect_npc_cooshcoosh; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_elder_kuruti"; - newscript->pGossipHello = &GossipHello_npc_elder_kuruti; - newscript->pGossipSelect = &GossipSelect_npc_elder_kuruti; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_kayra_longmane"; - newscript->GetAI = &GetAI_npc_kayra_longmane; - newscript->pQuestAccept = &QuestAccept_npc_kayra_longmane; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_mortog_steamhead"; - newscript->pGossipHello = &GossipHello_npc_mortog_steamhead; - newscript->pGossipSelect = &GossipSelect_npc_mortog_steamhead; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_timothy_daniels"; - newscript->pGossipHello = &GossipHello_npc_timothy_daniels; - newscript->pGossipSelect = &GossipSelect_npc_timothy_daniels; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "event_taxi_stormcrow"; - newscript->pProcessEventId = &ProcessEventId_event_taxi_stormcrow; - newscript->RegisterSelf(); + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_cooshcoosh"; + pNewScript->GetAI = &GetAI_npc_cooshcoosh; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_kayra_longmane"; + pNewScript->GetAI = &GetAI_npc_kayra_longmane; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kayra_longmane; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + 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/pandaria/dread_wastes.cpp b/scripts/pandaria/dread_wastes.cpp new file mode 100644 index 0000000000..84618a57b6 --- /dev/null +++ b/scripts/pandaria/dread_wastes.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Dread_Wastes +SD%Complete: ? +SDComment: Quest support: +SDCategory: Dread Wastes +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_dread_wastes() +{ + +} diff --git a/scripts/pandaria/gate_of_the_setting_sun/boss_commander_ri_mok.cpp b/scripts/pandaria/gate_of_the_setting_sun/boss_commander_ri_mok.cpp new file mode 100644 index 0000000000..1d6f51c91c --- /dev/null +++ b/scripts/pandaria/gate_of_the_setting_sun/boss_commander_ri_mok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_commander_ri_mok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gate of the Setting Sun +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_commander_ri_mok() +{ +} diff --git a/scripts/pandaria/gate_of_the_setting_sun/boss_raigonn.cpp b/scripts/pandaria/gate_of_the_setting_sun/boss_raigonn.cpp new file mode 100644 index 0000000000..e5762f5316 --- /dev/null +++ b/scripts/pandaria/gate_of_the_setting_sun/boss_raigonn.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_raigonn +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gate of the Setting Sun +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_raigonn() +{ +} diff --git a/scripts/pandaria/gate_of_the_setting_sun/boss_saboteur_kip_tilak.cpp b/scripts/pandaria/gate_of_the_setting_sun/boss_saboteur_kip_tilak.cpp new file mode 100644 index 0000000000..f54cc01524 --- /dev/null +++ b/scripts/pandaria/gate_of_the_setting_sun/boss_saboteur_kip_tilak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_saboteur_kip_tilak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gate of the Setting Sun +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_saboteur_kip_tilak() +{ +} diff --git a/scripts/pandaria/gate_of_the_setting_sun/boss_striker_ga_dok.cpp b/scripts/pandaria/gate_of_the_setting_sun/boss_striker_ga_dok.cpp new file mode 100644 index 0000000000..a07239e1de --- /dev/null +++ b/scripts/pandaria/gate_of_the_setting_sun/boss_striker_ga_dok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_striker_ga_dok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gate of the Setting Sun +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_striker_ga_dok() +{ +} diff --git a/scripts/pandaria/gate_of_the_setting_sun/gate_of_the_setting_sun.h b/scripts/pandaria/gate_of_the_setting_sun/gate_of_the_setting_sun.h new file mode 100644 index 0000000000..99c58143b2 --- /dev/null +++ b/scripts/pandaria/gate_of_the_setting_sun/gate_of_the_setting_sun.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_GATEOFTHESETTINGSUN_H +#define DEF_GATEOFTHESETTINGSUN_H + +#endif diff --git a/scripts/pandaria/gate_of_the_setting_sun/instance_gate_of_the_setting_sun.cpp b/scripts/pandaria/gate_of_the_setting_sun/instance_gate_of_the_setting_sun.cpp new file mode 100644 index 0000000000..a4c2d135f9 --- /dev/null +++ b/scripts/pandaria/gate_of_the_setting_sun/instance_gate_of_the_setting_sun.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_gate_of_the_setting_sun +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Gate of the Setting Sun +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_gate_of_the_setting_sun() +{ +} diff --git a/scripts/pandaria/heart_of_fear/boss_amber_shaper_un_sok.cpp b/scripts/pandaria/heart_of_fear/boss_amber_shaper_un_sok.cpp new file mode 100644 index 0000000000..f275276f27 --- /dev/null +++ b/scripts/pandaria/heart_of_fear/boss_amber_shaper_un_sok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_amber_shaper_un_sok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_amber_shaper_un_sok() +{ +} diff --git a/scripts/pandaria/heart_of_fear/boss_blade_lord_ta_yak.cpp b/scripts/pandaria/heart_of_fear/boss_blade_lord_ta_yak.cpp new file mode 100644 index 0000000000..4f9a574194 --- /dev/null +++ b/scripts/pandaria/heart_of_fear/boss_blade_lord_ta_yak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_blade_lord_ta_yak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_blade_lord_ta_yak() +{ +} diff --git a/scripts/pandaria/heart_of_fear/boss_garalon.cpp b/scripts/pandaria/heart_of_fear/boss_garalon.cpp new file mode 100644 index 0000000000..de1491812b --- /dev/null +++ b/scripts/pandaria/heart_of_fear/boss_garalon.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_garalon +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_garalon() +{ +} diff --git a/scripts/pandaria/heart_of_fear/boss_grand_empress_shek_zeer.cpp b/scripts/pandaria/heart_of_fear/boss_grand_empress_shek_zeer.cpp new file mode 100644 index 0000000000..9a581581af --- /dev/null +++ b/scripts/pandaria/heart_of_fear/boss_grand_empress_shek_zeer.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_grand_empress_shek_zeer +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_grand_empress_shek_zeer() +{ +} diff --git a/scripts/pandaria/heart_of_fear/boss_imperial_vizier_zor_lok.cpp b/scripts/pandaria/heart_of_fear/boss_imperial_vizier_zor_lok.cpp new file mode 100644 index 0000000000..814e051ddb --- /dev/null +++ b/scripts/pandaria/heart_of_fear/boss_imperial_vizier_zor_lok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_imperial_vizier_zor_lok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_imperial_vizier_zor_lok() +{ +} diff --git a/scripts/pandaria/heart_of_fear/boss_wind_lord_mel_jarak.cpp b/scripts/pandaria/heart_of_fear/boss_wind_lord_mel_jarak.cpp new file mode 100644 index 0000000000..88c03ee934 --- /dev/null +++ b/scripts/pandaria/heart_of_fear/boss_wind_lord_mel_jarak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_wind_lord_mel_jarak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_wind_lord_mel_jarak() +{ +} diff --git a/scripts/pandaria/heart_of_fear/heart_of_fear.h b/scripts/pandaria/heart_of_fear/heart_of_fear.h new file mode 100644 index 0000000000..a263434166 --- /dev/null +++ b/scripts/pandaria/heart_of_fear/heart_of_fear.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_HEARTOFFEAR_H +#define DEF_HEARTOFFEAR_H + +#endif diff --git a/scripts/pandaria/heart_of_fear/instance_heart_of_fear.cpp b/scripts/pandaria/heart_of_fear/instance_heart_of_fear.cpp new file mode 100644 index 0000000000..7150cf9e9f --- /dev/null +++ b/scripts/pandaria/heart_of_fear/instance_heart_of_fear.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_heart_of_fear +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Heart of Fear +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_heart_of_fear() +{ +} diff --git a/scripts/pandaria/isle_of_giants.cpp b/scripts/pandaria/isle_of_giants.cpp new file mode 100644 index 0000000000..8134f7b2c6 --- /dev/null +++ b/scripts/pandaria/isle_of_giants.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Isle_of_Giants +SD%Complete: ? +SDComment: Quest support: +SDCategory: Isle of Giants +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_isle_of_giants() +{ + +} diff --git a/scripts/pandaria/isle_of_thunder.cpp b/scripts/pandaria/isle_of_thunder.cpp new file mode 100644 index 0000000000..a84ac0434e --- /dev/null +++ b/scripts/pandaria/isle_of_thunder.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Isle_of_Thunder +SD%Complete: ? +SDComment: Quest support: +SDCategory: Isle of Thunder +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_isle_of_thunder() +{ + +} diff --git a/scripts/pandaria/krasarang_wilds.cpp b/scripts/pandaria/krasarang_wilds.cpp new file mode 100644 index 0000000000..f4d8c812c1 --- /dev/null +++ b/scripts/pandaria/krasarang_wilds.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Krasarang_Wilds +SD%Complete: ? +SDComment: Quest support: +SDCategory: Krasarang Wilds +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_krasarang_wilds() +{ + +} diff --git a/scripts/pandaria/kun-lai_summit.cpp b/scripts/pandaria/kun-lai_summit.cpp new file mode 100644 index 0000000000..675a162d26 --- /dev/null +++ b/scripts/pandaria/kun-lai_summit.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Kun-Lai_Summit +SD%Complete: ? +SDComment: Quest support: +SDCategory: Kun-Lai Summit +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_kunlai_summit() +{ + +} diff --git a/scripts/pandaria/mogu_shan_palace/boss_gekkan.cpp b/scripts/pandaria/mogu_shan_palace/boss_gekkan.cpp new file mode 100644 index 0000000000..fb61f7b9b5 --- /dev/null +++ b/scripts/pandaria/mogu_shan_palace/boss_gekkan.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_gekkan +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Palace +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_gekkan() +{ +} diff --git a/scripts/pandaria/mogu_shan_palace/boss_trial_of_the_king.cpp b/scripts/pandaria/mogu_shan_palace/boss_trial_of_the_king.cpp new file mode 100644 index 0000000000..8eed479d61 --- /dev/null +++ b/scripts/pandaria/mogu_shan_palace/boss_trial_of_the_king.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_trial_of_the_king +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Palace +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_trial_of_the_king() +{ +} diff --git a/scripts/pandaria/mogu_shan_palace/boss_xin_the_weaponmaster.cpp b/scripts/pandaria/mogu_shan_palace/boss_xin_the_weaponmaster.cpp new file mode 100644 index 0000000000..01014dc147 --- /dev/null +++ b/scripts/pandaria/mogu_shan_palace/boss_xin_the_weaponmaster.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_xin_the_weaponmaster +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Palace +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_xin_the_weaponmaster() +{ +} diff --git a/scripts/pandaria/mogu_shan_palace/instance_mogu_shan_palace.cpp b/scripts/pandaria/mogu_shan_palace/instance_mogu_shan_palace.cpp new file mode 100644 index 0000000000..023caad5c0 --- /dev/null +++ b/scripts/pandaria/mogu_shan_palace/instance_mogu_shan_palace.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_mogu_shan_palace +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Palace +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_mogu_shan_palace() +{ +} diff --git a/scripts/pandaria/mogu_shan_palace/mogu_shan_palace.h b/scripts/pandaria/mogu_shan_palace/mogu_shan_palace.h new file mode 100644 index 0000000000..5521aa45de --- /dev/null +++ b/scripts/pandaria/mogu_shan_palace/mogu_shan_palace.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MOGUSHANPALACE_H +#define DEF_MOGUSHANPALACE_H + +#endif diff --git a/scripts/pandaria/mogu_shan_vaults/boss_elegon.cpp b/scripts/pandaria/mogu_shan_vaults/boss_elegon.cpp new file mode 100644 index 0000000000..f6a3a40c15 --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/boss_elegon.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_elegon +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_elegon() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/boss_feng_the_accursed.cpp b/scripts/pandaria/mogu_shan_vaults/boss_feng_the_accursed.cpp new file mode 100644 index 0000000000..89aac3e985 --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/boss_feng_the_accursed.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_feng_the_accursed +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_feng_the_accursed() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/boss_gara_jal_the_spiritbinder.cpp b/scripts/pandaria/mogu_shan_vaults/boss_gara_jal_the_spiritbinder.cpp new file mode 100644 index 0000000000..cba7afbb8a --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/boss_gara_jal_the_spiritbinder.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_gara_jal_the_spiritbinder +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_gara_jal_the_spiritbinder() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/boss_the_spirit_kings.cpp b/scripts/pandaria/mogu_shan_vaults/boss_the_spirit_kings.cpp new file mode 100644 index 0000000000..d55dea8d1f --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/boss_the_spirit_kings.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_spirit_kings +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_the_spirit_kings() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/boss_the_stone_guard.cpp b/scripts/pandaria/mogu_shan_vaults/boss_the_stone_guard.cpp new file mode 100644 index 0000000000..e283bbf683 --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/boss_the_stone_guard.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_stone_guard +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_the_stone_guard() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/boss_will_of_the_emperor.cpp b/scripts/pandaria/mogu_shan_vaults/boss_will_of_the_emperor.cpp new file mode 100644 index 0000000000..239cee4b38 --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/boss_will_of_the_emperor.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_will_of_the_emperor +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_will_of_the_emperor() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/instance_mogu_shan_vaults.cpp b/scripts/pandaria/mogu_shan_vaults/instance_mogu_shan_vaults.cpp new file mode 100644 index 0000000000..d9607fbdd2 --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/instance_mogu_shan_vaults.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_mogu_shan_vaults +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Mogu'shan Vaults +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_mogu_shan_vaults() +{ +} diff --git a/scripts/pandaria/mogu_shan_vaults/mogu_shan_vaults.h b/scripts/pandaria/mogu_shan_vaults/mogu_shan_vaults.h new file mode 100644 index 0000000000..ee0dfa8113 --- /dev/null +++ b/scripts/pandaria/mogu_shan_vaults/mogu_shan_vaults.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_MOGUSHANVAULTS_H +#define DEF_MOGUSHANVAULTS_H + +#endif diff --git a/scripts/pandaria/shado_pan_monastery/boss_gu_cloudstrike.cpp b/scripts/pandaria/shado_pan_monastery/boss_gu_cloudstrike.cpp new file mode 100644 index 0000000000..c3fdde4e59 --- /dev/null +++ b/scripts/pandaria/shado_pan_monastery/boss_gu_cloudstrike.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_gu_cloudstrike +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Shado-Pan Monastery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_gu_cloudstrike() +{ +} diff --git a/scripts/pandaria/shado_pan_monastery/boss_master_snowdrift.cpp b/scripts/pandaria/shado_pan_monastery/boss_master_snowdrift.cpp new file mode 100644 index 0000000000..aee2c0ffd0 --- /dev/null +++ b/scripts/pandaria/shado_pan_monastery/boss_master_snowdrift.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_master_snowdrift +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Shado-Pan Monastery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_master_snowdrift() +{ +} diff --git a/scripts/pandaria/shado_pan_monastery/boss_sha_of_violence.cpp b/scripts/pandaria/shado_pan_monastery/boss_sha_of_violence.cpp new file mode 100644 index 0000000000..6da063e478 --- /dev/null +++ b/scripts/pandaria/shado_pan_monastery/boss_sha_of_violence.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_sha_of_violence +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Shado-Pan Monastery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_sha_of_violence() +{ +} diff --git a/scripts/pandaria/shado_pan_monastery/boss_taran_zhu.cpp b/scripts/pandaria/shado_pan_monastery/boss_taran_zhu.cpp new file mode 100644 index 0000000000..5696ac8d82 --- /dev/null +++ b/scripts/pandaria/shado_pan_monastery/boss_taran_zhu.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_taran_zhu +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Shado-Pan Monastery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_taran_zhu() +{ +} diff --git a/scripts/pandaria/shado_pan_monastery/instance_shado_pan_monastery.cpp b/scripts/pandaria/shado_pan_monastery/instance_shado_pan_monastery.cpp new file mode 100644 index 0000000000..c5d8da65ac --- /dev/null +++ b/scripts/pandaria/shado_pan_monastery/instance_shado_pan_monastery.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_shado_pan_monastery +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Shado-Pan Monastery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_shado_pan_monastery() +{ +} diff --git a/scripts/pandaria/shado_pan_monastery/shado_pan_monastery.h b/scripts/pandaria/shado_pan_monastery/shado_pan_monastery.h new file mode 100644 index 0000000000..af92ecb416 --- /dev/null +++ b/scripts/pandaria/shado_pan_monastery/shado_pan_monastery.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SHADOPANMONASTERY_H +#define DEF_SHADOPANMONASTERY_H + +#endif diff --git a/scripts/pandaria/siege_of_niuzao_temple/boss_commander_vojak.cpp b/scripts/pandaria/siege_of_niuzao_temple/boss_commander_vojak.cpp new file mode 100644 index 0000000000..de5ae35df1 --- /dev/null +++ b/scripts/pandaria/siege_of_niuzao_temple/boss_commander_vojak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_commander_vojak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Niuzao Temple +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_commander_vojak() +{ +} diff --git a/scripts/pandaria/siege_of_niuzao_temple/boss_general_pavalak.cpp b/scripts/pandaria/siege_of_niuzao_temple/boss_general_pavalak.cpp new file mode 100644 index 0000000000..fefccc97c1 --- /dev/null +++ b/scripts/pandaria/siege_of_niuzao_temple/boss_general_pavalak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_general_pavalak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Niuzao Temple +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_general_pavalak() +{ +} diff --git a/scripts/pandaria/siege_of_niuzao_temple/boss_vizier_jinbak.cpp b/scripts/pandaria/siege_of_niuzao_temple/boss_vizier_jinbak.cpp new file mode 100644 index 0000000000..2d8aa67283 --- /dev/null +++ b/scripts/pandaria/siege_of_niuzao_temple/boss_vizier_jinbak.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_vizier_jinbak +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Niuzao Temple +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_vizier_jinbak() +{ +} diff --git a/scripts/pandaria/siege_of_niuzao_temple/boss_wing_leader_neronok.cpp b/scripts/pandaria/siege_of_niuzao_temple/boss_wing_leader_neronok.cpp new file mode 100644 index 0000000000..d35d8b6050 --- /dev/null +++ b/scripts/pandaria/siege_of_niuzao_temple/boss_wing_leader_neronok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_wing_leader_neronok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Niuzao Temple +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_wing_leader_neronok() +{ +} diff --git a/scripts/pandaria/siege_of_niuzao_temple/instance_siege_of_niuzao_temple.cpp b/scripts/pandaria/siege_of_niuzao_temple/instance_siege_of_niuzao_temple.cpp new file mode 100644 index 0000000000..c1a7274373 --- /dev/null +++ b/scripts/pandaria/siege_of_niuzao_temple/instance_siege_of_niuzao_temple.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_siege_of_niuzao_temple +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege Of Niuzao Temple +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_siege_of_niuzao_temple() +{ +} diff --git a/scripts/pandaria/siege_of_niuzao_temple/siege_of_niuzao_temple.h b/scripts/pandaria/siege_of_niuzao_temple/siege_of_niuzao_temple.h new file mode 100644 index 0000000000..66252b0b7e --- /dev/null +++ b/scripts/pandaria/siege_of_niuzao_temple/siege_of_niuzao_temple.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SIEGEOFNIUZAOTEMPLE_H +#define DEF_SIEGEOFNIUZAOTEMPLE_H + +#endif diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_galakras.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_galakras.cpp new file mode 100644 index 0000000000..8d77098c1e --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_galakras.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_galakras +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_galakras() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_garrosh_hellscream.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_garrosh_hellscream.cpp new file mode 100644 index 0000000000..9d9642209c --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_garrosh_hellscream.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_garrosh_hellscream +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_garrosh_hellscream() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_general_nazgrim.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_general_nazgrim.cpp new file mode 100644 index 0000000000..d6f4993591 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_general_nazgrim.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_general_nazgrim +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_general_nazgrim() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_iron_juggernaut.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_iron_juggernaut.cpp new file mode 100644 index 0000000000..298520aa43 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_iron_juggernaut.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_iron_juggernaut +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_iron_juggernaut() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_kor_kron_dark_shaman.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_kor_kron_dark_shaman.cpp new file mode 100644 index 0000000000..fd0de0514d --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_kor_kron_dark_shaman.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_kor_kron_dark_shaman +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_kor_kron_dark_shaman() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_malkorok.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_malkorok.cpp new file mode 100644 index 0000000000..95e050c623 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_malkorok.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_malkorok +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_malkorok() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_norushen.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_norushen.cpp new file mode 100644 index 0000000000..b16e435275 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_norushen.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_norushen +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_norushen() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_paragons_of_the_klaxxi.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_paragons_of_the_klaxxi.cpp new file mode 100644 index 0000000000..43da7bb0f0 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_paragons_of_the_klaxxi.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_paragons_of_the_klaxxi +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_paragons_of_the_klaxxi() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_sha_of_pride.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_sha_of_pride.cpp new file mode 100644 index 0000000000..8bb41d141f --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_sha_of_pride.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_sha_of_pride +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_sha_of_pride() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_siegecrafter_blackfuse.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_siegecrafter_blackfuse.cpp new file mode 100644 index 0000000000..7504f1e1cb --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_siegecrafter_blackfuse.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_siegecrafter_blackfuse +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_siegecrafter_blackfuse() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_spoils_of_pandaria.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_spoils_of_pandaria.cpp new file mode 100644 index 0000000000..80d1985fb6 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_spoils_of_pandaria.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_spoils_of_pandaria +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_spoils_of_pandaria() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_the_fallen_protectors.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_the_fallen_protectors.cpp new file mode 100644 index 0000000000..040135111a --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_the_fallen_protectors.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_fallen_protectors +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_the_fallen_protectors() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/boss_thok_the_bloodthirsty.cpp b/scripts/pandaria/siege_of_orgrimmar/boss_thok_the_bloodthirsty.cpp new file mode 100644 index 0000000000..c8fea1c371 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/boss_thok_the_bloodthirsty.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_thok_the_bloodthirsty +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_thok_the_bloodthirsty() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/instance_siege_of_orgrimmar.cpp b/scripts/pandaria/siege_of_orgrimmar/instance_siege_of_orgrimmar.cpp new file mode 100644 index 0000000000..259a147e48 --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/instance_siege_of_orgrimmar.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_siege_of_orgrimmar +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Siege of Orgrimmar +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_siege_of_orgrimmar() +{ +} diff --git a/scripts/pandaria/siege_of_orgrimmar/siege_of_orgrimmar.h b/scripts/pandaria/siege_of_orgrimmar/siege_of_orgrimmar.h new file mode 100644 index 0000000000..2a70c823ea --- /dev/null +++ b/scripts/pandaria/siege_of_orgrimmar/siege_of_orgrimmar.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_SIEGEOFORGRIMMAR_H +#define DEF_SIEGEOFORGRIMMAR_H + +#endif diff --git a/scripts/pandaria/stormstout_brewery/boss_hoptallus.cpp b/scripts/pandaria/stormstout_brewery/boss_hoptallus.cpp new file mode 100644 index 0000000000..e36403919b --- /dev/null +++ b/scripts/pandaria/stormstout_brewery/boss_hoptallus.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_hoptallus +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stormstout Brewery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_hoptallus() +{ +} diff --git a/scripts/pandaria/stormstout_brewery/boss_ook_ook.cpp b/scripts/pandaria/stormstout_brewery/boss_ook_ook.cpp new file mode 100644 index 0000000000..c1bbc51d78 --- /dev/null +++ b/scripts/pandaria/stormstout_brewery/boss_ook_ook.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ook_ook +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stormstout Brewery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ook_ook() +{ +} diff --git a/scripts/pandaria/stormstout_brewery/boss_yan_zhu_the_uncasked.cpp b/scripts/pandaria/stormstout_brewery/boss_yan_zhu_the_uncasked.cpp new file mode 100644 index 0000000000..b0bb2312e4 --- /dev/null +++ b/scripts/pandaria/stormstout_brewery/boss_yan_zhu_the_uncasked.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_yan_zhu_the_uncasked +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stormstout Brewery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_yan_zhu_the_uncasked() +{ +} diff --git a/scripts/pandaria/stormstout_brewery/instance_stormstout_brewery.cpp b/scripts/pandaria/stormstout_brewery/instance_stormstout_brewery.cpp new file mode 100644 index 0000000000..b664e0201e --- /dev/null +++ b/scripts/pandaria/stormstout_brewery/instance_stormstout_brewery.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_stormstout_brewery +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Stormstout Brewery +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_stormstour_brewery() +{ +} diff --git a/scripts/pandaria/stormstout_brewery/stormstout_brewery.h b/scripts/pandaria/stormstout_brewery/stormstout_brewery.h new file mode 100644 index 0000000000..5cb39ae1e8 --- /dev/null +++ b/scripts/pandaria/stormstout_brewery/stormstout_brewery.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_STORMSTOUTBREWERY_H +#define DEF_STORMSTOUTBREWERY_H + +#endif diff --git a/scripts/pandaria/temple_of_the_jade_serpent/boss_liu_flameheart.cpp b/scripts/pandaria/temple_of_the_jade_serpent/boss_liu_flameheart.cpp new file mode 100644 index 0000000000..0e45210e1f --- /dev/null +++ b/scripts/pandaria/temple_of_the_jade_serpent/boss_liu_flameheart.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_liu_flameheart +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Temple of the Jade Serpent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_liu_flameheart() +{ +} diff --git a/scripts/pandaria/temple_of_the_jade_serpent/boss_lorewalker_stonestep.cpp b/scripts/pandaria/temple_of_the_jade_serpent/boss_lorewalker_stonestep.cpp new file mode 100644 index 0000000000..0443c1b281 --- /dev/null +++ b/scripts/pandaria/temple_of_the_jade_serpent/boss_lorewalker_stonestep.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lorewalker_stonestep +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Temple of the Jade Serpent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lorewalker_stonestep() +{ +} diff --git a/scripts/pandaria/temple_of_the_jade_serpent/boss_sha_of_doubt.cpp b/scripts/pandaria/temple_of_the_jade_serpent/boss_sha_of_doubt.cpp new file mode 100644 index 0000000000..2fea0c6d86 --- /dev/null +++ b/scripts/pandaria/temple_of_the_jade_serpent/boss_sha_of_doubt.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_sha_of_doubt +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Temple of the Jade Serpent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_sha_of_doubt() +{ +} diff --git a/scripts/pandaria/temple_of_the_jade_serpent/boss_wise_mari.cpp b/scripts/pandaria/temple_of_the_jade_serpent/boss_wise_mari.cpp new file mode 100644 index 0000000000..302e6da66e --- /dev/null +++ b/scripts/pandaria/temple_of_the_jade_serpent/boss_wise_mari.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_wise_mari +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Temple of the Jade Serpent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_wise_mari() +{ +} diff --git a/scripts/pandaria/temple_of_the_jade_serpent/instance_temple_of_the_jade_serpent.cpp b/scripts/pandaria/temple_of_the_jade_serpent/instance_temple_of_the_jade_serpent.cpp new file mode 100644 index 0000000000..311b8ae0a9 --- /dev/null +++ b/scripts/pandaria/temple_of_the_jade_serpent/instance_temple_of_the_jade_serpent.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_temple_of_the_jade_serpent +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Temple of the Jade Serpent +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_temple_of_the_jade_serpent() +{ +} diff --git a/scripts/pandaria/temple_of_the_jade_serpent/temple_of_the_jade_serpent.h b/scripts/pandaria/temple_of_the_jade_serpent/temple_of_the_jade_serpent.h new file mode 100644 index 0000000000..1e5c53e41e --- /dev/null +++ b/scripts/pandaria/temple_of_the_jade_serpent/temple_of_the_jade_serpent.h @@ -0,0 +1,127 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_TEMPLEOFTHEJADESERPENT_H +#define DEF_TEMPLEOFTHEJADESERPENT_H + +enum Spells +{ + SPELL_CORRUPTED_WATERS = 106778, + //Spells for Lorewalker Stonestep event. + SPELL_SHA_CORRUPTION = 107034, //On spawn: Lot of mobs and decoration + //HAUNTING SHA SPELLS + SPELL_SHA_EXPLOSION_2 = 111812, + //ZAO SUNSEEKER SPELLS + SPELL_SHA_CORRUPTION_2 = 123947, + SPELL_SHOOT_SUN = 112084, //10 52 00 - 11 26 50 - 11 52 35 + SPELL_SHOOT_SUN_2 = 112085, + SPELL_SHA_CORRUPTION_3 = 120000, //OnSpawn: Jiang + SPELL_HELLFIRE_ARROW = 113017, + //LOREWALKER STONESTEP SPELLS + SPELL_JADE_BLAST = 107035, + SPELL_JADE_BLAST_2 = 107048, + SPELL_ROOT_SELF = 106822, + SPELL_LOREWALKER_ALACRITY = 122714, //To cast on players + SPELL_MEDITATION = 122715, + //SCROLL SPELLS + SPELL_SCROLL_FLOOR = 107350, //On spawn + SPELL_JADE_ENERGY = 107384, + SPELL_JADE_ENERGY_2 = 111452, //On spawn + SPELL_DRAW_SHA_2 = 111393, + SPELL_DRAW_SHA_3 = 111431, + SPELL_SHA_BURNING = 111588, //OnDied + SPELL_SHA_EXPLOSION = 111579, //OnDied + SPELL_DEATH = 98391, //OnDied + //SUN SPELLS + SPELL_DRAW_SHA = 111395, + SPELL_SUN = 107349, + SPELL_GROW_LOW = 104921, + SPELL_GROW_HIGH = 111701, + SPELL_SUNFIRE_EXPLOSION = 111737, + SPELL_DUMMY_NUKE = 105898, //11 00 04 - 11 07 05 - 11 40 22 + SPELL_SUNFIRE_BLAST = 111853, + SPELL_SUNFIRE_RAYS = 107223, //09 26 28 - 09 46 29 - 10 06 46 + SPELL_EXTRACT_SHA = 111764, + SPELL_EXTRACT_SHA_2 = 111806, + SPELL_EXTRACT_SHA_3 = 111807, + SPELL_EXTRACT_SHA_4 = 111768, + SPELL_UNKNOWN = 105581, + //JIANG SPELLS + SPELL_JUGGLER_JIANG = 114745, //OnSpawn: Jiang + //THE SONGBIRD QUEEN SPELLS + SPELL_SINGING_SONGBIRD = 114789, //OnSpawn: Songbird + //HAUNTING SHA SPELLS + SPELL_HAUNTING_GAZE = 114650, //OnSpawn + //XIANG SPELLS + SPELL_JUGGLER_XIANG = 114718, + //FISH SPELLS + SPELL_WATER_BUBBLE = 114549, //OnSpawn + //ChannelSpell : 42808, 512 + + SPELL_POSSESSED_BY_SHA = 110164, //On Spawn + SPELL_JADE_ESSENCE = 106797, //AddAura on phase 2 + SPELL_TRANSFORM_VISUAL = 74620, //When the dragon is dead, cast this and remove the possess aura. + + SPELL_FIGMENT_OF_DOUBT_2 = 106935, + SPELL_COPY_WEAPON = 41054, + SPELL_COPY_WEAPON_2 = 41055, + SPELL_BOUNDS_OF_REALITY_2 = 117665, +}; + +enum Creatures +{ + CREATURE_WISE_MARI = 56448, + + CREATURE_SCROLL = 57080, + CREATURE_ZAO_SUNSEEKER = 58826, + CREATURE_LOREWALKTER_STONESTEP = 56843, + CREATURE_SUN = 56915, + CREATURE_SUN_TRIGGER = 56861, + CREATURE_HAUNTING_SHA_2 = 58856, + + CREATURE_STRIFE = 59726, + CREATURE_PERIL = 59051, + + CREATURE_MINION_OF_DOUBTS = 57109, + CREATURE_LIU_FLAMEHEART = 56732, + CREATURE_YU_LON = 56762, + CREATURE_JADE_FIRE = 56893, + + CREATURE_FIGMENT_OF_DOUBT = 56792, + CREATURE_SHA_OF_DOUBT = 56439, +}; + +enum GameObjects +{ + GAMEOBJECT_DOOR_WISE_MARI = 213550, + GAMEOBJECT_DOOR_LOREWALKER_STONSTEP = 213549, + GAMEOBJECT_DOOR_LIU_FLAMEHEART = 213548, + GAMEOBJECT_DOOR_LIU_FLAMEHEART_2 = 213544, +}; + +enum Types +{ + TYPE_LOREWALKTER_STONESTEP = 0, + TYPE_NUMBER_SUN_DEFEATED = 1, + TYPE_SET_SUNS_SELECTABLE = 2, + TYPE_LOREWALKER_STONESTEP_TALK_AFTER_ZAO = 3, + TYPE_SET_SCROLL_SELECTABLE = 4, + TYPE_GET_EVENT_LOREWALKER_STONESTEP = 5, + TYPE_LIU_FLAMEHEART_STATUS = 6, + TYPE_IS_WIPE = 7, + TYPE_CLASS_FIGMENT = 8, + TYPE_CLASS_FIGMENT_DIE = 9, +}; + +enum Status +{ + STATUS_LOREWALKER_STONESTEP_NONE = 1, + STATUS_LOREWALKER_STONESTEP_INTRO = 2, + STATUS_LOREWALKER_STONESTEP_SPAWN_SUNS = 3, + STATUS_LOREWALKER_STONESTEP_SPAWN_SUNS_2= 4, + STATUS_LOREWALKER_STONESTEP_ZAO_COMBAT = 5, + STATUS_LOREWALKER_STONESTEP_FINISH = 6, +}; + +#endif diff --git a/scripts/pandaria/terrace_of_endless_spring/boss_lei_shi.cpp b/scripts/pandaria/terrace_of_endless_spring/boss_lei_shi.cpp new file mode 100644 index 0000000000..550bb6ae11 --- /dev/null +++ b/scripts/pandaria/terrace_of_endless_spring/boss_lei_shi.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lei_shi +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Terrace of Endless Spring +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lei_shi() +{ +} diff --git a/scripts/pandaria/terrace_of_endless_spring/boss_protectors_of_the_endless.cpp b/scripts/pandaria/terrace_of_endless_spring/boss_protectors_of_the_endless.cpp new file mode 100644 index 0000000000..c89c4e8067 --- /dev/null +++ b/scripts/pandaria/terrace_of_endless_spring/boss_protectors_of_the_endless.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_protectors_of_the_endless +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Terrace of Endless Spring +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_protectors_of_the_endless() +{ +} diff --git a/scripts/pandaria/terrace_of_endless_spring/boss_sha_of_fear.cpp b/scripts/pandaria/terrace_of_endless_spring/boss_sha_of_fear.cpp new file mode 100644 index 0000000000..278ec79bdc --- /dev/null +++ b/scripts/pandaria/terrace_of_endless_spring/boss_sha_of_fear.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_sha_of_fear +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Terrace of Endless Spring +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_sha_of_fear() +{ +} diff --git a/scripts/pandaria/terrace_of_endless_spring/boss_tsulong.cpp b/scripts/pandaria/terrace_of_endless_spring/boss_tsulong.cpp new file mode 100644 index 0000000000..4b19019619 --- /dev/null +++ b/scripts/pandaria/terrace_of_endless_spring/boss_tsulong.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_tsulong +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Terrace of Endless Spring +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_tsulong() +{ +} diff --git a/scripts/pandaria/terrace_of_endless_spring/instance_terrace_of_endless_spring.cpp b/scripts/pandaria/terrace_of_endless_spring/instance_terrace_of_endless_spring.cpp new file mode 100644 index 0000000000..b9bce6c18d --- /dev/null +++ b/scripts/pandaria/terrace_of_endless_spring/instance_terrace_of_endless_spring.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_terrace_of_endless_spring +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Terrace of Endless Spring +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_terrace_of_endless_spring() +{ +} diff --git a/scripts/pandaria/terrace_of_endless_spring/terrace_of_endless_spring.h b/scripts/pandaria/terrace_of_endless_spring/terrace_of_endless_spring.h new file mode 100644 index 0000000000..8e861e600f --- /dev/null +++ b/scripts/pandaria/terrace_of_endless_spring/terrace_of_endless_spring.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_TERRACEOFENDLESSSPRING_H +#define DEF_TERRACEOFENDLESSSPRING_H + +#endif diff --git a/scripts/pandaria/the_jade_forest.cpp b/scripts/pandaria/the_jade_forest.cpp new file mode 100644 index 0000000000..428c5ad4c6 --- /dev/null +++ b/scripts/pandaria/the_jade_forest.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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_Jade_Forest +SD%Complete: ? +SDComment: Quest support: +SDCategory: The Jade Forest +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_the_jade_forest() +{ + +} diff --git a/scripts/pandaria/the_veiled_stair.cpp b/scripts/pandaria/the_veiled_stair.cpp new file mode 100644 index 0000000000..7b5b81a28c --- /dev/null +++ b/scripts/pandaria/the_veiled_stair.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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_Veiled_Stair +SD%Complete: ? +SDComment: Quest support: +SDCategory: The Veiled Stair +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_the_veiled_stair() +{ + +} diff --git a/scripts/pandaria/throne_of_thunder/boss_council_of_elders.cpp b/scripts/pandaria/throne_of_thunder/boss_council_of_elders.cpp new file mode 100644 index 0000000000..a82e274245 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_council_of_elders.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_council_of_elders +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_council_of_elders() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_dark_animus.cpp b/scripts/pandaria/throne_of_thunder/boss_dark_animus.cpp new file mode 100644 index 0000000000..fadc242508 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_dark_animus.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_dark_animus +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_dark_animus() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_durumu_the_forgotten.cpp b/scripts/pandaria/throne_of_thunder/boss_durumu_the_forgotten.cpp new file mode 100644 index 0000000000..fc8d4406a0 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_durumu_the_forgotten.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_durumu_the_forgotten +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_durumu_the_forgotten() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_horridon.cpp b/scripts/pandaria/throne_of_thunder/boss_horridon.cpp new file mode 100644 index 0000000000..66aefc2112 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_horridon.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_horridon +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_horridon() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_iron_qon.cpp b/scripts/pandaria/throne_of_thunder/boss_iron_qon.cpp new file mode 100644 index 0000000000..d46d6e174f --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_iron_qon.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_iron_qon +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_iron_qon() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_ji_kun.cpp b/scripts/pandaria/throne_of_thunder/boss_ji_kun.cpp new file mode 100644 index 0000000000..ac62f88a0b --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_ji_kun.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ji_kun +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ji_kun() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_jin_rokh_the_breaker.cpp b/scripts/pandaria/throne_of_thunder/boss_jin_rokh_the_breaker.cpp new file mode 100644 index 0000000000..fa327eee8a --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_jin_rokh_the_breaker.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_jin_rokh_the_breaker +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_jin_rokh_the_breaker() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_lei_shen.cpp b/scripts/pandaria/throne_of_thunder/boss_lei_shen.cpp new file mode 100644 index 0000000000..be4581a783 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_lei_shen.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_lei_shen +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_lei_shen() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_megaera.cpp b/scripts/pandaria/throne_of_thunder/boss_megaera.cpp new file mode 100644 index 0000000000..3a75645467 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_megaera.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_megaera +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_megaera() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_primordius.cpp b/scripts/pandaria/throne_of_thunder/boss_primordius.cpp new file mode 100644 index 0000000000..9d42af49fb --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_primordius.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_primordius +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_primordius() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_ra_den.cpp b/scripts/pandaria/throne_of_thunder/boss_ra_den.cpp new file mode 100644 index 0000000000..a0276591ca --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_ra_den.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_ra_den +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_ra_den() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_tortos.cpp b/scripts/pandaria/throne_of_thunder/boss_tortos.cpp new file mode 100644 index 0000000000..0e9a22928c --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_tortos.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_tortos +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_tortos() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/boss_twin_consorts.cpp b/scripts/pandaria/throne_of_thunder/boss_twin_consorts.cpp new file mode 100644 index 0000000000..2ea8dd93fc --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/boss_twin_consorts.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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_twin_consorts +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_boss_twin_consorts() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/instance_throne_of_thunder.cpp b/scripts/pandaria/throne_of_thunder/instance_throne_of_thunder.cpp new file mode 100644 index 0000000000..30cc56e9aa --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/instance_throne_of_thunder.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2006 - 2013 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: instance_throne_of_thunder +SD%Complete: 0 +SDComment: Placeholder +SDCategory: Throne of Thunder +EndScriptData */ + +#include "precompiled.h" + +void AddSC_instance_throne_of_thunder() +{ +} diff --git a/scripts/pandaria/throne_of_thunder/throne_of_thunder.h b/scripts/pandaria/throne_of_thunder/throne_of_thunder.h new file mode 100644 index 0000000000..88d7d32709 --- /dev/null +++ b/scripts/pandaria/throne_of_thunder/throne_of_thunder.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2010 -2013 by /dev/rsa for ScriptDev2 + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_THRONEOFTHUNDER_H +#define DEF_THRONEOFTHUNDER_H + +#endif diff --git a/scripts/pandaria/townlong_steppes.cpp b/scripts/pandaria/townlong_steppes.cpp new file mode 100644 index 0000000000..8c49f74fc7 --- /dev/null +++ b/scripts/pandaria/townlong_steppes.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Townlong_Steppes +SD%Complete: ? +SDComment: Quest support: +SDCategory: Townlong Steppes +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_townlong_steppes() +{ + +} diff --git a/scripts/pandaria/vale_of_eternal_blossoms.cpp b/scripts/pandaria/vale_of_eternal_blossoms.cpp new file mode 100644 index 0000000000..bacf5ad63c --- /dev/null +++ b/scripts/pandaria/vale_of_eternal_blossoms.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Vale_of_Eternal_Blossoms +SD%Complete: ? +SDComment: Quest support: +SDCategory: Vale of Eternal Blossoms +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_vale_of_eternal_blossoms() +{ + +} diff --git a/scripts/pandaria/valley_of_the_four_winds.cpp b/scripts/pandaria/valley_of_the_four_winds.cpp new file mode 100644 index 0000000000..1fab7538e1 --- /dev/null +++ b/scripts/pandaria/valley_of_the_four_winds.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2006 - 2013 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: Vale_of_the_Four_Winds +SD%Complete: ? +SDComment: Quest support: +SDCategory: Vale of Four Winds +EndScriptData */ + +/* ContentData + +EndContentData */ + +#include "precompiled.h" + +void AddSC_vale_of_the_four_winds() +{ + +} diff --git a/scripts/world/areatrigger_scripts.cpp b/scripts/world/areatrigger_scripts.cpp index 2babab81f3..28cf7c9bc7 100644 --- a/scripts/world/areatrigger_scripts.cpp +++ b/scripts/world/areatrigger_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,7 +17,7 @@ /* ScriptData SDName: Areatrigger_Scripts SD%Complete: 100 -SDComment: Quest support: 6681, 11686, 10589/10604, 12741, 12548, 13315/13351, 12575 +SDComment: Quest support: 4291, 6681, 10589/10604, 11686, 12548, 12575, 12741, 13315/13351, 24849/24851. SDCategory: Areatrigger EndScriptData */ @@ -30,9 +30,13 @@ at_spearborn_encampment 5030 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 EndContentData */ #include "precompiled.h" +#include "world_map_scripts.h" static uint32 TriggerOrphanSpell[6][3] = { @@ -49,7 +53,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; @@ -77,7 +81,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; @@ -96,7 +100,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)) { @@ -119,7 +123,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()) { @@ -149,7 +153,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); @@ -171,13 +175,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; @@ -203,7 +207,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; @@ -231,7 +235,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; @@ -251,7 +255,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); @@ -259,52 +263,144 @@ bool AreaTrigger_at_stormwright_shelf(Player* pPlayer, AreaTriggerEntry const* p return true; } +/*###### +## at_scent_larkorwi +######*/ + +enum +{ + QUEST_SCENT_OF_LARKORWI = 4291, + NPC_LARKORWI_MATE = 9683 +}; + +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_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; +} + void AddSC_areatrigger_scripts() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "at_childrens_week_spot"; - pNewScript->pAreaTrigger = &AreaTrigger_at_childrens_week_spot; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_aldurthar_gate"; - pNewScript->pAreaTrigger = &AreaTrigger_at_aldurthar_gate; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_coilfang_waterfall"; - pNewScript->pAreaTrigger = &AreaTrigger_at_coilfang_waterfall; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_legion_teleporter"; - pNewScript->pAreaTrigger = &AreaTrigger_at_legion_teleporter; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_ravenholdt"; - pNewScript->pAreaTrigger = &AreaTrigger_at_ravenholdt; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_spearborn_encampment"; - pNewScript->pAreaTrigger = &AreaTrigger_at_spearborn_encampment; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_warsong_farms"; - pNewScript->pAreaTrigger = &AreaTrigger_at_warsong_farms; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_waygate"; - pNewScript->pAreaTrigger = &AreaTrigger_at_waygate; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "at_stormwright_shelf"; - pNewScript->pAreaTrigger = &AreaTrigger_at_stormwright_shelf; - pNewScript->RegisterSelf(); + AutoScript s; + + s.newScript("at_childrens_week_spot"); + s->pAreaTrigger = &AreaTrigger_at_childrens_week_spot; + + s.newScript("at_aldurthar_gate"); + s->pAreaTrigger = &AreaTrigger_at_aldurthar_gate; + + s.newScript("at_coilfang_waterfall"); + s->pAreaTrigger = &AreaTrigger_at_coilfang_waterfall; + + s.newScript("at_legion_teleporter"); + s->pAreaTrigger = &AreaTrigger_at_legion_teleporter; + + s.newScript("at_ravenholdt"); + s->pAreaTrigger = &AreaTrigger_at_ravenholdt; + + s.newScript("at_spearborn_encampment"); + s->pAreaTrigger = &AreaTrigger_at_spearborn_encampment; + + s.newScript("at_warsong_farms"); + s->pAreaTrigger = &AreaTrigger_at_warsong_farms; + + s.newScript("at_waygate"); + s->pAreaTrigger = &AreaTrigger_at_waygate; + + s.newScript("at_stormwright_shelf"); + s->pAreaTrigger = &AreaTrigger_at_stormwright_shelf; + + s.newScript("at_scent_larkorwi"); + s->pAreaTrigger = &AreaTrigger_at_scent_larkorwi; + + s.newScript("at_murkdeep"); + s->pAreaTrigger = &AreaTrigger_at_murkdeep; + + s.newScript("at_hot_on_the_trail"); + s->pAreaTrigger = &AreaTrigger_at_hot_on_the_trail; } diff --git a/scripts/world/boss_emeriss.cpp b/scripts/world/boss_emeriss.cpp deleted file mode 100644 index 44727b1c23..0000000000 --- a/scripts/world/boss_emeriss.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Emeriss -SD%Complete: 90 -SDComment: Teleport function & Mark of Nature missing -SDCategory: Bosses -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SAY_AGGRO = -1000401, - SAY_CASTCORRUPTION = -1000402, - - SPELL_SLEEP = 24777, - SPELL_NOXIOUSBREATH = 24818, - SPELL_TAILSWEEP = 15847, - //SPELL_MARKOFNATURE = 25040, // Not working - SPELL_VOLATILEINFECTION = 24928, - SPELL_CORRUPTIONOFEARTH = 24910 -}; - -struct MANGOS_DLL_DECL boss_emerissAI : public ScriptedAI -{ - boss_emerissAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiSleep_Timer; - uint32 m_uiNoxiousBreath_Timer; - uint32 m_uiTailSweep_Timer; - //uint32 m_uiMarkOfNature_Timer; - uint32 m_uiVolatileInfection_Timer; - uint32 m_uiCorruptionsCasted; - - void Reset() - { - m_uiSleep_Timer = urand(15000, 20000); - m_uiNoxiousBreath_Timer = 8000; - m_uiTailSweep_Timer = 4000; - //m_uiMarkOfNature_Timer = 45000; - m_uiVolatileInfection_Timer = 12000; - m_uiCorruptionsCasted = 0; - } - - void Aggro(Unit* pWho) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Sleep_Timer - if (m_uiSleep_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_SLEEP); - - m_uiSleep_Timer = urand(8000, 16000); - } - else - m_uiSleep_Timer -= uiDiff; - - //NoxiousBreath_Timer - if (m_uiNoxiousBreath_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_NOXIOUSBREATH); - m_uiNoxiousBreath_Timer = urand(14000, 20000); - } - else - m_uiNoxiousBreath_Timer -= uiDiff; - - //Tailsweep every 2 seconds - if (m_uiTailSweep_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_TAILSWEEP); - m_uiTailSweep_Timer = 2000; - } - else - m_uiTailSweep_Timer -= uiDiff; - - //MarkOfNature_Timer - //if (m_uiMarkOfNature_Timer < uiDiff) - //{ - // DoCastSpellIfCan(m_creature->getVictim(), SPELL_MARKOFNATURE); - // m_uiMarkOfNature_Timer = 45000; - //} - //else - //m_uiMarkOfNature_Timer -= uiDiff; - - //VolatileInfection_Timer - if (m_uiVolatileInfection_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_VOLATILEINFECTION); - m_uiVolatileInfection_Timer = urand(7000, 12000); - } - else - m_uiVolatileInfection_Timer -= uiDiff; - - //CorruptionofEarth at 75%, 50% and 25% - if (m_creature->GetHealthPercent() < float(100 - 25*m_uiCorruptionsCasted)) - { - ++m_uiCorruptionsCasted; // prevent casting twice on same hp - DoScriptText(SAY_CASTCORRUPTION, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORRUPTIONOFEARTH); - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_emeriss(Creature* pCreature) -{ - return new boss_emerissAI(pCreature); -} - -void AddSC_boss_emeriss() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "boss_emeriss"; - newscript->GetAI = &GetAI_boss_emeriss; - newscript->RegisterSelf(); -} diff --git a/scripts/world/boss_taerar.cpp b/scripts/world/boss_taerar.cpp deleted file mode 100644 index a41bc109b1..0000000000 --- a/scripts/world/boss_taerar.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Taerar -SD%Complete: 70 -SDComment: Mark of Nature & Teleport NYI. Fix the way to be banished. -SDCategory: Bosses -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SAY_AGGRO = -1000399, - SAY_SUMMONSHADE = -1000400, - - //Spells of Taerar - SPELL_SLEEP = 24777, - SPELL_NOXIOUSBREATH = 24818, - SPELL_TAILSWEEP = 15847, - // SPELL_MARKOFNATURE = 25040, // Not working - SPELL_ARCANEBLAST = 24857, - SPELL_BELLOWINGROAR = 22686, - - SPELL_SUMMONSHADE_1 = 24841, - SPELL_SUMMONSHADE_2 = 24842, - SPELL_SUMMONSHADE_3 = 24843, - - //Spells of Shades of Taerar - SPELL_POSIONCLOUD = 24840, - SPELL_POSIONBREATH = 20667 -}; - -uint32 m_auiSpellSummonShade[]= -{ - SPELL_SUMMONSHADE_1, SPELL_SUMMONSHADE_2, SPELL_SUMMONSHADE_3 -}; - -struct MANGOS_DLL_DECL boss_taerarAI : public ScriptedAI -{ - boss_taerarAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiSleep_Timer; - uint32 m_uiNoxiousBreath_Timer; - uint32 m_uiTailSweep_Timer; - //uint32 m_uiMarkOfNature_Timer; - uint32 m_uiArcaneBlast_Timer; - uint32 m_uiBellowingRoar_Timer; - uint32 m_uiShades_Timer; - uint32 m_uiShadesSummoned; - - bool m_bShades; - - void Reset() - { - m_uiSleep_Timer = urand(15000, 20000); - m_uiNoxiousBreath_Timer = 8000; - m_uiTailSweep_Timer = 4000; - //m_uiMarkOfNature_Timer = 45000; - m_uiArcaneBlast_Timer = 12000; - m_uiBellowingRoar_Timer = 30000; - m_uiShades_Timer = 60000; //The time that Taerar is banished - m_uiShadesSummoned = 0; - - m_bShades = false; - } - - void Aggro(Unit* pWho) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - 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_bShades && m_uiShades_Timer < uiDiff) - { - //Become unbanished again - m_creature->setFaction(14); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_bShades = false; - } - else if (m_bShades) - { - m_uiShades_Timer -= uiDiff; - //Do nothing while banished - return; - } - - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Sleep_Timer - if (m_uiSleep_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_SLEEP); - - m_uiSleep_Timer = urand(8000, 15000); - } - else - m_uiSleep_Timer -= uiDiff; - - //NoxiousBreath_Timer - if (m_uiNoxiousBreath_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_NOXIOUSBREATH); - m_uiNoxiousBreath_Timer = urand(14000, 20000); - } - else - m_uiNoxiousBreath_Timer -= uiDiff; - - //Tailsweep every 2 seconds - if (m_uiTailSweep_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_TAILSWEEP); - m_uiTailSweep_Timer = 2000; - } - else - m_uiTailSweep_Timer -= uiDiff; - - //MarkOfNature_Timer - //if (m_uiMarkOfNature_Timer < uiDiff) - //{ - // DoCastSpellIfCan(m_creature->getVictim(), SPELL_MARKOFNATURE); - // m_uiMarkOfNature_Timer = 45000; - //} - //else - //m_uiMarkOfNature_Timer -= uiDiff; - - //ArcaneBlast_Timer - if (m_uiArcaneBlast_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANEBLAST); - m_uiArcaneBlast_Timer = urand(7000, 12000); - } - else - m_uiArcaneBlast_Timer -= uiDiff; - - //BellowingRoar_Timer - if (m_uiBellowingRoar_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BELLOWINGROAR); - m_uiBellowingRoar_Timer = urand(20000, 30000); - } - else - m_uiBellowingRoar_Timer -= uiDiff; - - //Summon 3 Shades at 75%, 50% and 25% (if bShades is true we already left in line 117, no need to check here again) - if (!m_bShades && m_creature->GetHealthPercent() < float(100 - 25*m_uiShadesSummoned)) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - //Inturrupt any spell casting - m_creature->InterruptNonMeleeSpells(false); - - //horrible workaround, need to fix - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - DoScriptText(SAY_SUMMONSHADE, m_creature); - - int iSize = sizeof(m_auiSpellSummonShade) / sizeof(uint32); - - for(int i = 0; i < iSize; ++i) - m_creature->CastSpell(pTarget, m_auiSpellSummonShade[i], true); - - ++m_uiShadesSummoned; // prevent casting twice at same health - m_bShades = true; - } - m_uiShades_Timer = 60000; - } - - DoMeleeAttackIfReady(); - } -}; - -// 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); -} - -void AddSC_boss_taerar() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_taerar"; - newscript->GetAI = &GetAI_boss_taerar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "boss_shade_of_taerar"; - newscript->GetAI = &GetAI_boss_shadeoftaerar; - newscript->RegisterSelf(); -} diff --git a/scripts/world/boss_ysondre.cpp b/scripts/world/boss_ysondre.cpp deleted file mode 100644 index 921ba38f25..0000000000 --- a/scripts/world/boss_ysondre.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* Copyright (C) 2006 - 2010 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: Ysondre -SD%Complete: 90 -SDComment: Mark of Nature & Teleport missing -SDCategory: Bosses -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SAY_AGGRO = -1000360, - SAY_SUMMONDRUIDS = -1000361, - - SPELL_SLEEP = 24777, - SPELL_NOXIOUSBREATH = 24818, - SPELL_TAILSWEEP = 15847, - //SPELL_MARKOFNATURE = 25040, // Not working - SPELL_LIGHTNINGWAVE = 24819, - SPELL_SUMMONDRUIDS = 24795, - - SPELL_SUMMON_PLAYER = 24776, - - //druid spells - SPELL_MOONFIRE = 21669 -}; - -// Ysondre script -struct MANGOS_DLL_DECL boss_ysondreAI : public ScriptedAI -{ - boss_ysondreAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiSleep_Timer; - uint32 m_uiNoxiousBreath_Timer; - uint32 m_uiTailSweep_Timer; - //uint32 m_uiMarkOfNature_Timer; - uint32 m_uiLightningWave_Timer; - uint32 m_uiSummonDruidModifier; - - void Reset() - { - m_uiSleep_Timer = urand(15000, 20000); - m_uiNoxiousBreath_Timer = 8000; - m_uiTailSweep_Timer = 4000; - //m_uiMarkOfNature_Timer = 45000; - m_uiLightningWave_Timer = 12000; - m_uiSummonDruidModifier = 0; - } - - void Aggro(Unit* pWho) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - 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; - - //Sleep_Timer - if (m_uiSleep_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_SLEEP); - - m_uiSleep_Timer = urand(8000, 15000); - } - else - m_uiSleep_Timer -= uiDiff; - - //NoxiousBreath_Timer - if (m_uiNoxiousBreath_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_NOXIOUSBREATH); - m_uiNoxiousBreath_Timer = urand(14000, 20000); - } - else - m_uiNoxiousBreath_Timer -= uiDiff; - - //Tailsweep every 2 seconds - if (m_uiTailSweep_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_TAILSWEEP); - m_uiTailSweep_Timer = 2000; - } - else - m_uiTailSweep_Timer -= uiDiff; - - //MarkOfNature_Timer - //if (m_uiMarkOfNature_Timer < uiDiff) - //{ - // DoCastSpellIfCan(m_creature->getVictim(), SPELL_MARKOFNATURE); - // m_uiMarkOfNature_Timer = 45000; - //} - //else - //m_uiMarkOfNature_Timer -= uiDiff; - - //LightningWave_Timer - if (m_uiLightningWave_Timer < uiDiff) - { - //Cast LIGHTNINGWAVE on a Random target - if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_LIGHTNINGWAVE); - - m_uiLightningWave_Timer = urand(7000, 12000); - } - else - m_uiLightningWave_Timer -= uiDiff; - - //Summon Druids - if (m_creature->GetHealthPercent() <= float(100 - 25*m_uiSummonDruidModifier)) - { - DoScriptText(SAY_SUMMONDRUIDS, m_creature); - - for(int i = 0; i < 10; ++i) - DoCastSpellIfCan(m_creature, SPELL_SUMMONDRUIDS, CAST_TRIGGERED); - - ++m_uiSummonDruidModifier; - } - - DoMeleeAttackIfReady(); - } -}; - -// 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_boss_ysondre() -{ - Script *newscript; - - newscript = new Script; - newscript->Name = "boss_ysondre"; - newscript->GetAI = &GetAI_boss_ysondre; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "mob_dementeddruids"; - newscript->GetAI = &GetAI_mob_dementeddruids; - newscript->RegisterSelf(); -} diff --git a/scripts/world/bosses_emerald_dragons.cpp b/scripts/world/bosses_emerald_dragons.cpp new file mode 100644 index 0000000000..50f30dc929 --- /dev/null +++ b/scripts/world/bosses_emerald_dragons.cpp @@ -0,0 +1,545 @@ +/* Copyright (C) 2006 - 2013 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: bosses_emerald_dragons +SD%Complete: 95 +SDComment: Missing correct behaviour of used trigger NPCs, some spell issues, summon player NYI +SDCategory: Emerald Dragon Bosses +EndScriptData */ + +/* ContentData +boss_emerald_dragon -- Superclass for the four dragons +boss_emeriss +boss_lethon +npc_spirit_shade +boss_taerar +boss_ysondre +EndContentData */ + +#include "precompiled.h" + +/*###### +## boss_emerald_dragon -- Superclass for the four dragons +######*/ + +enum +{ + SPELL_MARK_OF_NATURE_PLAYER = 25040, + SPELL_MARK_OF_NATURE_AURA = 25041, + SPELL_SEEPING_FOG_R = 24813, // Summons 15224 'Dream Fog' + SPELL_SEEPING_FOG_L = 24814, + SPELL_DREAM_FOG = 24777, // Used by summoned Adds + SPELL_NOXIOUS_BREATH = 24818, + SPELL_TAILSWEEP = 15847, + SPELL_SUMMON_PLAYER = 24776, // NYI + + NPC_DREAM_FOG = 15224, +}; + +struct MANGOS_DLL_DECL boss_emerald_dragonAI : public ScriptedAI +{ + boss_emerald_dragonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiEventCounter; + + uint32 m_uiSeepingFogTimer; + uint32 m_uiNoxiousBreathTimer; + uint32 m_uiTailsweepTimer; + + void Reset() override + { + m_uiEventCounter = 1; + + m_uiSeepingFogTimer = urand(15000, 20000); + m_uiNoxiousBreathTimer = 8000; + m_uiTailsweepTimer = 4000; + } + + void EnterCombat(Unit* pEnemy) override + { + DoCastSpellIfCan(m_creature, SPELL_MARK_OF_NATURE_AURA, CAST_TRIGGERED); + + ScriptedAI::EnterCombat(pEnemy); + } + + 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) override + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + if (pSummoned->GetEntry() == NPC_DREAM_FOG) + pSummoned->CastSpell(pSummoned, SPELL_DREAM_FOG, true, NULL, NULL, m_creature->GetObjectGuid()); + } + + // Return true, if succeeded + virtual bool DoSpecialDragonAbility() = 0; + + // Return true to handle shared timers and MeleeAttack + virtual bool UpdateDragonAI(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; + + // Trigger special ability function at 75, 50 and 25% health + if (m_creature->GetHealthPercent() < 100.0f - m_uiEventCounter * 25.0f && DoSpecialDragonAbility()) + ++m_uiEventCounter; + + // Call dragon specific virtual function + if (!UpdateDragonAI(uiDiff)) + return; + + if (m_uiSeepingFogTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_SEEPING_FOG_R, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SEEPING_FOG_L, CAST_TRIGGERED); + m_uiSeepingFogTimer = urand(120000, 150000); // Rather Guesswork, but one Fog has 2min duration, hence a bit longer + } + else + m_uiSeepingFogTimer -= uiDiff; + + if (m_uiNoxiousBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NOXIOUS_BREATH) == CAST_OK) + m_uiNoxiousBreathTimer = urand(14000, 20000); + } + else + m_uiNoxiousBreathTimer -= uiDiff; + + if (m_uiTailsweepTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAILSWEEP) == CAST_OK) + m_uiTailsweepTimer = 2000; + } + else + m_uiTailsweepTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## boss_emeriss +######*/ + +enum +{ + SAY_EMERISS_AGGRO = -1000401, + SAY_CAST_CORRUPTION = -1000402, + + SPELL_VOLATILE_INFECTION = 24928, + SPELL_CORRUPTION_OF_EARTH = 24910, + SPELL_PUTRID_MUSHROOM = 24904, // Summons a mushroom on killing a player +}; + +struct MANGOS_DLL_DECL boss_emerissAI : public boss_emerald_dragonAI +{ + boss_emerissAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) { Reset(); } + + uint32 m_uiVolatileInfectionTimer; + + void Reset() override + { + boss_emerald_dragonAI::Reset(); + + m_uiVolatileInfectionTimer = 12000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_EMERISS_AGGRO, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + // summon a mushroom on the spot the player dies + if (pVictim->GetTypeId() == TYPEID_PLAYER) + pVictim->CastSpell(pVictim, SPELL_PUTRID_MUSHROOM, true, NULL, NULL, m_creature->GetObjectGuid()); + + boss_emerald_dragonAI::KilledUnit(pVictim); + } + + // Corruption of Earth at 75%, 50% and 25% + bool DoSpecialDragonAbility() + { + if (DoCastSpellIfCan(m_creature, SPELL_CORRUPTION_OF_EARTH) == CAST_OK) + { + DoScriptText(SAY_CAST_CORRUPTION, m_creature); + + // Successfull cast + return true; + } + + return false; + } + + bool UpdateDragonAI(const uint32 uiDiff) + { + // Volatile Infection Timer + if (m_uiVolatileInfectionTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + if (pTarget && DoCastSpellIfCan(pTarget, SPELL_VOLATILE_INFECTION) == CAST_OK) + m_uiVolatileInfectionTimer = urand(7000, 12000); + } + else + m_uiVolatileInfectionTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_emeriss(Creature* pCreature) +{ + return new boss_emerissAI(pCreature); +} + +/*###### +## boss_lethon +######*/ + +enum +{ + SAY_LETHON_AGGRO = -1000666, + SAY_DRAW_SPIRIT = -1000667, + + SPELL_SHADOW_BOLT_WIRL = 24834, // Periodic aura + SPELL_DRAW_SPIRIT = 24811, + SPELL_SUMMON_SPIRIT_SHADE = 24810, // Summon spell was removed, was SPELL_EFFECT_SUMMON_DEMON + + NPC_LETHON = 14888, + NPC_SPIRIT_SHADE = 15261, // Add summoned by Lethon + SPELL_DARK_OFFERING = 24804, + SPELL_SPIRIT_SHAPE_VISUAL = 24809, +}; + +struct MANGOS_DLL_DECL boss_lethonAI : public boss_emerald_dragonAI +{ + boss_lethonAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) {} + + 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 + DoCastSpellIfCan(m_creature, SPELL_SHADOW_BOLT_WIRL, CAST_TRIGGERED); + } + + // Summon a spirit which moves toward the boss and heals him for each player hit by the spell; used at 75%, 50% and 25% + bool DoSpecialDragonAbility() + { + if (DoCastSpellIfCan(m_creature, SPELL_DRAW_SPIRIT) == CAST_OK) + { + DoScriptText(SAY_DRAW_SPIRIT, m_creature); + return true; + } + + return false; + } + + // Need this code here, as SPELL_DRAW_SPIRIT has no Script- or Dummyeffect + 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) + { + // Summon this way, to be able to cast the shade visual spell with player as original caster + // This might not be supported currently by core, but this spell's visual should be dependend on the player + // Also possible that this was no problem due to the special way these NPCs had been summoned in classic times + if (Creature* pSummoned = pTarget->SummonCreature(NPC_SPIRIT_SHADE, 0.0f, 0.0f, 0.0f, pTarget->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0)) + pSummoned->CastSpell(pSummoned, SPELL_SPIRIT_SHAPE_VISUAL, true, NULL, NULL, pTarget->GetObjectGuid()); + } + } + + void JustSummoned(Creature* pSummoned) override + { + // Move the shade to lethon + if (pSummoned->GetEntry() == NPC_SPIRIT_SHADE) + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0.0f, 0.0f); + else + boss_emerald_dragonAI::JustSummoned(pSummoned); + } +}; + +struct MANGOS_DLL_DECL npc_spirit_shadeAI : public ScriptedAI +{ + npc_spirit_shadeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bHasHealed; + + void Reset() override + { + m_bHasHealed = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasHealed && pWho->GetEntry() == NPC_LETHON && pWho->IsWithinDistInMap(m_creature, 3.0f)) + { + if (DoCastSpellIfCan(pWho, SPELL_DARK_OFFERING) == CAST_OK) + { + m_bHasHealed = true; + m_creature->ForcedDespawn(1000); + } + } + } + + void AttackStart(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_boss_lethon(Creature* pCreature) +{ + return new boss_lethonAI(pCreature); +} + +CreatureAI* GetAI_npc_spirit_shade(Creature* pCreature) +{ + return new npc_spirit_shadeAI(pCreature); +} + +/*###### +## boss_taerar +######*/ + +enum +{ + SAY_TAERAR_AGGRO = -1000399, + SAY_SUMMONSHADE = -1000400, + + SPELL_ARCANE_BLAST = 24857, + SPELL_BELLOWING_ROAR = 22686, + + SPELL_SUMMON_SHADE_1 = 24841, + SPELL_SUMMON_SHADE_2 = 24842, + SPELL_SUMMON_SHADE_3 = 24843, + SPELL_SELF_STUN = 24883, // Stunns the main boss until the shades are dead or timer expires + + NPC_SHADE_OF_TAERAR = 15302, + SPELL_POSIONCLOUD = 24840, + SPELL_POSIONBREATH = 20667 +}; + +struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI +{ + boss_taerarAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) { Reset(); } + + uint32 m_uiArcaneBlastTimer; + uint32 m_uiBellowingRoarTimer; + uint32 m_uiShadesTimeoutTimer; + uint8 m_uiShadesDead; + + void Reset() override + { + boss_emerald_dragonAI::Reset(); + + m_uiArcaneBlastTimer = 12000; + m_uiBellowingRoarTimer = 30000; + m_uiShadesTimeoutTimer = 0; // The time that Taerar is banished + m_uiShadesDead = 0; + + // Remove Unselectable if needed + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_TAERAR_AGGRO, m_creature); + } + + // Summon 3 Shades at 75%, 50% and 25% and Banish Self + bool DoSpecialDragonAbility() + { + if (DoCastSpellIfCan(m_creature, SPELL_SELF_STUN) == CAST_OK) + { + // Summon the shades at boss position + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SHADE_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SHADE_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SHADE_3, CAST_TRIGGERED); + + // Make boss not selectable when banished + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoScriptText(SAY_SUMMONSHADE, m_creature); + m_uiShadesTimeoutTimer = 60000; + + return true; + } + + return false; + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SHADE_OF_TAERAR) + { + ++m_uiShadesDead; + + // If all shades are dead then unbanish the boss + if (m_uiShadesDead == 3) + DoUnbanishBoss(); + } + } + + void DoUnbanishBoss() + { + m_creature->RemoveAurasDueToSpell(SPELL_SELF_STUN); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_uiShadesTimeoutTimer = 0; + m_uiShadesDead = 0; + } + + bool UpdateDragonAI(const uint32 uiDiff) + { + // Timer to unbanish the boss + if (m_uiShadesTimeoutTimer) + { + if (m_uiShadesTimeoutTimer <= uiDiff) + DoUnbanishBoss(); + else + m_uiShadesTimeoutTimer -= uiDiff; + + // Prevent further spells or timer handling while banished + return false; + } + + // Arcane Blast Timer + if (m_uiArcaneBlastTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + if (pTarget && DoCastSpellIfCan(pTarget, SPELL_ARCANE_BLAST) == CAST_OK) + m_uiArcaneBlastTimer = urand(7000, 12000); + } + else + m_uiArcaneBlastTimer -= uiDiff; + + // Bellowing Roar Timer + if (m_uiBellowingRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BELLOWING_ROAR) == CAST_OK) + m_uiBellowingRoarTimer = urand(20000, 30000); + } + else + m_uiBellowingRoarTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_taerar(Creature* pCreature) +{ + return new boss_taerarAI(pCreature); +} + +/*###### +## boss_ysondre +######*/ + +enum +{ + SAY_YSONDRE_AGGRO = -1000360, + SAY_SUMMON_DRUIDS = -1000361, + + SPELL_LIGHTNING_WAVE = 24819, + SPELL_SUMMON_DRUIDS = 24795, + + // druid spells + SPELL_MOONFIRE = 21669 +}; + +// Ysondre script +struct MANGOS_DLL_DECL boss_ysondreAI : public boss_emerald_dragonAI +{ + boss_ysondreAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) { Reset(); } + + uint32 m_uiLightningWaveTimer; + + void Reset() override + { + boss_emerald_dragonAI::Reset(); + + m_uiLightningWaveTimer = 12000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_YSONDRE_AGGRO, m_creature); + } + + // Summon Druids - TODO FIXME (spell not understood) + bool DoSpecialDragonAbility() + { + DoScriptText(SAY_SUMMON_DRUIDS, m_creature); + + for (int i = 0; i < 10; ++i) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DRUIDS, CAST_TRIGGERED); + + return true; + } + + bool UpdateDragonAI(const uint32 uiDiff) + { + // Lightning Wave Timer + if (m_uiLightningWaveTimer < uiDiff) + { + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + if (pTarget && DoCastSpellIfCan(pTarget, SPELL_LIGHTNING_WAVE) == CAST_OK) + m_uiLightningWaveTimer = urand(7000, 12000); + } + else + m_uiLightningWaveTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_ysondre(Creature* pCreature) +{ + return new boss_ysondreAI(pCreature); +} + +void AddSC_bosses_emerald_dragons() +{ + AutoScript s; + + s.newScript("boss_emeriss"); + s->GetAI = &GetAI_boss_emeriss; + + s.newScript("boss_lethon"); + s->GetAI = &GetAI_boss_lethon; + + s.newScript("npc_spirit_shade"); + s->GetAI = &GetAI_npc_spirit_shade; + + s.newScript("boss_taerar"); + s->GetAI = &GetAI_boss_taerar; + + s.newScript("boss_ysondre"); + s->GetAI = &GetAI_boss_ysondre; + +} diff --git a/scripts/world/go_scripts.cpp b/scripts/world/go_scripts.cpp index e67af1f058..d6f868dc31 100644 --- a/scripts/world/go_scripts.cpp +++ b/scripts/world/go_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -17,102 +17,24 @@ /* ScriptData SDName: GO_Scripts SD%Complete: 100 -SDComment: Quest support: 4285,4287,4288(crystal pylons), 4296, 5088, 5097, 5098, 6481, 10990, 10991, 10992, 14092/14076. Field_Repair_Bot->Teaches spell 22704. 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_northern_crystal_pylon -go_eastern_crystal_pylon -go_western_crystal_pylon go_barov_journal go_ethereum_prison go_ethereum_stasis -go_field_repair_bot_74A go_mysterious_snow_mound -go_orb_of_command -go_resonite_cask -go_sacred_fire_of_life -go_shrine_of_the_birds -go_tablet_of_madness -go_tablet_of_the_seven go_tele_to_dalaran_crystal go_tele_to_violet_stand go_andorhal_tower go_scourge_enclosure +go_lab_work_reagents EndContentData */ #include "precompiled.h" -/*###### -## go_cat_figurine -######*/ - -enum -{ - SPELL_SUMMON_GHOST_SABER = 5968, -}; - -bool GOHello_go_cat_figurine(Player* pPlayer, GameObject* pGo) -{ - pPlayer->CastSpell(pPlayer, SPELL_SUMMON_GHOST_SABER, true); - return false; -} - -/*###### -## go_crystal_pylons (3x) -######*/ - -enum -{ - QUEST_THE_NORTHERN_PYLON = 4285, - QUEST_THE_EASTERN_PYLON = 4287, - QUEST_THE_WESTERN_PYLON = 4288 -}; - -bool GOHello_go_northern_crystal_pylon(Player* pPlayer, GameObject* pGo) -{ - if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - pPlayer->PrepareQuestMenu(pGo->GetGUID()); - pPlayer->SendPreparedQuest(pGo->GetGUID()); - } - - if (pPlayer->GetQuestStatus(QUEST_THE_NORTHERN_PYLON) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(QUEST_THE_NORTHERN_PYLON); - - return true; -} - -bool GOHello_go_eastern_crystal_pylon(Player* pPlayer, GameObject* pGo) -{ - if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - pPlayer->PrepareQuestMenu(pGo->GetGUID()); - pPlayer->SendPreparedQuest(pGo->GetGUID()); - } - - if (pPlayer->GetQuestStatus(QUEST_THE_EASTERN_PYLON) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(QUEST_THE_EASTERN_PYLON); - - return true; -} - -bool GOHello_go_western_crystal_pylon(Player* pPlayer, GameObject* pGo) -{ - if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) - { - pPlayer->PrepareQuestMenu(pGo->GetGUID()); - pPlayer->SendPreparedQuest(pGo->GetGUID()); - } - - if (pPlayer->GetQuestStatus(QUEST_THE_WESTERN_PYLON) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(QUEST_THE_WESTERN_PYLON); - - return true; -} - /*###### ## go_barov_journal ######*/ @@ -123,7 +45,7 @@ enum SPELL_LEARN_FELCLOTH_BAG = 26095 }; -bool GOHello_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)) { @@ -155,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 GOHello_go_ethereum_prison(Player* pPlayer, GameObject* pGo) +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)) { @@ -173,7 +95,7 @@ bool GOHello_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; @@ -184,9 +106,9 @@ bool GOHello_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()); } } } @@ -203,55 +125,17 @@ const uint32 uiNpcStasisEntry[] = 22825, 20888, 22827, 22826, 22828 }; -bool GOHello_go_ethereum_stasis(Player* pPlayer, GameObject* pGo) +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_field_repair_bot_74A -######*/ - -enum -{ - SPELL_ENGINEER_FIELD_REPAIR_BOT_74A = 22704, - SPELL_LEARN_FIELD_REPAIR_BOT_74A = 22864 -}; - -bool GOHello_go_field_repair_bot_74A(Player* pPlayer, GameObject* pGo) -{ - if (pPlayer->HasSkill(SKILL_ENGINEERING) && pPlayer->GetBaseSkillValue(SKILL_ENGINEERING) >= 300 && !pPlayer->HasSpell(SPELL_ENGINEER_FIELD_REPAIR_BOT_74A)) - pPlayer->CastSpell(pPlayer, SPELL_LEARN_FIELD_REPAIR_BOT_74A, false); - - return true; -} - -/*###### -## go_gilded_brazier -######*/ - -enum -{ - NPC_STILLBLADE = 17716, -}; - -bool GOHello_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 ######*/ @@ -262,7 +146,7 @@ enum NPC_JUMP_A_TRON = 19041 }; -bool GOHello_go_jump_a_tron(Player* pPlayer, GameObject* pGo) +bool GOUse_go_jump_a_tron(Player* pPlayer, GameObject* pGo) { if (Creature* pCreature = GetClosestCreatureWithEntry(pGo, NPC_JUMP_A_TRON, INTERACTION_DISTANCE)) pCreature->CastSpell(pPlayer, SPELL_JUMP_A_TRON, false); @@ -281,9 +165,9 @@ enum SPELL_SUMMON_MARAUDER = 66491, }; -bool GOHello_go_mysterious_snow_mound(Player* pPlayer, GameObject* pGo) +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); } @@ -300,132 +184,6 @@ bool GOHello_go_mysterious_snow_mound(Player* pPlayer, GameObject* pGo) return true; } -/*###### -## go_orb_of_command -######*/ - -enum -{ - QUEST_BLACKHANDS_COMMAND = 7761, - SPELL_TELEPORT_TO_BWL = 23460 -}; - -bool GOHello_go_orb_of_command(Player* pPlayer, GameObject* pGo) -{ - if (pPlayer->GetQuestRewardStatus(QUEST_BLACKHANDS_COMMAND)) - pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_TO_BWL, true); - - return true; -} - -/*###### -## go_resonite_cask -######*/ - -enum -{ - NPC_GOGGEROC = 11920 -}; - -bool GOHello_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 GOHello_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 GOHello_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_tablet_of_madness -######*/ - -enum -{ - SPELL_ALCHEMY_GURUBASHI_MOJO_MADNESS = 24266, - SPELL_LEARN_GURUBASHI_MOJO_MADNESS = 24267 -}; - -bool GOHello_go_tablet_of_madness(Player* pPlayer, GameObject* pGo) -{ - if (pPlayer->HasSkill(SKILL_ALCHEMY) && pPlayer->GetSkillValue(SKILL_ALCHEMY) >= 300 && !pPlayer->HasSpell(SPELL_ALCHEMY_GURUBASHI_MOJO_MADNESS)) - pPlayer->CastSpell(pPlayer, SPELL_LEARN_GURUBASHI_MOJO_MADNESS, false); - - return true; -} - -/*###### -## go_tablet_of_the_seven - OBSOLETE -######*/ - -//TODO: use gossip option ("Transcript the Tablet") instead, if Mangos adds support. -bool GOHello_go_tablet_of_the_seven(Player* pPlayer, GameObject* pGo) -{ - if (pGo->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) - return true; - - if (pPlayer->GetQuestStatus(4296) == QUEST_STATUS_INCOMPLETE) - pPlayer->CastSpell(pPlayer, 15065, false); - - return true; -} - /*###### ## go_tele_to_dalaran_crystal ######*/ @@ -436,12 +194,12 @@ enum QUEST_TELE_CRYSTAL_FLAG = 12845 }; -bool GOHello_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; } @@ -449,7 +207,7 @@ bool GOHello_go_tele_to_dalaran_crystal(Player* pPlayer, GameObject* pGo) ## go_tele_to_violet_stand ######*/ -bool GOHello_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; @@ -457,24 +215,6 @@ bool GOHello_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 GOHello_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 ######*/ @@ -493,12 +233,12 @@ enum GO_ANDORHAL_TOWER_4 = 176097 }; -bool GOHello_go_andorhal_tower(Player* pPlayer, GameObject* pGo) +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; @@ -519,135 +259,93 @@ enum { SPELL_GYMER_LOCK_EXPLOSION = 55529, NPC_GYMER_LOCK_DUMMY = 29928 - }; -bool GOHello_go_scourge_enclosure(Player* pPlayer, GameObject* pGo) +bool GOUse_go_scourge_enclosure(Player* pPlayer, GameObject* pGo) { std::list m_lResearchersList; 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); return true; } +/*###### +## go_lab_work_reagents +######*/ + +enum +{ + QUEST_LAB_WORK = 12557, + + SPELL_WIRHERED_BATWING_KILL_CREDIT = 51226, + SPELL_MUDDY_MIRE_MAGGOT_KILL_CREDIT = 51227, + SPELL_AMBERSEED_KILL_CREDIT = 51228, + SPELL_CHILLED_SERPENT_MUCUS_KILL_CREDIT = 51229, + + GO_AMBERSEED = 190459, + GO_CHILLED_SERPENT_MUCUS = 190462, + GO_WITHERED_BATWING = 190473, + GO_MUDDY_MIRE_MAGGOTS = 190478, +}; + +bool GOUse_go_lab_work_reagents(Player* pPlayer, GameObject* pGo) +{ + if (pPlayer->GetQuestStatus(QUEST_LAB_WORK) == QUEST_STATUS_INCOMPLETE) + { + uint32 uiCreditSpellId = 0; + switch (pGo->GetEntry()) + { + case GO_AMBERSEED: uiCreditSpellId = SPELL_AMBERSEED_KILL_CREDIT; break; + case GO_CHILLED_SERPENT_MUCUS: uiCreditSpellId = SPELL_CHILLED_SERPENT_MUCUS_KILL_CREDIT; break; + case GO_WITHERED_BATWING: uiCreditSpellId = SPELL_WIRHERED_BATWING_KILL_CREDIT; break; + case GO_MUDDY_MIRE_MAGGOTS: uiCreditSpellId = SPELL_MUDDY_MIRE_MAGGOT_KILL_CREDIT; break; + } + + if (uiCreditSpellId) + pPlayer->CastSpell(pPlayer, uiCreditSpellId, true); + } + + return false; +} + void AddSC_go_scripts() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "go_cat_figurine"; - pNewScript->pGOHello = &GOHello_go_cat_figurine; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_northern_crystal_pylon"; - pNewScript->pGOHello = &GOHello_go_northern_crystal_pylon; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_eastern_crystal_pylon"; - pNewScript->pGOHello = &GOHello_go_eastern_crystal_pylon; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_western_crystal_pylon"; - pNewScript->pGOHello = &GOHello_go_western_crystal_pylon; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_barov_journal"; - pNewScript->pGOHello = &GOHello_go_barov_journal; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_ethereum_prison"; - pNewScript->pGOHello = &GOHello_go_ethereum_prison; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_ethereum_stasis"; - pNewScript->pGOHello = &GOHello_go_ethereum_stasis; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_field_repair_bot_74A"; - pNewScript->pGOHello = &GOHello_go_field_repair_bot_74A; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_gilded_brazier"; - pNewScript->pGOHello = &GOHello_go_gilded_brazier; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_jump_a_tron"; - pNewScript->pGOHello = &GOHello_go_jump_a_tron; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_mysterious_snow_mound"; - pNewScript->pGOHello = &GOHello_go_mysterious_snow_mound; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_orb_of_command"; - pNewScript->pGOHello = &GOHello_go_orb_of_command; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_resonite_cask"; - pNewScript->pGOHello = &GOHello_go_resonite_cask; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_sacred_fire_of_life"; - pNewScript->pGOHello = &GOHello_go_sacred_fire_of_life; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_shrine_of_the_birds"; - pNewScript->pGOHello = &GOHello_go_shrine_of_the_birds; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_tablet_of_madness"; - pNewScript->pGOHello = &GOHello_go_tablet_of_madness; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_tablet_of_the_seven"; - pNewScript->pGOHello = &GOHello_go_tablet_of_the_seven; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_tele_to_dalaran_crystal"; - pNewScript->pGOHello = &GOHello_go_tele_to_dalaran_crystal; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_tele_to_violet_stand"; - pNewScript->pGOHello = &GOHello_go_tele_to_violet_stand; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_blood_filled_orb"; - pNewScript->pGOHello = &GOHello_go_blood_filled_orb; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_andorhal_tower"; - pNewScript->pGOHello = &GOHello_go_andorhal_tower; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_scourge_enclosure"; - pNewScript->pGOHello = &GOHello_go_scourge_enclosure; - pNewScript->RegisterSelf(); + AutoScript s; + + s.newScript("go_barov_journal"); + s->pGOUse = &GOUse_go_barov_journal; + + s.newScript("go_ethereum_prison"); + s->pGOUse = &GOUse_go_ethereum_prison; + + s.newScript("go_ethereum_stasis"); + s->pGOUse = &GOUse_go_ethereum_stasis; + + s.newScript("go_jump_a_tron"); + s->pGOUse = &GOUse_go_jump_a_tron; + + s.newScript("go_mysterious_snow_mound"); + s->pGOUse = &GOUse_go_mysterious_snow_mound; + + s.newScript("go_tele_to_dalaran_crystal"); + s->pGOUse = &GOUse_go_tele_to_dalaran_crystal; + + s.newScript("go_tele_to_violet_stand"); + s->pGOUse = &GOUse_go_tele_to_violet_stand; + + s.newScript("go_andorhal_tower"); + s->pGOUse = &GOUse_go_andorhal_tower; + + s.newScript("go_scourge_enclosure"); + s->pGOUse = &GOUse_go_scourge_enclosure; + + s.newScript("go_lab_work_reagents"); + s->pGOUse = &GOUse_go_lab_work_reagents; } diff --git a/scripts/world/guards.cpp b/scripts/world/guards.cpp index e788be4e18..30964f6166 100644 --- a/scripts/world/guards.cpp +++ b/scripts/world/guards.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -122,18 +122,18 @@ struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI uint32 m_uiExile_Timer; uint32 m_uiBanish_Timer; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; bool m_bCanTeleport; - void Reset() + void Reset() override { m_uiBanish_Timer = 5000; m_uiExile_Timer = 8500; - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_bCanTeleport = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -142,13 +142,13 @@ struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI { if (m_uiExile_Timer < uiDiff) { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_playerGuid)) { pTarget->CastSpell(pTarget, SPELL_EXILE, true); pTarget->CastSpell(pTarget, SPELL_BANISH_TELEPORT, true); } - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_uiExile_Timer = 8500; m_bCanTeleport = false; } @@ -163,10 +163,8 @@ struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI { DoCastSpellIfCan(pVictim, SPELL_BANISHED_SHATTRATH_A); m_uiBanish_Timer = 9000; - m_uiPlayerGUID = pVictim->GetGUID(); - - if (m_uiPlayerGUID) - m_bCanTeleport = true; + m_playerGuid = pVictim->GetObjectGuid(); + m_bCanTeleport = true; } } else @@ -191,18 +189,18 @@ struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI uint32 m_uiExile_Timer; uint32 m_uiBanish_Timer; - uint64 m_uiPlayerGUID; + ObjectGuid m_playerGuid; bool m_bCanTeleport; - void Reset() + void Reset() override { m_uiBanish_Timer = 5000; m_uiExile_Timer = 8500; - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_bCanTeleport = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -211,13 +209,13 @@ struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI { if (m_uiExile_Timer < uiDiff) { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_uiPlayerGUID)) + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_playerGuid)) { pTarget->CastSpell(pTarget, SPELL_EXILE, true); pTarget->CastSpell(pTarget, SPELL_BANISH_TELEPORT, true); } - m_uiPlayerGUID = 0; + m_playerGuid.Clear(); m_uiExile_Timer = 8500; m_bCanTeleport = false; } @@ -232,10 +230,8 @@ struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI { DoCastSpellIfCan(pVictim, SPELL_BANISHED_SHATTRATH_S); m_uiBanish_Timer = 9000; - m_uiPlayerGUID = pVictim->GetGUID(); - - if (m_uiPlayerGUID) - m_bCanTeleport = true; + m_playerGuid = pVictim->GetObjectGuid(); + m_bCanTeleport = true; } } else @@ -277,105 +273,65 @@ CreatureAI* GetAI_guard_undercity(Creature* pCreature) void AddSC_guards() { - Script *newscript; - - newscript = new Script; - newscript->Name = "guard_azuremyst"; - newscript->GetAI = &GetAI_guard_azuremyst; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_bluffwatcher"; - newscript->GetAI = &GetAI_guard_bluffwatcher; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_contested"; - newscript->GetAI = &GetAI_guard_contested; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_darnassus"; - newscript->GetAI = &GetAI_guard_darnassus; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_dunmorogh"; - newscript->GetAI = &GetAI_guard_dunmorogh; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_durotar"; - newscript->GetAI = &GetAI_guard_durotar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_elwynnforest"; - newscript->GetAI = &GetAI_guard_elwynnforest; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_eversong"; - newscript->GetAI = &GetAI_guard_eversong; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_exodar"; - newscript->GetAI = &GetAI_guard_exodar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_ironforge"; - newscript->GetAI = &GetAI_guard_ironforge; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_mulgore"; - newscript->GetAI = &GetAI_guard_mulgore; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_orgrimmar"; - newscript->GetAI = &GetAI_guard_orgrimmar; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_shattrath"; - newscript->GetAI = &GetAI_guard_shattrath; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_shattrath_aldor"; - newscript->GetAI = &GetAI_guard_shattrath_aldor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_shattrath_scryer"; - newscript->GetAI = &GetAI_guard_shattrath_scryer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_silvermoon"; - newscript->GetAI = &GetAI_guard_silvermoon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_stormwind"; - newscript->GetAI = &GetAI_guard_stormwind; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_teldrassil"; - newscript->GetAI = &GetAI_guard_teldrassil; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_tirisfal"; - newscript->GetAI = &GetAI_guard_tirisfal; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "guard_undercity"; - newscript->GetAI = &GetAI_guard_undercity; - newscript->RegisterSelf(); + AutoScript s; + + s.newScript("guard_azuremyst"); + s->GetAI = &GetAI_guard_azuremyst; + + s.newScript("guard_bluffwatcher"); + s->GetAI = &GetAI_guard_bluffwatcher; + + s.newScript("guard_contested"); + s->GetAI = &GetAI_guard_contested; + + s.newScript("guard_darnassus"); + s->GetAI = &GetAI_guard_darnassus; + + s.newScript("guard_dunmorogh"); + s->GetAI = &GetAI_guard_dunmorogh; + + s.newScript("guard_durotar"); + s->GetAI = &GetAI_guard_durotar; + + s.newScript("guard_elwynnforest"); + s->GetAI = &GetAI_guard_elwynnforest; + + s.newScript("guard_eversong"); + s->GetAI = &GetAI_guard_eversong; + + s.newScript("guard_exodar"); + s->GetAI = &GetAI_guard_exodar; + + s.newScript("guard_ironforge"); + s->GetAI = &GetAI_guard_ironforge; + + s.newScript("guard_mulgore"); + s->GetAI = &GetAI_guard_mulgore; + + s.newScript("guard_orgrimmar"); + s->GetAI = &GetAI_guard_orgrimmar; + + s.newScript("guard_shattrath"); + s->GetAI = &GetAI_guard_shattrath; + + s.newScript("guard_shattrath_aldor"); + s->GetAI = &GetAI_guard_shattrath_aldor; + + s.newScript("guard_shattrath_scryer"); + s->GetAI = &GetAI_guard_shattrath_scryer; + + s.newScript("guard_silvermoon"); + s->GetAI = &GetAI_guard_silvermoon; + + s.newScript("guard_stormwind"); + s->GetAI = &GetAI_guard_stormwind; + + s.newScript("guard_teldrassil"); + s->GetAI = &GetAI_guard_teldrassil; + + s.newScript("guard_tirisfal"); + s->GetAI = &GetAI_guard_tirisfal; + + s.newScript("guard_undercity"); + s->GetAI = &GetAI_guard_undercity; } diff --git a/scripts/world/item_scripts.cpp b/scripts/world/item_scripts.cpp index 277d80cf3d..d4aeeb23a4 100644 --- a/scripts/world/item_scripts.cpp +++ b/scripts/world/item_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -25,6 +25,7 @@ EndScriptData */ item_arcane_charges Prevent use if player is not flying (cannot cast while on ground) item_flying_machine(i34060,i34061) Engineering crafted flying machines item_gor_dreks_ointment(i30175) Protecting Our Own(q10488) +Item_jungle_punch_offer EndContentData */ #include "precompiled.h" @@ -39,7 +40,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 +57,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 +69,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 +84,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 +110,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; @@ -127,27 +128,46 @@ bool ItemUse_item_petrov_cluster_bombs(Player* pPlayer, Item* pItem, const Spell return false; } +/*#### +# jungle_punch_ +####*/ + +enum +{ + SPELL_OFFER_JUNGLE_PUNCH = 51962 +}; + +bool ItemUse_item_jungle_punch_sample(Player* pPlayer, Item* pItem, const SpellCastTargets &pTargets) +{ + Unit* pTarget = pPlayer->GetMap()->GetUnit(pPlayer->GetTargetGuid()); + if (pTarget && pTarget->GetTypeId() == TYPEID_UNIT) + { + pPlayer->CastSpell(pTarget, SPELL_OFFER_JUNGLE_PUNCH, false); + return true; + } + else + { + pPlayer->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + return true; + } +} + void AddSC_item_scripts() { - Script *newscript; - - newscript = new Script; - newscript->Name = "item_arcane_charges"; - newscript->pItemUse = &ItemUse_item_arcane_charges; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "item_flying_machine"; - newscript->pItemUse = &ItemUse_item_flying_machine; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "item_gor_dreks_ointment"; - newscript->pItemUse = &ItemUse_item_gor_dreks_ointment; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "item_petrov_cluster_bombs"; - newscript->pItemUse = &ItemUse_item_petrov_cluster_bombs; - newscript->RegisterSelf(); + AutoScript s; + + s.newScript("item_arcane_charges"); + s->pItemUse = &ItemUse_item_arcane_charges; + + s.newScript("item_flying_machine"); + s->pItemUse = &ItemUse_item_flying_machine; + + s.newScript("item_gor_dreks_ointment"); + s->pItemUse = &ItemUse_item_gor_dreks_ointment; + + s.newScript("item_petrov_cluster_bombs"); + s->pItemUse = &ItemUse_item_petrov_cluster_bombs; + + s.newScript("item_jungle_punch_sample"); + s->pItemUse = &ItemUse_item_jungle_punch_sample; } diff --git a/scripts/world/mob_generic_creature.cpp b/scripts/world/mob_generic_creature.cpp index 531e36ecc9..98c326add1 100644 --- a/scripts/world/mob_generic_creature.cpp +++ b/scripts/world/mob_generic_creature.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -29,82 +29,89 @@ struct MANGOS_DLL_DECL 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->IsWithinDistInMap(who, ATTACK_DISTANCE)) - { - 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; - //If we are within range melee the target - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) + // Return if we already cast a spell + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) { - //Make sure our attack is ready and we arn't currently casting - if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) + // 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()); @@ -114,44 +121,38 @@ struct MANGOS_DLL_DECL generic_creatureAI : public ScriptedAI } else { - //Only run this code if we arn't already casting - if (!m_creature->IsNonMeleeSpellCasted(false)) - { - bool Healing = false; - SpellEntry const *info = NULL; + bool Healing = false; + SpellEntry const* info = NULL; - //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); + // 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) - if (info) Healing = true; - else info = SelectSpell(m_creature->getVictim(), -1, -1, SELECT_TARGET_ANY_ENEMY, 0, 0, ATTACK_DISTANCE, 0, SELECT_EFFECT_DONTCARE); + // 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 - if (info && !GlobalCooldown) + // 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 (!IsSelfRooted) { - //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); - - //Set our global cooldown - GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + IsSelfRooted = true; + } + // Cast spell + if (Healing) DoCastSpell(m_creature, info); + else DoCastSpell(m_creature->getVictim(), info); - }//If no spells available and we arn't moving run to target - else if (IsSelfRooted) - { - //Cancel our current spell and then allow movement agian - m_creature->InterruptNonMeleeSpells(false); - IsSelfRooted = false; - } + // Set our global cooldown + GlobalCooldown = GENERIC_CREATURE_COOLDOWN; + }// If no spells available and we arn't moving run to target + else if (IsSelfRooted) + { + // Cancel our current spell and then allow movement agian + m_creature->InterruptNonMeleeSpells(false); + IsSelfRooted = false; } } } @@ -164,9 +165,5 @@ CreatureAI* GetAI_generic_creature(Creature* pCreature) void AddSC_generic_creature() { - Script *newscript; - newscript = new Script; - newscript->Name = "generic_creature"; - newscript->GetAI = &GetAI_generic_creature; - newscript->RegisterSelf(false); + AutoScript("generic_creature", false)->GetAI = &GetAI_generic_creature; } diff --git a/scripts/world/npc_professions.cpp b/scripts/world/npc_professions.cpp index 305005a78e..47d57e3847 100644 --- a/scripts/world/npc_professions.cpp +++ b/scripts/world/npc_professions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -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,27 @@ 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]; + SpellEffectEntry const* pSpellEffect = spell->GetSpellEffect(SpellEffectIndex(i)); + if (!pSpellEffect) + return false; + + uint32 reqSpell = pSpellEffect->EffectTriggerSpell;; 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 +203,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->GetGUID()); - 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->GetGUID()); - return true; -} - -void SendActionMenu_npc_prof_alchemy(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; - case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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 ###*/ @@ -540,55 +305,55 @@ bool HasWeaponSub(Player* pPlayer) bool GossipHello_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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(); - //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)) @@ -597,26 +362,26 @@ bool GossipHello_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature) } } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); + pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetGUID()); + 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 +389,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) - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // 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 +409,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 +428,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 +449,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,22 +506,22 @@ 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) - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // 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) - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // 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) - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + // unknown textID (TALK_SWORD_LEARN) + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; } } @@ -758,31 +532,31 @@ 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) - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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 +564,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,147 +576,15 @@ 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; }*/ -/*### -# engineering trinkets -###*/ - -enum -{ - NPC_ZAP = 14742, - NPC_JHORDY = 14743, - NPC_KABLAM = 21493, - NPC_SMILES = 21494, - - SPELL_LEARN_TO_EVERLOOK = 23490, - SPELL_LEARN_TO_GADGET = 23491, - SPELL_LEARN_TO_AREA52 = 36956, - SPELL_LEARN_TO_TOSHLEY = 36957, - - SPELL_TO_EVERLOOK = 23486, - SPELL_TO_GADGET = 23489, - SPELL_TO_AREA52 = 36954, - SPELL_TO_TOSHLEY = 36955, - - ITEM_GNOMISH_CARD = 10790, - ITEM_GOBLIN_CARD = 10791 -}; - -#define GOSSIP_ITEM_ZAP "[PH] Unknown" -#define GOSSIP_ITEM_JHORDY "I must build a beacon for this marvelous device!" -#define GOSSIP_ITEM_KABLAM "[PH] Unknown" -#define GOSSIP_ITEM_SMILES "[PH] Unknown" - -bool GossipHello_npc_engineering_tele_trinket(Player* pPlayer, Creature* pCreature) -{ - uint32 uiNpcTextId = 0; - std::string strGossipItem; - bool bCanLearn = false; - - if (pPlayer->HasSkill(SKILL_ENGINEERING)) - { - switch(pCreature->GetEntry()) - { - case NPC_ZAP: - uiNpcTextId = 7249; - if (pPlayer->GetBaseSkillValue(SKILL_ENGINEERING) >= 260 && pPlayer->HasSpell(S_GOBLIN)) - { - if (!pPlayer->HasSpell(SPELL_TO_EVERLOOK)) - { - bCanLearn = true; - strGossipItem = GOSSIP_ITEM_ZAP; - } - else if (pPlayer->HasSpell(SPELL_TO_EVERLOOK)) - uiNpcTextId = 0; - } - break; - case NPC_JHORDY: - uiNpcTextId = 7251; - if (pPlayer->GetBaseSkillValue(SKILL_ENGINEERING) >= 260 && pPlayer->HasSpell(S_GNOMISH)) - { - if (!pPlayer->HasSpell(SPELL_TO_GADGET)) - { - bCanLearn = true; - strGossipItem = GOSSIP_ITEM_JHORDY; - } - else if (pPlayer->HasSpell(SPELL_TO_GADGET)) - uiNpcTextId = 7252; - } - break; - case NPC_KABLAM: - uiNpcTextId = 10365; - if (pPlayer->GetBaseSkillValue(SKILL_ENGINEERING) >= 350 && pPlayer->HasSpell(S_GOBLIN)) - { - if (!pPlayer->HasSpell(SPELL_TO_AREA52)) - { - bCanLearn = true; - strGossipItem = GOSSIP_ITEM_KABLAM; - } - else if (pPlayer->HasSpell(SPELL_TO_AREA52)) - uiNpcTextId = 0; - } - break; - case NPC_SMILES: - uiNpcTextId = 10363; - if (pPlayer->GetBaseSkillValue(SKILL_ENGINEERING) >= 350 && pPlayer->HasSpell(S_GNOMISH)) - { - if (!pPlayer->HasSpell(SPELL_TO_TOSHLEY)) - { - bCanLearn = true; - strGossipItem = GOSSIP_ITEM_SMILES; - } - else if (pPlayer->HasSpell(SPELL_TO_TOSHLEY)) - uiNpcTextId = 0; - } - break; - } - } - - if (bCanLearn) - { - if (pPlayer->HasItemCount(ITEM_GOBLIN_CARD,1) || pPlayer->HasItemCount(ITEM_GNOMISH_CARD,1)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, strGossipItem, pCreature->GetEntry(), GOSSIP_ACTION_INFO_DEF+1); - } - - pPlayer->SEND_GOSSIP_MENU(uiNpcTextId ? uiNpcTextId : pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_engineering_tele_trinket(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - pPlayer->CLOSE_GOSSIP_MENU(); - - if (uiSender != pCreature->GetEntry()) - return true; - - switch(uiSender) - { - case NPC_ZAP: - pPlayer->CastSpell(pPlayer,SPELL_LEARN_TO_EVERLOOK,false); - break; - case NPC_JHORDY: - pPlayer->CastSpell(pPlayer,SPELL_LEARN_TO_GADGET,false); - break; - case NPC_KABLAM: - pPlayer->CastSpell(pPlayer,SPELL_LEARN_TO_AREA52,false); - break; - case NPC_SMILES: - pPlayer->CastSpell(pPlayer,SPELL_LEARN_TO_TOSHLEY,false); - break; - } - - return true; -} - /*### # start menues leatherworking ###*/ @@ -950,7 +592,7 @@ bool GossipSelect_npc_engineering_tele_trinket(Player* pPlayer, Creature* pCreat bool GossipHello_npc_prof_leather(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + 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()) @@ -958,83 +600,89 @@ 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; } } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } void SendActionMenu_npc_prof_leather(Player* pPlayer, Creature* pCreature, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); + pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetGUID()); + 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; } @@ -1045,25 +693,25 @@ 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 () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - 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 () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - 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 () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + 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 () + 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 () + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; } } @@ -1071,7 +719,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; @@ -1080,217 +728,15 @@ 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->GetGUID()); - 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->GetGUID()); - return true; -} - -void SendActionMenu_npc_prof_tailor(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - break; - case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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) ###*/ -/*bool GOHello_go_soothsaying_for_dummies(Player* pPlayer, GameObject* pGo) +/*bool GOUse_go_soothsaying_for_dummies(Player* pPlayer, GameObject* pGo) { pPlayer->PlayerTalkClass->GetGossipMenu()->AddMenuItem(0,GOSSIP_LEARN_DRAGON, GOSSIP_SENDER_INFO, GOSSIP_ACTION_INFO_DEF, "", 0); - pPlayer->SEND_GOSSIP_MENU(5584, pGo->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(5584, pGo->GetObjectGuid()); return true; }*/ @@ -1301,41 +747,17 @@ bool GossipSelect_npc_prof_tailor(Player* pPlayer, Creature* pCreature, uint32 u void AddSC_npc_professions() { - Script *newscript; - - newscript = new Script; - newscript->Name = "npc_prof_alchemy"; - newscript->pGossipHello = &GossipHello_npc_prof_alchemy; - newscript->pGossipSelect = &GossipSelect_npc_prof_alchemy; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_prof_blacksmith"; - newscript->pGossipHello = &GossipHello_npc_prof_blacksmith; - newscript->pGossipSelect = &GossipSelect_npc_prof_blacksmith; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_engineering_tele_trinket"; - newscript->pGossipHello = &GossipHello_npc_engineering_tele_trinket; - newscript->pGossipSelect = &GossipSelect_npc_engineering_tele_trinket; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_prof_leather"; - newscript->pGossipHello = &GossipHello_npc_prof_leather; - newscript->pGossipSelect = &GossipSelect_npc_prof_leather; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_prof_tailor"; - newscript->pGossipHello = &GossipHello_npc_prof_tailor; - newscript->pGossipSelect = &GossipSelect_npc_prof_tailor; - newscript->RegisterSelf(); - - /*newscript = new Script; - newscript->Name = "go_soothsaying_for_dummies"; - newscript->pGOHello = &GOHello_go_soothsaying_for_dummies; - //newscript->pGossipSelect = &GossipSelect_go_soothsaying_for_dummies; - newscript->RegisterSelf();*/ + AutoScript s; + + s.newScript("npc_prof_blacksmith"); + s->pGossipHello = &GossipHello_npc_prof_blacksmith; + s->pGossipSelect = &GossipSelect_npc_prof_blacksmith; + + s.newScript("npc_prof_leather"); + s->pGossipHello = &GossipHello_npc_prof_leather; + s->pGossipSelect = &GossipSelect_npc_prof_leather; + + /*s.newScript("go_soothsaying_for_dummies"); + s->pGOUse = &GOUse_go_soothsaying_for_dummies; + // s->pGossipSelect = &GossipSelect_go_soothsaying_for_dummies;*/ } diff --git a/scripts/world/npcs_special.cpp b/scripts/world/npcs_special.cpp index 78e69c22c3..83013fa5c8 100644 --- a/scripts/world/npcs_special.cpp +++ b/scripts/world/npcs_special.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -24,6 +24,7 @@ EndScriptData #include "precompiled.h" #include "escort_ai.h" +#include "pet_ai.h" #include "ObjectMgr.h" #include "GameEventMgr.h" @@ -35,14 +36,9 @@ npc_guardian 100% guardianAI used to prevent players from accessin npc_garments_of_quests 80% NPC's related to all Garments of-quests 5621, 5624, 5625, 5648, 5650 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% Innkeepers in general. A lot do be done here (misc options for events) -npc_kingdom_of_dalaran_quests Misc NPC's gossip option related to quests 12791, 12794 and 12796 -npc_lunaclaw_spirit 100% Appears at two different locations, quest 6001/6002 -npc_mount_vendor 100% Regular mount vendors all over the world. Display gossip if player doesn't meet the requirements to buy -npc_rogue_trainer 80% Scripted trainers, so they are able to offer item 17126 for class quest 6681 -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_locksmith 75% list of keys needs to be confirmed +npc_innkeeper 25% ScriptName not assigned. Innkeepers in general. +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 */ /*######## @@ -73,33 +69,33 @@ 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 @@ -107,12 +103,9 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI npc_air_force_botsAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pSpawnAssoc = NULL; - m_uiSpawnedGUID = 0; // find the correct spawnhandling - static uint32 uiEntryCount = sizeof(m_aSpawnAssociations)/sizeof(SpawnAssociation); - - for (uint8 i=0; iGetEntry()) { @@ -137,16 +130,16 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI } SpawnAssociation* m_pSpawnAssoc; - uint64 m_uiSpawnedGUID; + 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_uiSpawnedGUID = pSummoned->GetGUID(); + m_spawnedGuid = pSummoned->GetObjectGuid(); else { error_db_log("SD2: npc_air_force_bots: wasn't able to spawn creature %u", m_pSpawnAssoc->m_uiSpawnedCreatureEntry); @@ -158,7 +151,7 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI Creature* GetSummonedGuard() { - Creature* pCreature = m_creature->GetMap()->GetCreature(m_uiSpawnedGUID); + Creature* pCreature = m_creature->GetMap()->GetCreature(m_spawnedGuid); if (pCreature && pCreature->isAlive()) return pCreature; @@ -166,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; @@ -179,13 +172,13 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI if (!pPlayerTarget) return; - Creature* pLastSpawnedGuard = m_uiSpawnedGUID == 0 ? NULL : GetSummonedGuard(); + Creature* pLastSpawnedGuard = m_spawnedGuid ? GetSummonedGuard() : NULL; // prevent calling GetCreature at next MoveInLineOfSight call - speedup if (!pLastSpawnedGuard) - m_uiSpawnedGUID = 0; + m_spawnedGuid.Clear(); - switch(m_pSpawnAssoc->m_SpawnType) + switch (m_pSpawnAssoc->m_SpawnType) { case SPAWNTYPE_ALARMBOT: { @@ -272,7 +265,7 @@ struct MANGOS_DLL_DECL npc_chicken_cluckAI : public ScriptedAI uint32 m_uiResetFlagTimer; - void Reset() + void Reset() override { m_uiResetFlagTimer = 120000; @@ -280,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) { @@ -314,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)) @@ -335,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) { @@ -346,7 +339,7 @@ bool QuestAccept_npc_chicken_cluck(Player* pPlayer, Creature* pCreature, const Q return true; } -bool QuestComplete_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) { @@ -370,9 +363,9 @@ struct MANGOS_DLL_DECL 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); @@ -385,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 @@ -420,38 +413,33 @@ enum HORDE_COORDS = 6 }; -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 @@ -465,9 +453,9 @@ 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 }; /*###### @@ -478,39 +466,39 @@ struct MANGOS_DLL_DECL npc_doctorAI : public ScriptedAI { npc_doctorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint64 Playerguid; + 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; - std::list Patients; - std::vector Coordinates; + GuidList m_lPatientGuids; + std::vector m_vPatientSummonCoordinates; - void Reset() + void Reset() override { - Playerguid = 0; + 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; }; /*##### @@ -521,74 +509,69 @@ struct MANGOS_DLL_DECL npc_injured_patientAI : public ScriptedAI { npc_injured_patientAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint64 Doctorguid; - Location* Coord; + ObjectGuid m_doctorGuid; + LOCATION* m_pCoord; - void Reset() + void Reset() override { - Doctorguid = 0; - Coord = NULL; + m_doctorGuid.Clear(); + 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 (Doctorguid) + if (Creature* pDoctor = m_creature->GetMap()->GetCreature(m_doctorGuid)) { - if (Creature* pDoctor = m_creature->GetMap()->GetCreature(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->RemoveSplineFlag(SPLINEFLAG_WALKMODE); - - uint32 mobId = m_creature->GetEntry(); + m_creature->SetWalk(false); - switch (mobId) + switch (m_creature->GetEntry()) { case 12923: case 12924: @@ -604,28 +587,26 @@ 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 - if (m_creature->isAlive() && m_creature->GetHealth() > 6) + // 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(uint32(m_creature->GetHealth()-5)); + m_creature->SetHealth(m_creature->GetHealth() - uiHPLose); } - if (m_creature->isAlive() && m_creature->GetHealth() <= 6) + if (m_creature->isAlive() && m_creature->GetHealth() <= 1 + uiHPLose) { m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetDeathState(JUST_DIED); m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - if (Doctorguid) + if (Creature* pDoctor = m_creature->GetMap()->GetCreature(m_doctorGuid)) { - if (Creature* pDoctor = m_creature->GetMap()->GetCreature(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,38 +623,38 @@ npc_doctor (continue) void npc_doctorAI::BeginEvent(Player* pPlayer) { - Playerguid = pPlayer->GetGUID(); + 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(Playerguid); + 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); @@ -684,31 +665,27 @@ 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 && Playerguid == pPlayer->GetGUID()) + 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) { - if (!Patients.empty()) + for (GuidList::const_iterator itr = m_lPatientGuids.begin(); itr != m_lPatientGuids.end(); ++itr) { - std::list::iterator itr; - for(itr = Patients.begin(); itr != Patients.end(); ++itr) - { - if (Creature* Patient = m_creature->GetMap()->GetCreature(*itr)) - Patient->SetDeathState(JUST_DIED); - } + if (Creature* Patient = m_creature->GetMap()->GetCreature(*itr)) + Patient->SetDeathState(JUST_DIED); } if (pPlayer->GetQuestStatus(QUEST_TRIAGE_A) == QUEST_STATUS_INCOMPLETE) @@ -720,67 +697,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->GetGUID()); + 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->Doctorguid = m_creature->GetGUID(); - - if (Point) - pPatientAI->Coord = Point; + pPatientAI->m_doctorGuid = m_creature->GetObjectGuid(); + 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; } } @@ -804,8 +768,6 @@ CreatureAI* GetAI_npc_doctor(Creature* pCreature) ## npc_garments_of_quests ######*/ -//TODO: get text for each NPC - enum { SPELL_LESSER_HEAL_R2 = 2052, @@ -838,167 +800,167 @@ enum struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI { - npc_garments_of_questsAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} + npc_garments_of_questsAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - uint64 caster; + ObjectGuid m_playerGuid; - bool bIsHealed; - bool bCanRun; + bool m_bIsHealed; + bool m_bCanRun; - uint32 RunAwayTimer; + uint32 m_uiRunAwayTimer; - void Reset() + void Reset() override { - caster = 0; + m_playerGuid.Clear(); - bIsHealed = false; - bCanRun = false; + m_bIsHealed = false; + m_bCanRun = false; - RunAwayTimer = 5000; + m_uiRunAwayTimer = 5000; m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); - //expect database to have RegenHealth=0 - m_creature->SetHealth(int(m_creature->GetMaxHealth()*0.7)); + // expect database to have RegenHealth=0 + m_creature->SetHealth(int(m_creature->GetMaxHealth() * 0.7)); } - void SpellHit(Unit* pCaster, const SpellEntry *Spell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (Spell->Id == SPELL_LESSER_HEAL_R2 || Spell->Id == SPELL_FORTITUDE_R1) + if (pSpell->Id == SPELL_LESSER_HEAL_R2 || pSpell->Id == SPELL_FORTITUDE_R1) { - //not while in combat + // not while in combat if (m_creature->isInCombat()) return; - //nothing to be done now - if (bIsHealed && bCanRun) + // nothing to be done now + if (m_bIsHealed && m_bCanRun) return; 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) { - if (bIsHealed && !bCanRun && Spell->Id == SPELL_FORTITUDE_R1) + if (m_bIsHealed && !m_bCanRun && pSpell->Id == SPELL_FORTITUDE_R1) { - DoScriptText(SAY_SHAYA_THANKS,m_creature,pCaster); - bCanRun = true; + DoScriptText(SAY_SHAYA_THANKS, m_creature, pCaster); + m_bCanRun = true; } - else if (!bIsHealed && Spell->Id == SPELL_LESSER_HEAL_R2) + else if (!m_bIsHealed && pSpell->Id == SPELL_LESSER_HEAL_R2) { - caster = pCaster->GetGUID(); + m_playerGuid = pCaster->GetObjectGuid(); m_creature->SetStandState(UNIT_STAND_STATE_STAND); - DoScriptText(SAY_COMMON_HEALED,m_creature,pCaster); - bIsHealed = true; + DoScriptText(SAY_COMMON_HEALED, m_creature, pCaster); + m_bIsHealed = true; } } break; case ENTRY_ROBERTS: if (((Player*)pCaster)->GetQuestStatus(QUEST_LIGHT_1) == QUEST_STATUS_INCOMPLETE) { - if (bIsHealed && !bCanRun && Spell->Id == SPELL_FORTITUDE_R1) + if (m_bIsHealed && !m_bCanRun && pSpell->Id == SPELL_FORTITUDE_R1) { - DoScriptText(SAY_ROBERTS_THANKS,m_creature,pCaster); - bCanRun = true; + DoScriptText(SAY_ROBERTS_THANKS, m_creature, pCaster); + m_bCanRun = true; } - else if (!bIsHealed && Spell->Id == SPELL_LESSER_HEAL_R2) + else if (!m_bIsHealed && pSpell->Id == SPELL_LESSER_HEAL_R2) { - caster = pCaster->GetGUID(); + m_playerGuid = pCaster->GetObjectGuid(); m_creature->SetStandState(UNIT_STAND_STATE_STAND); - DoScriptText(SAY_COMMON_HEALED,m_creature,pCaster); - bIsHealed = true; + DoScriptText(SAY_COMMON_HEALED, m_creature, pCaster); + m_bIsHealed = true; } } break; case ENTRY_DOLF: if (((Player*)pCaster)->GetQuestStatus(QUEST_LIGHT_2) == QUEST_STATUS_INCOMPLETE) { - if (bIsHealed && !bCanRun && Spell->Id == SPELL_FORTITUDE_R1) + if (m_bIsHealed && !m_bCanRun && pSpell->Id == SPELL_FORTITUDE_R1) { - DoScriptText(SAY_DOLF_THANKS,m_creature,pCaster); - bCanRun = true; + DoScriptText(SAY_DOLF_THANKS, m_creature, pCaster); + m_bCanRun = true; } - else if (!bIsHealed && Spell->Id == SPELL_LESSER_HEAL_R2) + else if (!m_bIsHealed && pSpell->Id == SPELL_LESSER_HEAL_R2) { - caster = pCaster->GetGUID(); + m_playerGuid = pCaster->GetObjectGuid(); m_creature->SetStandState(UNIT_STAND_STATE_STAND); - DoScriptText(SAY_COMMON_HEALED,m_creature,pCaster); - bIsHealed = true; + DoScriptText(SAY_COMMON_HEALED, m_creature, pCaster); + m_bIsHealed = true; } } break; case ENTRY_KORJA: if (((Player*)pCaster)->GetQuestStatus(QUEST_SPIRIT) == QUEST_STATUS_INCOMPLETE) { - if (bIsHealed && !bCanRun && Spell->Id == SPELL_FORTITUDE_R1) + if (m_bIsHealed && !m_bCanRun && pSpell->Id == SPELL_FORTITUDE_R1) { - DoScriptText(SAY_KORJA_THANKS,m_creature,pCaster); - bCanRun = true; + DoScriptText(SAY_KORJA_THANKS, m_creature, pCaster); + m_bCanRun = true; } - else if (!bIsHealed && Spell->Id == SPELL_LESSER_HEAL_R2) + else if (!m_bIsHealed && pSpell->Id == SPELL_LESSER_HEAL_R2) { - caster = pCaster->GetGUID(); + m_playerGuid = pCaster->GetObjectGuid(); m_creature->SetStandState(UNIT_STAND_STATE_STAND); - DoScriptText(SAY_COMMON_HEALED,m_creature,pCaster); - bIsHealed = true; + DoScriptText(SAY_COMMON_HEALED, m_creature, pCaster); + m_bIsHealed = true; } } break; case ENTRY_DG_KEL: if (((Player*)pCaster)->GetQuestStatus(QUEST_DARKNESS) == QUEST_STATUS_INCOMPLETE) { - if (bIsHealed && !bCanRun && Spell->Id == SPELL_FORTITUDE_R1) + if (m_bIsHealed && !m_bCanRun && pSpell->Id == SPELL_FORTITUDE_R1) { - DoScriptText(SAY_DG_KEL_THANKS,m_creature,pCaster); - bCanRun = true; + DoScriptText(SAY_DG_KEL_THANKS, m_creature, pCaster); + m_bCanRun = true; } - else if (!bIsHealed && Spell->Id == SPELL_LESSER_HEAL_R2) + else if (!m_bIsHealed && pSpell->Id == SPELL_LESSER_HEAL_R2) { - caster = pCaster->GetGUID(); + m_playerGuid = pCaster->GetObjectGuid(); m_creature->SetStandState(UNIT_STAND_STATE_STAND); - DoScriptText(SAY_COMMON_HEALED,m_creature,pCaster); - bIsHealed = true; + DoScriptText(SAY_COMMON_HEALED, m_creature, pCaster); + m_bIsHealed = true; } } break; } - //give quest credit, not expect any special quest objectives - if (bCanRun) - ((Player*)pCaster)->TalkedToCreature(m_creature->GetEntry(),m_creature->GetGUID()); + // give quest credit, not expect any special quest objectives + if (m_bCanRun) + ((Player*)pCaster)->TalkedToCreature(m_creature->GetEntry(), m_creature->GetObjectGuid()); } } } - void WaypointReached(uint32 uiPoint) - { - } + void WaypointReached(uint32 /*uiPointId*/) override {} - void UpdateEscortAI(const uint32 diff) + void UpdateEscortAI(const uint32 uiDiff) override { - if (bCanRun && !m_creature->isInCombat()) + if (m_bCanRun && !m_creature->isInCombat()) { - if (RunAwayTimer <= diff) + if (m_uiRunAwayTimer <= uiDiff) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(caster)) + 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_SHAYA: DoScriptText(SAY_SHAYA_GOODBYE, m_creature, pPlayer); break; case ENTRY_ROBERTS: DoScriptText(SAY_ROBERTS_GOODBYE, m_creature, pPlayer); break; - case ENTRY_DOLF: DoScriptText(SAY_DOLF_GOODBYE, m_creature, pPlayer); break; - case ENTRY_KORJA: DoScriptText(SAY_KORJA_GOODBYE, m_creature, pPlayer); break; - case ENTRY_DG_KEL: DoScriptText(SAY_DG_KEL_GOODBYE, m_creature, pPlayer); break; + case ENTRY_DOLF: DoScriptText(SAY_DOLF_GOODBYE, m_creature, pPlayer); break; + case ENTRY_KORJA: DoScriptText(SAY_KORJA_GOODBYE, m_creature, pPlayer); break; + case ENTRY_DG_KEL: DoScriptText(SAY_DG_KEL_GOODBYE, m_creature, pPlayer); break; } Start(true); } else - EnterEvadeMode(); //something went wrong + EnterEvadeMode(); // something went wrong - RunAwayTimer = 30000; - }else RunAwayTimer -= diff; + m_uiRunAwayTimer = 30000; + } + else + m_uiRunAwayTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -1023,19 +985,19 @@ struct MANGOS_DLL_DECL 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(); } } @@ -1058,19 +1020,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_TREAT = 24715, - SPELL_TRICK_NO_ATTACK = 24753, - SPELL_TRICK_GNOME = 24713, - SPELL_TRICK_GHOST_MALE = 24735, - SPELL_TRICK_GHOST_FEMALE = 24736, - SPELL_TRICK_NINJA_MALE = 24710, - SPELL_TRICK_NINJA_FEMALE = 24711, - SPELL_TRICK_PIRATE_MALE = 24708, - SPELL_TRICK_PIRATE_FEMALE = 24709, - SPELL_TRICK_SKELETON = 24723, - SPELL_TRICK_BAT = 24732 + 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!" @@ -1078,765 +1029,1056 @@ enum bool GossipHello_npc_innkeeper(Player* pPlayer, Creature* pCreature) { - pPlayer->PrepareGossipMenu(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->GetGUID()); + pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); pPlayer->SendPreparedGossip(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->GetGUID()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_WHAT_TO_DO, pCreature->GetObjectGuid()); break; - case GOSSIP_ACTION_INFO_DEF+2: - { pPlayer->CLOSE_GOSSIP_MENU(); - - // either trick or treat, 50% chance - if (urand(0, 1)) - { - pPlayer->CastSpell(pPlayer, SPELL_TREAT, true); - } - else - { - uint32 uiTrickSpell = 0; - - switch(urand(0, 9)) // note that female characters can get male costumes and vice versa - { - case 0: uiTrickSpell = SPELL_TRICK_NO_ATTACK; break; - case 1: uiTrickSpell = SPELL_TRICK_GNOME; break; - case 2: uiTrickSpell = SPELL_TRICK_GHOST_MALE; break; - case 3: uiTrickSpell = SPELL_TRICK_GHOST_FEMALE; break; - case 4: uiTrickSpell = SPELL_TRICK_NINJA_MALE; break; - case 5: uiTrickSpell = SPELL_TRICK_NINJA_FEMALE; break; - case 6: uiTrickSpell = SPELL_TRICK_PIRATE_MALE; break; - case 7: uiTrickSpell = SPELL_TRICK_PIRATE_FEMALE; break; - case 8: uiTrickSpell = SPELL_TRICK_SKELETON; break; - case 9: uiTrickSpell = SPELL_TRICK_BAT; break; - } - - pPlayer->CastSpell(pPlayer, uiTrickSpell, true); - } - - pPlayer->CastSpell(pPlayer, SPELL_TRICK_OR_TREATED, true); + pCreature->CastSpell(pPlayer, SPELL_TRICK_OR_TREAT, true); break; - } - case GOSSIP_OPTION_VENDOR: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); + pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); break; case GOSSIP_OPTION_INNKEEPER: pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->SetBindPoint(pCreature->GetGUID()); + pPlayer->SetBindPoint(pCreature->GetObjectGuid()); break; } return true; } -/*###### -## npc_kingdom_of_dalaran_quests -######*/ +/*#### + ## npc_snake_trap_serpents - Summonned snake id are 19921 and 19833 + ####*/ -enum -{ - SPELL_TELEPORT_DALARAN = 53360, - ITEM_KT_SIGNET = 39740, - QUEST_MAGICAL_KINGDOM_A = 12794, - QUEST_MAGICAL_KINGDOM_H = 12791, - QUEST_MAGICAL_KINGDOM_N = 12796 -}; +#define SPELL_MIND_NUMBING_POISON 25810 //Viper +#define SPELL_CRIPPLING_POISON 30981 //Viper +#define SPELL_DEADLY_POISON 34655 //Venomous Snake -#define GOSSIP_ITEM_TELEPORT_TO "I am ready to be teleported to Dalaran." +#define MOB_VIPER 19921 +#define MOB_VENOM_SNIKE 19833 -bool GossipHello_npc_kingdom_of_dalaran_quests(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_snake_trap_serpentsAI : public ScriptedAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_snake_trap_serpentsAI(Creature *c) : ScriptedAI(c) {Reset();} - if (pPlayer->HasItemCount(ITEM_KT_SIGNET,1) && (!pPlayer->GetQuestRewardStatus(QUEST_MAGICAL_KINGDOM_A) || - !pPlayer->GetQuestRewardStatus(QUEST_MAGICAL_KINGDOM_H) || !pPlayer->GetQuestRewardStatus(QUEST_MAGICAL_KINGDOM_N))) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT_TO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + uint32 SpellTimer; + Unit* Owner; - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); - return true; -} + void Reset() override + { + SpellTimer = 500; + Owner = m_creature->GetCharmerOrOwner(); + if (!Owner) return; -bool GossipSelect_npc_kingdom_of_dalaran_quests(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + m_creature->SetLevel(Owner->getLevel()); + m_creature->setFaction(Owner->getFaction()); + } + + void AttackStart(Unit* pWho) override { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer,SPELL_TELEPORT_DALARAN,false); + if (!pWho) return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->SetInCombatWith(pWho); + m_creature->AddThreat(pWho, 100.0f); + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(pWho); + } } - return true; -} -/*###### -## npc_lunaclaw_spirit -######*/ + void UpdateAI(const uint32 diff) override + { + if (!m_creature->getVictim()) + { + if (Owner && Owner->getVictim()) + AttackStart(Owner->getVictim()); + return; + } -enum -{ - QUEST_BODY_HEART_A = 6001, - QUEST_BODY_HEART_H = 6002, + if (SpellTimer <= diff) + { + if (m_creature->GetEntry() == MOB_VIPER ) //Viper - 19921 + { + if (!urand(0,2)) //33% chance to cast + { + uint32 spell; + if (urand(0,1)) + spell = SPELL_MIND_NUMBING_POISON; + else + spell = SPELL_CRIPPLING_POISON; + DoCast(m_creature->getVictim(), spell); + } - TEXT_ID_DEFAULT = 4714, - TEXT_ID_PROGRESS = 4715 -}; + SpellTimer = urand(3000, 5000); + } + else if (m_creature->GetEntry() == MOB_VENOM_SNIKE ) //Venomous Snake - 19833 + { + if (urand(0,1) == 0) //80% chance to cast + DoCast(m_creature->getVictim(), SPELL_DEADLY_POISON); + SpellTimer = urand(2500, 4500); + } + } + else SpellTimer -= diff; -#define GOSSIP_ITEM_GRANT "You have thought well, spirit. I ask you to grant me the strength of your body and the strength of your heart." + DoMeleeAttackIfReady(); + } +}; -bool GossipHello_npc_lunaclaw_spirit(Player* pPlayer, Creature* pCreature) +CreatureAI* GetAI_npc_snake_trap_serpents(Creature* pCreature) { - if (pPlayer->GetQuestStatus(QUEST_BODY_HEART_A) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_BODY_HEART_H) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GRANT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_DEFAULT, pCreature->GetGUID()); - return true; + return new npc_snake_trap_serpentsAI(pCreature); } -bool GossipSelect_npc_lunaclaw_spirit(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +struct MANGOS_DLL_DECL npc_rune_blade : public ScriptedAI { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + npc_rune_blade(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + Unit* owner; + + void Reset() override { - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_PROGRESS, pCreature->GetGUID()); - pPlayer->AreaExploredOrEventHappens((pPlayer->GetTeam() == ALLIANCE) ? QUEST_BODY_HEART_A : QUEST_BODY_HEART_H); - } - return true; -} + owner = m_creature->GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; -/*###### -## npc_mount_vendor -######*/ + // Cannot be Selected or Attacked + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -bool GossipHello_npc_mount_vendor(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + m_creature->SetLevel(owner->getLevel()); + m_creature->setFaction(owner->getFaction()); - bool canBuy; - canBuy = false; - uint32 vendor = pCreature->GetEntry(); - uint8 race = pPlayer->getRace(); + // Add visible weapon + if (Item const * item = ((Player *)owner)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, item->GetProto()->ItemId); - 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->GetGUID()); - else canBuy = true; - break; - case 1261: //Veron Amberstill - if (pPlayer->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF) - pPlayer->SEND_GOSSIP_MENU(5856, pCreature->GetGUID()); - else canBuy = true; - break; - case 3362: //Ogunaro Wolfrunner - if (pPlayer->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC) - pPlayer->SEND_GOSSIP_MENU(5841, pCreature->GetGUID()); - else canBuy = true; - break; - case 3685: //Harb Clawhoof - if (pPlayer->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN) - pPlayer->SEND_GOSSIP_MENU(5843, pCreature->GetGUID()); - else canBuy = true; - break; - case 4730: //Lelanai - if (pPlayer->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF) - pPlayer->SEND_GOSSIP_MENU(5844, pCreature->GetGUID()); - else canBuy = true; - break; - case 4731: //Zachariah Post - if (pPlayer->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER) - pPlayer->SEND_GOSSIP_MENU(5840, pCreature->GetGUID()); - else canBuy = true; - break; - case 7952: //Zjolnir - if (pPlayer->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL) - pPlayer->SEND_GOSSIP_MENU(5842, pCreature->GetGUID()); - else canBuy = true; - break; - case 7955: //Milli Featherwhistle - if (pPlayer->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME) - pPlayer->SEND_GOSSIP_MENU(5857, pCreature->GetGUID()); - else canBuy = true; - break; - case 16264: //Winaestra - if (pPlayer->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF) - pPlayer->SEND_GOSSIP_MENU(10305, pCreature->GetGUID()); - 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->GetGUID()); - else canBuy = true; - break; + // Add stats scaling + int32 damageDone=owner->CalculateDamage(BASE_ATTACK, true); // might be average damage instead ? + int32 meleeSpeed=owner->m_modAttackSpeedPct[BASE_ATTACK]; + m_creature->CastCustomSpell(m_creature, 51906, &damageDone, &meleeSpeed, NULL, true); + + // Visual Glow + m_creature->CastSpell(m_creature, 53160, true); + + SetCombatMovement(true); } - if (canBuy) + void UpdateAI(const uint32 /*diff*/) override { - 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->GetGUID()); + if (!owner) return; + + if (!m_creature->getVictim()) + { + if (owner->getVictim()) + AttackStart(owner->getVictim()); + } + + DoMeleeAttackIfReady(); } - return true; -} +}; -bool GossipSelect_npc_mount_vendor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +CreatureAI* GetAI_npc_rune_blade(Creature* pCreature) { - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - - return true; + return new npc_rune_blade(pCreature); } -/*###### -## npc_rogue_trainer -######*/ +/*######## +# npc_risen_ally AI +#########*/ -bool GossipHello_npc_rogue_trainer(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_risen_allyAI : public ScriptedAI { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + npc_risen_allyAI(Creature *pCreature) : ScriptedAI(pCreature) + { + } - if (pCreature->isTrainer()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); + uint32 StartTimer; - if (pCreature->CanTrainAndResetTalentsOf(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "I wish to unlearn my talents", GOSSIP_SENDER_MAIN, GOSSIP_OPTION_UNLEARNTALENTS); + void Reset() override + { + StartTimer = 2000; + m_creature->SetSheath(SHEATH_STATE_MELEE); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_ABANDONED); + m_creature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048); + m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + m_creature->SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f); + if (Player* creator = m_creature->GetMap()->GetPlayer(m_creature->GetCreatorGuid())) + { + m_creature->SetLevel(creator->getLevel()); + m_creature->setFaction(creator->getFaction()); + } + } - if (pPlayer->getClass() == CLASS_ROGUE && pPlayer->getLevel() >= 24 && !pPlayer->HasItemCount(17126,1) && !pPlayer->GetQuestRewardStatus(6681)) + void JustDied(Unit* killer) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(5996, pCreature->GetGUID()); - } else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + if (!m_creature) + return; - return true; -} + if (Player* creator = m_creature->GetMap()->GetPlayer(m_creature->GetCreatorGuid())) + { + creator->RemoveAurasDueToSpell(46619); + creator->RemoveAurasDueToSpell(62218); + } + } -bool GossipSelect_npc_rogue_trainer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) + void AttackStart(Unit* pWho) override { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer,21100,false); - break; - case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetGUID()); - break; - case GOSSIP_OPTION_UNLEARNTALENTS: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->SendTalentWipeConfirm(pCreature->GetGUID()); - break; - } - return true; -} + if (!pWho) return; -/*###### -## npc_sayge -######*/ + if (m_creature->Attack(pWho, true)) + { + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 10.0f); + SetCombatMovement(true); + } + } -#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->GetGUID()); - - 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->GetGUID()); - else + void UpdateAI(const uint32 uiDiff) override { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(7339, pCreature->GetGUID()); + if(StartTimer > uiDiff) + { + StartTimer -= uiDiff; + return; + } + + if(!m_creature->isCharmed()) + m_creature->ForcedDespawn(); + + if (m_creature->isInCombat()) + DoMeleeAttackIfReady(); } +}; - return true; +CreatureAI* GetAI_npc_risen_ally(Creature* pCreature) +{ + return new npc_risen_allyAI(pCreature); } -void SendAction_npc_sayge(Player* pPlayer, Creature* pCreature, uint32 uiAction) +/*######## +# npc_explosive_decoyAI +#########*/ + +struct MANGOS_DLL_DECL npc_explosive_decoyAI : public ScriptedAI { - switch(uiAction) + npc_explosive_decoyAI(Creature *pCreature) : ScriptedAI(pCreature) { - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - 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->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pCreature->CastSpell(pPlayer, SPELL_FORTUNE, false); - pPlayer->SEND_GOSSIP_MENU(7365, pCreature->GetGUID()); - break; + Reset(); } -} -bool GossipSelect_npc_sayge(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiSender) + Player* p_owner; + + void Reset() override { - 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; + p_owner = NULL; + SetCombatMovement(false); } - return true; -} -/*###### -## npc_tabard_vendor -######*/ + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!m_creature || !m_creature->isAlive()) + return; -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 -}; + if (uiDamage > 0) + m_creature->CastSpell(m_creature, 53273, true); + } -#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); - } + void JustDied(Unit* killer) + { + if (!m_creature || !p_owner) + return; - 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); - } + SpellEntry const* createSpell = GetSpellStore()->LookupEntry(m_creature->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + if (createSpell) + p_owner->SendCooldownEvent(createSpell); } - else - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - return true; -} - -bool GossipSelect_npc_tabard_vendor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) + void UpdateAI(const uint32 uiDiff) override { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetGUID()); - 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; -} + if (p_owner) + return; -/*###### -## npc_locksmith -######*/ + p_owner = m_creature->GetMap()->GetPlayer(m_creature->GetCreatorGuid()); -enum -{ - QUEST_HOW_TO_BRAKE_IN_TO_THE_ARCATRAZ = 10704, - QUEST_DARK_IRON_LEGACY = 3802, - QUEST_THE_KEY_TO_SCHOLOMANCE_A = 5505, - QUEST_THE_KEY_TO_SCHOLOMANCE_H = 5511, - QUEST_HOTTER_THAN_HELL_A = 10758, - QUEST_HOTTER_THAN_HELL_H = 10764, - QUEST_RETURN_TO_KHAGDAR = 9837, - QUEST_CONTAINMENT = 13159, - - ITEM_ARCATRAZ_KEY = 31084, - ITEM_SHADOWFORGE_KEY = 11000, - ITEM_SKELETON_KEY = 13704, - ITEM_SHATTERED_HALLS_KEY = 28395, - ITEM_THE_MASTERS_KEY = 24490, - ITEM_VIOLET_HOLD_KEY = 42482, - - SPELL_ARCATRAZ_KEY = 54881, - SPELL_SHADOWFORGE_KEY = 54882, - SPELL_SKELETON_KEY = 54883, - SPELL_SHATTERED_HALLS_KEY = 54884, - SPELL_THE_MASTERS_KEY = 54885, - SPELL_VIOLET_HOLD_KEY = 67253 + if (!p_owner) + return; + + m_creature->setFaction(p_owner->getFaction()); + m_creature->SetCreatorGuid(ObjectGuid()); + } }; -#define GOSSIP_LOST_ARCATRAZ_KEY "I've lost my key to the Arcatraz." -#define GOSSIP_LOST_SHADOWFORGE_KEY "I've lost my key to the Blackrock Depths." -#define GOSSIP_LOST_SKELETON_KEY "I've lost my key to the Scholomance." -#define GOSSIP_LOST_SHATTERED_HALLS_KEY "I've lost my key to the Shattered Halls." -#define GOSSIP_LOST_THE_MASTERS_KEY "I've lost my key to the Karazhan." -#define GOSSIP_LOST_VIOLET_HOLD_KEY "I've lost my key to the Violet Hold." +CreatureAI* GetAI_npc_explosive_decoy(Creature* pCreature) +{ + return new npc_explosive_decoyAI(pCreature); +} +/*######## +# npc_eye_of_kilroggAI +#########*/ -bool GossipHello_npc_locksmith(Player* pPlayer, Creature* pCreature) +struct MANGOS_DLL_DECL npc_eye_of_kilrogg : public ScriptedAI { + npc_eye_of_kilrogg(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + + Player* p_owner; - // Arcatraz Key - if (pPlayer->GetQuestRewardStatus(QUEST_HOW_TO_BRAKE_IN_TO_THE_ARCATRAZ) && !pPlayer->HasItemCount(ITEM_ARCATRAZ_KEY, 1, true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_ARCATRAZ_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +1); + void Reset() override + { + p_owner = NULL; + } - // Shadowforge Key - if (pPlayer->GetQuestRewardStatus(QUEST_DARK_IRON_LEGACY) && !pPlayer->HasItemCount(ITEM_SHADOWFORGE_KEY, 1, true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_SHADOWFORGE_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +2); + void UpdateAI(const uint32 /*diff*/) override + { + if (p_owner) + return; - // Skeleton Key - if ((pPlayer->GetQuestRewardStatus(QUEST_THE_KEY_TO_SCHOLOMANCE_A) || pPlayer->GetQuestRewardStatus(QUEST_THE_KEY_TO_SCHOLOMANCE_H)) && - !pPlayer->HasItemCount(ITEM_SKELETON_KEY, 1, true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_SKELETON_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +3); + p_owner = (Player*)m_creature->GetCharmerOrOwner(); - // Shatered Halls Key - if ((pPlayer->GetQuestRewardStatus(QUEST_HOTTER_THAN_HELL_A) || pPlayer->GetQuestRewardStatus(QUEST_HOTTER_THAN_HELL_H)) && - !pPlayer->HasItemCount(ITEM_SHATTERED_HALLS_KEY, 1, true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_SHATTERED_HALLS_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +4); + if (!p_owner) + return; - // Master's Key - if (pPlayer->GetQuestRewardStatus(QUEST_RETURN_TO_KHAGDAR) && !pPlayer->HasItemCount(ITEM_THE_MASTERS_KEY, 1, true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_THE_MASTERS_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +5); + if (!m_creature->HasAura(2585)) + m_creature->CastSpell(m_creature, 2585, true); - // Violet Hold Key - if (pPlayer->GetQuestRewardStatus(QUEST_CONTAINMENT) && !pPlayer->HasItemCount(ITEM_VIOLET_HOLD_KEY, 1, true)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_VIOLET_HOLD_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +6); + if (p_owner->HasAura(58081)) + m_creature->CastSpell(m_creature, 58083, true); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + } +}; - return true; +CreatureAI* GetAI_npc_eye_of_kilrogg(Creature* pCreature) +{ + return new npc_eye_of_kilrogg(pCreature); } -bool GossipSelect_npc_locksmith(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +/*######## +# npc_fire_bunny +#########*/ + +enum { - switch(uiAction) + NPC_FIRE_BUNNY = 23686, + SPELL_THROW_BUCKET = 42339, + SPELL_EXTINGUISH_VISUAL = 42348, + SPELL_FLAMES_LARGE = 42075, + SPELL_SMOKE = 42355, + SPELL_CONFLAGRATE = 42132, + SPELL_HORSEMAN_MOUNT = 48024, + SPELL_HORSMAN_SHADE_VIS = 43904, + SPELL_Q_STOP_THE_FIRE = 42242, + SPELL_Q_LET_THE_FIRES_C = 47775, + SPELL_LAUGH_DELAYED_8 = 43893, + + PHASE_INITIAL = 0, + PHASE_1ST_SPEACH = 1, + PHASE_2ND_SPEACH = 2, + PHASE_FAIL = 3, + PHASE_END = 4, + + YELL_IGNITE = -1110001, + YELL_1ST = -1110002, + YELL_2ND = -1110003, + YELL_FAIL = -1110004, + YELL_VICTORY = -1110005, + YELL_CONFLAGRATION = -1110006 +}; + +struct MANGOS_DLL_DECL npc_horseman_fire_bunnyAI : public Scripted_NoMovementAI +{ + npc_horseman_fire_bunnyAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_ARCATRAZ_KEY, false); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_SHADOWFORGE_KEY, false); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_SKELETON_KEY, false); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_SHATTERED_HALLS_KEY, false); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_THE_MASTERS_KEY, false); + Reset(); + m_creature->RemoveAllAuras(); + } + + void Reset() override + { + if (!m_creature->isAlive()) + m_creature->Respawn(); + } + + void SpellHit(Unit* pWho, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_THROW_BUCKET) + { + pWho->CastSpell(m_creature, SPELL_EXTINGUISH_VISUAL, false); + m_creature->RemoveAurasDueToSpell(SPELL_FLAMES_LARGE); + } + if (pSpell->Id == SPELL_CONFLAGRATE) + { + DoCastSpellIfCan(m_creature, SPELL_FLAMES_LARGE); + m_creature->RemoveAurasDueToSpell(SPELL_CONFLAGRATE); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_creature->SelectHostileTarget() || m_creature->getVictim()) + EnterEvadeMode(); // Dunno how to prevent them from entering combat while hit by SPELL_EXTINGUISH_VISUAL (spelleffect 2) + } +}; + +CreatureAI* GetAI_npc_horseman_fire_bunny(Creature* pCreature) +{ + return new npc_horseman_fire_bunnyAI (pCreature); +}; + +/*######## +# npc_shade of horseman +#########*/ + +struct MANGOS_DLL_DECL npc_shade_of_horsemanAI : public ScriptedAI +{ + npc_shade_of_horsemanAI(Creature* pCreature) : ScriptedAI(pCreature){Reset();} + + uint8 uiPhase; + uint32 m_uiEventTimer; + uint32 m_uiConflagrationTimer; + uint32 m_uiConflagrationProcTimer; + bool bIsConflagrating; + + GuidList lFireBunnies; + + void Reset() override + { + if (!m_creature->isAlive()) + m_creature->Respawn(); + + uiPhase = PHASE_INITIAL; + lFireBunnies.clear(); + bIsConflagrating = true; + + m_uiEventTimer = 2.5*MINUTE*IN_MILLISECONDS; + + m_uiConflagrationTimer = 30000; + m_uiConflagrationProcTimer = 2000; + + DoCastSpellIfCan(m_creature, SPELL_HORSEMAN_MOUNT); + DoCastSpellIfCan(m_creature, SPELL_HORSMAN_SHADE_VIS); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (uiPhase == PHASE_INITIAL) + { + DoScriptText(YELL_IGNITE, m_creature); + ++uiPhase; + return; + } + else if (uiPhase == PHASE_END) + return; + + if (!bIsConflagrating) + { + bool IsVictory = true; + for (GuidList::iterator itr = lFireBunnies.begin(); itr != lFireBunnies.end(); ++itr) + if (Creature* pFireBunny = m_creature->GetMap()->GetCreature(*itr)) + if (pFireBunny->HasAura(SPELL_FLAMES_LARGE)) + IsVictory = false; + if (IsVictory) + { + DoScriptText(YELL_VICTORY, m_creature); + DoCastSpellIfCan(m_creature, SPELL_Q_STOP_THE_FIRE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_Q_LET_THE_FIRES_C, CAST_TRIGGERED); + m_creature->ForcedDespawn(5000); + uiPhase = PHASE_END; + return; + } + } + + if (m_uiEventTimer < uiDiff) + { + switch(uiPhase) + { + case PHASE_1ST_SPEACH: + DoScriptText(YELL_1ST, m_creature); + m_uiEventTimer = 2 *MINUTE*IN_MILLISECONDS; + break; + + case PHASE_2ND_SPEACH: + DoScriptText(YELL_2ND, m_creature); + m_uiEventTimer = 0.5 *MINUTE*IN_MILLISECONDS; + break; + case PHASE_FAIL: + DoScriptText(YELL_FAIL, m_creature); + m_creature->ForcedDespawn(10000); + for (GuidList::iterator itr = lFireBunnies.begin(); itr != lFireBunnies.end(); ++itr) + if (Creature* pFireBunny = m_creature->GetMap()->GetCreature(*itr)) + { + if (pFireBunny->HasAura(SPELL_FLAMES_LARGE)) + pFireBunny->RemoveAurasDueToSpell(SPELL_FLAMES_LARGE); + pFireBunny->CastSpell(m_creature, SPELL_SMOKE, true); + pFireBunny->ForcedDespawn(60000); + } + break; + } + ++uiPhase; + DoCastSpellIfCan(m_creature, SPELL_LAUGH_DELAYED_8); + } + else + m_uiEventTimer -= uiDiff; + + if (m_uiConflagrationTimer < uiDiff) + { + bIsConflagrating = !bIsConflagrating; + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_uiConflagrationProcTimer = 2000; + m_uiConflagrationTimer = bIsConflagrating ? 10000 : 30000; + if (bIsConflagrating) + DoScriptText(YELL_CONFLAGRATION, m_creature); + } + else + m_uiConflagrationTimer -= uiDiff; + + if (bIsConflagrating) + if (m_uiConflagrationProcTimer < uiDiff) + { + m_uiConflagrationProcTimer = 2000; + if (lFireBunnies.empty()) + { + std::list tempFireBunnies; + GetCreatureListWithEntryInGrid(tempFireBunnies, m_creature, NPC_FIRE_BUNNY, 50.0f); + for (std::list::iterator itr = tempFireBunnies.begin(); itr != tempFireBunnies.end(); ++itr) + lFireBunnies.push_back((*itr)->GetObjectGuid()); + } + + if (lFireBunnies.empty()) + { + m_creature->ForcedDespawn(5000); + error_log("Missing DB spawns of Fire Bunnies (Horseman Village Event)"); + uiPhase = PHASE_END; + return; + } + + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) + return; + + for (GuidList::iterator itr = lFireBunnies.begin(); itr != lFireBunnies.end(); ++itr) + if (Creature* pFireBunny = m_creature->GetMap()->GetCreature(*itr)) + if (!pFireBunny->HasAura(SPELL_FLAMES_LARGE)) + { + if (DoCastSpellIfCan(pFireBunny, SPELL_CONFLAGRATE) != CAST_OK) + { + float x,y,z; + pFireBunny->GetPosition(x,y,z); + pFireBunny->GetClosePoint(x,y,z,0,5,0); + m_creature->GetMotionMaster()->MovePoint(0, x,y,z+15); + break; + } + } + } + else + m_uiConflagrationProcTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_shade_of_horseman(Creature* pCreature) +{ + return new npc_shade_of_horsemanAI (pCreature); +}; + +/*######## +npc_wild_turkey +#########*/ +enum +{ + EMOTE_TURKEY_HUNTER = -1730001, + EMOTE_TURKEY_DOMINATION = -1730002, + EMOTE_TURKEY_SLAUGHTER = -1730003, + EMOTE_TURKEY_TRIUMPH = -1730004, + + SPELL_TURKEY_TRACKER = 62014, + SPELL_PH_KILL_COUNTER_VISUAL_MAX = 62021 +}; +struct MANGOS_DLL_DECL npc_wild_turkeyAI : public ScriptedAI +{ + npc_wild_turkeyAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_creature->RemoveAllAuras(); + } + + void Reset() override {} + + void UpdateAI(const uint32 uiDiff) override + { + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* pKiller) override + { + if (pKiller && pKiller->GetTypeId() == TYPEID_PLAYER) + { + pKiller->CastSpell(pKiller, SPELL_TURKEY_TRACKER, true); + Aura * pAura = pKiller->GetAura(SPELL_TURKEY_TRACKER, EFFECT_INDEX_0); + if (pAura) + { + uint32 stacks = pAura->GetStackAmount(); + switch (stacks) + { + case 10: + { + DoScriptText(EMOTE_TURKEY_HUNTER, m_creature, pKiller); + break; + } + case 20: + { + DoScriptText(EMOTE_TURKEY_DOMINATION, m_creature, pKiller); + break; + } + case 30: + { + DoScriptText(EMOTE_TURKEY_SLAUGHTER, m_creature, pKiller); + break; + } + case 40: + { + DoScriptText(EMOTE_TURKEY_TRIUMPH, m_creature, pKiller); + pKiller->CastSpell(pKiller, SPELL_PH_KILL_COUNTER_VISUAL_MAX, true); + break; + } + default: break; + } + } + } + } +}; + +CreatureAI* GetAI_npc_wild_turkey(Creature* pCreature) +{ + return new npc_wild_turkeyAI (pCreature); +}; + +/*###### +## npc_experience +######*/ + +#define EXP_COST 100000//10 00 00 copper (10golds) +#define GOSSIP_TEXT_EXP 14736 +#define GOSSIP_XP_OFF "I no longer wish to gain experience." +#define GOSSIP_XP_ON "I wish to start gaining experience again." + +bool GossipHello_npc_experience(Player* pPlayer, Creature* pCreature) +{ + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_XP_OFF, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_XP_ON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->PlayerTalkClass->SendGossipMenu(GOSSIP_TEXT_EXP, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_experience(Player* pPlayer, Creature* /*pCreature*/, uint32 /*uiSender*/, uint32 uiAction) +{ + bool noXPGain = pPlayer->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_XP_USER_DISABLED); + bool doSwitch = false; + + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF + 1://xp off + { + if (!noXPGain)//does gain xp + doSwitch = true;//switch to don't gain xp + } break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_VIOLET_HOLD_KEY, false); + case GOSSIP_ACTION_INFO_DEF + 2://xp on + { + if (noXPGain)//doesn't gain xp + doSwitch = true;//switch to gain xp + } break; } + if (doSwitch) + { + if (pPlayer->GetMoney() < EXP_COST) + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); + else if (noXPGain) + { + pPlayer->ModifyMoney(-EXP_COST); + pPlayer->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_XP_USER_DISABLED); + } + else if (!noXPGain) + { + pPlayer->ModifyMoney(-EXP_COST); + pPlayer->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_XP_USER_DISABLED); + } + } + pPlayer->PlayerTalkClass->CloseGossip(); return true; } +/*######## +## npc_spring_rabbit +## ATTENTION: This is actually a "fun" script, entirely done without proper source! +######*/ + +enum +{ + NPC_SPRING_RABBIT = 32791, + + SPELL_SPRING_RABBIT_JUMP = 61724, + SPELL_SPRING_RABBIT_WANDER = 61726, + SEPLL_SUMMON_BABY_BUNNY = 61727, + SPELL_SPRING_RABBIT_IN_LOVE = 61728, + SPELL_SPRING_FLING = 61875, +}; + +static const float DIST_START_EVENT = 15.0f; // Guesswork + +struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI +{ + npc_spring_rabbitAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + ObjectGuid m_partnerGuid; + uint32 m_uiStep; + uint32 m_uiStepTimer; + float m_fMoveAngle; + + void Reset() override + { + m_uiStep = 0; + m_uiStepTimer = 0; + m_partnerGuid.Clear(); + m_fMoveAngle = 0.0f; + } + + bool CanStartWhatRabbitsDo() { return !m_partnerGuid && !m_uiStepTimer; } + + void StartWhatRabbitsDo(Creature* pPartner) + { + m_partnerGuid = pPartner->GetObjectGuid(); + m_uiStep = 1; + m_uiStepTimer = 30000; + // Calculate meeting position + 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->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + + // Helper to get the Other Bunnies AI + npc_spring_rabbitAI* GetPartnerAI(Creature* pBunny = NULL) + { + if (!pBunny) + pBunny = m_creature->GetMap()->GetAnyTypeCreature(m_partnerGuid); + + if (!pBunny) + return NULL; + + return dynamic_cast(pBunny->AI()); + } + + // Event Starts when two rabbits see each other + void MoveInLineOfSight(Unit* pWho) override + { + if (m_creature->getVictim()) + return; + + if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_SPRING_RABBIT && CanStartWhatRabbitsDo() && m_creature->IsFriendlyTo(pWho) && m_creature->IsWithinDistInMap(pWho, DIST_START_EVENT, true)) + { + if (npc_spring_rabbitAI* pOtherBunnyAI = GetPartnerAI((Creature*)pWho)) + { + if (pOtherBunnyAI->CanStartWhatRabbitsDo()) + { + StartWhatRabbitsDo((Creature*)pWho); + pOtherBunnyAI->StartWhatRabbitsDo(m_creature); + } + } + return; + } + + ScriptedPetAI::MoveInLineOfSight(pWho); + } + + bool ReachedMeetingPlace() + { + if (m_uiStep == 3) // Already there + { + m_uiStepTimer = 3000; + m_uiStep = 2; + return true; + } + else + return false; + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) + { + if (uiMovementType != POINT_MOTION_TYPE || uiData != 1) + return; + + if (!m_partnerGuid) + return; + + m_uiStep = 3; + if (npc_spring_rabbitAI* pOtherBunnyAI = GetPartnerAI()) + { + if (pOtherBunnyAI->ReachedMeetingPlace()) + { + m_creature->SetFacingTo(pOtherBunnyAI->m_creature->GetOrientation()); + m_uiStepTimer = 3000; + } + else + 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()->MoveIdle(); + } + + // Overwrite ScriptedPetAI::UpdateAI, to prevent re-following while the event is active! + void UpdateAI(const uint32 uiDiff) override + { + if (!m_partnerGuid || !m_uiStepTimer) + { + ScriptedPetAI::UpdateAI(uiDiff); + return; + } + + if (m_uiStep == 6) + ScriptedPetAI::UpdateAI(uiDiff); // Event nearly finished, do normal following + + if (m_uiStepTimer <= uiDiff) + { + switch (m_uiStep) + { + case 1: // Timer expired, before reached meeting point. Reset. + Reset(); + break; + + case 2: // Called for the rabbit first reached meeting point + if (Creature* pBunny = m_creature->GetMap()->GetAnyTypeCreature(m_partnerGuid)) + pBunny->CastSpell(pBunny, SPELL_SPRING_RABBIT_IN_LOVE, false); + + DoCastSpellIfCan(m_creature, SPELL_SPRING_RABBIT_IN_LOVE); + // no break here + case 3: + m_uiStepTimer = 5000; + m_uiStep += 2; + break; + + case 4: // Called for the rabbit first reached meeting point + DoCastSpellIfCan(m_creature, SEPLL_SUMMON_BABY_BUNNY); + // no break here + case 5: + // Let owner cast achievement related spell + if (Unit* pOwner = m_creature->GetCharmerOrOwner()) + pOwner->CastSpell(pOwner, SPELL_SPRING_FLING, true); + + m_uiStep = 6; + m_uiStepTimer = 30000; + break; + case 6: + m_creature->RemoveAurasDueToSpell(SPELL_SPRING_RABBIT_IN_LOVE); + Reset(); + break; + } + } + else + m_uiStepTimer -= uiDiff; + } +}; + +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 MANGOS_DLL_DECL 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* newscript; - - newscript = new Script; - newscript->Name = "npc_air_force_bots"; - newscript->GetAI = &GetAI_npc_air_force_bots; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_chicken_cluck"; - newscript->GetAI = &GetAI_npc_chicken_cluck; - newscript->pQuestAccept = &QuestAccept_npc_chicken_cluck; - newscript->pQuestComplete = &QuestComplete_npc_chicken_cluck; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_dancing_flames"; - newscript->GetAI = &GetAI_npc_dancing_flames; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_injured_patient"; - newscript->GetAI = &GetAI_npc_injured_patient; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_doctor"; - newscript->GetAI = &GetAI_npc_doctor; - newscript->pQuestAccept = &QuestAccept_npc_doctor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_garments_of_quests"; - newscript->GetAI = &GetAI_npc_garments_of_quests; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_guardian"; - newscript->GetAI = &GetAI_npc_guardian; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_innkeeper"; - newscript->pGossipHello = &GossipHello_npc_innkeeper; - newscript->pGossipSelect = &GossipSelect_npc_innkeeper; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_kingdom_of_dalaran_quests"; - newscript->pGossipHello = &GossipHello_npc_kingdom_of_dalaran_quests; - newscript->pGossipSelect = &GossipSelect_npc_kingdom_of_dalaran_quests; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_lunaclaw_spirit"; - newscript->pGossipHello = &GossipHello_npc_lunaclaw_spirit; - newscript->pGossipSelect = &GossipSelect_npc_lunaclaw_spirit; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_mount_vendor"; - newscript->pGossipHello = &GossipHello_npc_mount_vendor; - newscript->pGossipSelect = &GossipSelect_npc_mount_vendor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_rogue_trainer"; - newscript->pGossipHello = &GossipHello_npc_rogue_trainer; - newscript->pGossipSelect = &GossipSelect_npc_rogue_trainer; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_sayge"; - newscript->pGossipHello = &GossipHello_npc_sayge; - newscript->pGossipSelect = &GossipSelect_npc_sayge; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_tabard_vendor"; - newscript->pGossipHello = &GossipHello_npc_tabard_vendor; - newscript->pGossipSelect = &GossipSelect_npc_tabard_vendor; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "npc_locksmith"; - newscript->pGossipHello = &GossipHello_npc_locksmith; - newscript->pGossipSelect = &GossipSelect_npc_locksmith; - newscript->RegisterSelf(); + AutoScript s; + + s.newScript("npc_air_force_bots"); + s->GetAI = &GetAI_npc_air_force_bots; + + s.newScript("npc_chicken_cluck"); + s->GetAI = &GetAI_npc_chicken_cluck; + s->pQuestAcceptNPC = &QuestAccept_npc_chicken_cluck; + s->pQuestRewardedNPC = &QuestRewarded_npc_chicken_cluck; + + s.newScript("npc_dancing_flames"); + s->GetAI = &GetAI_npc_dancing_flames; + + s.newScript("npc_injured_patient"); + s->GetAI = &GetAI_npc_injured_patient; + + s.newScript("npc_doctor"); + s->GetAI = &GetAI_npc_doctor; + s->pQuestAcceptNPC = &QuestAccept_npc_doctor; + + s.newScript("npc_garments_of_quests"); + s->GetAI = &GetAI_npc_garments_of_quests; + + s.newScript("npc_guardian"); + s->GetAI = &GetAI_npc_guardian; + + s.newScript("npc_innkeeper", false); // script and error report disabled, but script can be used for custom needs, adding ScriptName + s->pGossipHello = &GossipHello_npc_innkeeper; + s->pGossipSelect = &GossipSelect_npc_innkeeper; + + s.newScript("npc_snake_trap_serpents"); + s->GetAI = &GetAI_npc_snake_trap_serpents; + + s.newScript("npc_runeblade"); + s->GetAI = &GetAI_npc_rune_blade; + + s.newScript("npc_risen_ally"); + s->GetAI = &GetAI_npc_risen_ally; + + s.newScript("npc_explosive_decoy"); + s->GetAI = &GetAI_npc_explosive_decoy; + + s.newScript("npc_eye_of_kilrogg"); + s->GetAI = &GetAI_npc_eye_of_kilrogg; + + s.newScript("npc_horseman_fire_bunny"); + s->GetAI = &GetAI_npc_horseman_fire_bunny; + + s.newScript("npc_shade_of_horseman"); + s->GetAI = &GetAI_npc_shade_of_horseman; + + s.newScript("npc_wild_turkey"); + s->GetAI = &GetAI_npc_wild_turkey; + + s.newScript("npc_experience"); + s->pGossipHello = &GossipHello_npc_experience; + s->pGossipSelect = &GossipSelect_npc_experience; + + s.newScript("npc_spring_rabbit"); + s->GetAI = &GetAI_npc_spring_rabbit; + + s.newScript("npc_redemption_target"); + s->GetAI = &GetAI_npc_redemption_target; + s->pEffectDummyNPC = &EffectDummyCreature_npc_redemption_target; } diff --git a/scripts/world/pet_scripts.cpp b/scripts/world/pet_scripts.cpp new file mode 100644 index 0000000000..79a09af57b --- /dev/null +++ b/scripts/world/pet_scripts.cpp @@ -0,0 +1,203 @@ +/* Copyright (C) 2006 - 2013 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: pet_scripts +SD%Complete: +SDComment: To be used for pets. +SDCategory: Pet's +EndScriptData +*/ + +#include "precompiled.h" +#include "pet_ai.h" + +/* ContentData +pet_greater_fire_elemental ?% support for shaman pet Greater fire elemental +pet_greater_earth_elemental ?% support for shaman pet Greater earth elemental +EndContentData */ + +enum greater_fire_elemental_spells +{ + SPELL_FIRE_RING = 12470, + SPELL_FIRE_EXPLODE = 57984, +}; + +struct MANGOS_DLL_DECL pet_greater_fire_elemental : public ScriptedPetAI +{ + pet_greater_fire_elemental(Creature* pCreature) : ScriptedPetAI(pCreature) + { + Reset(); + } + + uint32 m_uiFireRingTimer; + uint32 m_uiFireExplodeTimer; + Pet* m_pet; + + void Reset() + { + m_pet = (Pet*)m_creature; + m_pet->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE); + m_pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + m_uiFireRingTimer = urand(3000,9000); + m_uiFireExplodeTimer = urand(4000,8000); + + if(m_pet->GetOwner()->IsPvP()) + m_pet->SetPvP(true); + if(m_pet->GetOwner()->IsFFAPvP()) + m_pet->SetFFAPvP(true); + } + + void UpdatePetAI(const uint32 diff) + { + if (!m_pet->GetOwner() || !m_pet->GetOwner()->isAlive()) + m_pet->ForcedDespawn(); + + if (m_pet->GetOwner()->getVictim() && m_pet->getVictim() != m_pet->GetOwner()->getVictim()) + AttackStart(m_pet->GetOwner()->getVictim()); + + if (m_uiFireRingTimer <= diff) + { + if (m_pet->IsWithinDistInMap(m_pet->getVictim(),ATTACK_DISTANCE)) + DoCastSpellIfCan(m_pet,SPELL_FIRE_RING); + m_uiFireRingTimer = urand(4000,12000); + } + else m_uiFireRingTimer -= diff; + + if (m_uiFireExplodeTimer <= diff) + { + DoCastSpellIfCan(m_pet->getVictim(),SPELL_FIRE_EXPLODE); + m_uiFireExplodeTimer = urand(4000,8000); + } else m_uiFireExplodeTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void UpdatePetOOCAI(const uint32 diff) + { + if (!m_pet->GetOwner() || !m_pet->GetOwner()->isAlive()) + m_pet->ForcedDespawn(); + + if (m_pet->GetOwner() && m_pet->GetOwner()->getVictim()) + { + AttackStart(m_pet->GetOwner()->getVictim()); + } + else if (m_pet->GetOwner()->isInCombat()) + { + AttackStart(m_pet->GetOwner()->getAttackerForHelper()); + } + } +}; + +CreatureAI* GetAI_pet_greater_fire_elemental(Creature* pCreature) +{ + return new pet_greater_fire_elemental(pCreature); +} + +enum greater_earth_elemental_spells +{ + SPELL_EARTH_THREAT = 36213, + SPELL_EARTH_EXPLODE = 12374, + SPELL_EARTH_AOE = 33840, +}; + +struct MANGOS_DLL_DECL pet_greater_earth_elemental : public ScriptedPetAI +{ + pet_greater_earth_elemental(Creature* pCreature) : ScriptedPetAI(pCreature) + { + Reset(); + } + + uint32 m_uiEarthThreatTimer; + uint32 m_uiEarthAOETimer; + uint32 m_uiEarthAttackTimer; + Pet* m_pet; + + void Reset() + { + m_pet = (Pet*)m_creature; + m_pet->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE); + m_pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + m_uiEarthThreatTimer = urand(5000,12000); + m_uiEarthAOETimer = urand(10000,30000); + m_uiEarthAttackTimer = urand(2000,8000); + + if(m_pet->GetOwner()->IsPvP()) + m_pet->SetPvP(true); + if(m_pet->GetOwner()->IsFFAPvP()) + m_pet->SetFFAPvP(true); + } + + void UpdatePetAI(const uint32 diff) + { + if (!m_pet->GetOwner() || !m_pet->GetOwner()->isAlive()) + m_pet->ForcedDespawn(); + + if (m_pet->GetOwner()->getVictim() && m_pet->getVictim() != m_pet->GetOwner()->getVictim()) + AttackStart(m_pet->GetOwner()->getVictim()); + + if (m_uiEarthThreatTimer <= diff) + { + DoCastSpellIfCan(m_pet,SPELL_EARTH_THREAT); + m_uiEarthThreatTimer = urand(4000,12000); + } + else m_uiEarthThreatTimer -= diff; + + if (m_uiEarthAOETimer <= diff) + { + if (m_pet->IsWithinDistInMap(m_pet->getVictim(),ATTACK_DISTANCE)) + DoCastSpellIfCan(m_pet,SPELL_EARTH_AOE); + m_uiEarthAOETimer = urand(10000,30000); + } + else m_uiEarthAOETimer -= diff; + + if (m_uiEarthAttackTimer <= diff) + { + DoCastSpellIfCan(m_pet->getVictim(),SPELL_EARTH_EXPLODE); + m_uiEarthAttackTimer = urand(2000,8000); + } + else m_uiEarthAttackTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void UpdatePetOOCAI(const uint32 diff) + { + if (!m_pet->GetOwner() || !m_pet->GetOwner()->isAlive()) + m_pet->ForcedDespawn(); + + if (m_pet->GetOwner() && m_pet->GetOwner()->getVictim()) + { + AttackStart(m_pet->GetOwner()->getVictim()); + } + else if (m_pet->GetOwner()->isInCombat()) + { + AttackStart(m_pet->GetOwner()->getAttackerForHelper()); + } + } +}; + +CreatureAI* GetAI_pet_greater_earth_elemental(Creature* pCreature) +{ + return new pet_greater_earth_elemental(pCreature); +} + +void AddSC_pet_scripts() +{ + AutoScript s; + s.newScript("pet_greater_fire_elemental")->GetAI = &GetAI_pet_greater_fire_elemental; + s.newScript("pet_greater_earth_elemental")->GetAI = &GetAI_pet_greater_earth_elemental; +} diff --git a/scripts/world/spell_scripts.cpp b/scripts/world/spell_scripts.cpp index 2b7eca8644..3ba9a1f48c 100644 --- a/scripts/world/spell_scripts.cpp +++ b/scripts/world/spell_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 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 @@ -22,19 +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 51331 +spell 51332 +spell 51366 +spell 52090 +spell 56099 EndContentData */ #include "precompiled.h" @@ -51,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, @@ -60,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: { @@ -78,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); } @@ -96,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 @@ -139,6 +148,7 @@ enum // quest 6124/6129 SPELL_APPLY_SALVE = 19512, + SPELL_SICKLY_AURA = 19502, NPC_SICKLY_DEER = 12298, NPC_SICKLY_GAZELLE = 12296, @@ -264,11 +274,86 @@ enum SPELL_DARKMENDER_TINCTURE = 52741, SPELL_SUMMON_CORRUPTED_SCARLET = 54415, NPC_CORPSES_RISE_CREDIT_BUNNY = 29398, + + // quest 12659, item 38731 + SPELL_AHUNAES_KNIFE = 52090, + NPC_SCALPS_KILL_CREDIT_BUNNY = 28622, + + // quest 13549 + SPELL_TAILS_UP_GENDER_MASTER = 62110, + SPELL_TAILS_UP_AURA = 62109, + SPELL_FORCE_LEOPARD_SUMMON = 62117, + SPELL_FORCE_BEAR_SUMMON = 62118, + NPC_FROST_LEOPARD = 29327, + NPC_ICEPAW_BEAR = 29319, + NPC_LEOPARD_KILL_CREDIT = 33005, + NPC_BEAR_KILL_CREDIT = 33006, + SAY_ITS_FEMALE = -1000642, + SAY_ITS_MALE = -1000643, + + // quest 9849, item 24501 + SPELL_THROW_GORDAWG_BOULDER = 32001, + NPC_MINION_OF_GUROK = 18181, + + // quest 12589 + SPELL_HIT_APPLE = 51331, + SPELL_MISS_APPLE = 51332, + SPELL_MISS_APPLE_HIT_BIRD = 51366, + SPELL_APPLE_FALLS_TO_GROUND = 51371, + NPC_APPLE = 28053, + NPC_LUCKY_WILHELM = 28054, + NPC_DROSTAN = 28328, + SAY_LUCKY_HIT_1 = -1000644, + SAY_LUCKY_HIT_2 = -1000645, + SAY_LUCKY_HIT_3 = -1000646, + SAY_LUCKY_HIT_APPLE = -1000647, + SAY_DROSTAN_GOT_LUCKY_1 = -1000648, + SAY_DROSTAN_GOT_LUCKY_2 = -1000649, + SAY_DROSTAN_HIT_BIRD_1 = -1000650, + SAY_DROSTAN_HIT_BIRD_2 = -1000651, + + // quest 11314, item 33606 + SPELL_LURIELLES_PENDANT = 43340, + NPC_CHILL_NYMPH = 23678, + NPC_LURIELLE = 24117, + FACTION_FRIENDLY = 35, + SAY_FREE_1 = -1000781, + SAY_FREE_2 = -1000782, + SAY_FREE_3 = -1000783, + + // 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: { @@ -282,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; @@ -295,7 +380,7 @@ bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) { if (Player* pPlayer = (Player*)pAura->GetCaster()) { - pPlayer->KilledMonsterCredit(NPC_FALLEN_HERO_SPIRIT_PROXY, pCreature->GetGUID()); + pPlayer->KilledMonsterCredit(NPC_FALLEN_HERO_SPIRIT_PROXY, pCreature->GetObjectGuid()); pCreature->ForcedDespawn(); } } @@ -329,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; @@ -374,7 +459,7 @@ bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) { if (pAura->GetEffIndex() != EFFECT_INDEX_0) return true; - + if (Unit* pCaster = pAura->GetCaster()) DoScriptText(SAY_SPECIMEN, pCaster); @@ -393,31 +478,58 @@ bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) } case SPELL_ENRAGE: { - if (pAura->GetTarget()->GetTypeId() != TYPEID_UNIT || !bApply) + if (!bApply || pAura->GetTarget()->GetTypeId() != TYPEID_UNIT) return false; - if (Creature* pCreature = GetClosestCreatureWithEntry(pAura->GetTarget(), NPC_DARKSPINE_MYRMIDON, 25.0f)) + Creature* pTarget = (Creature*)pAura->GetTarget(); + + if (Creature* pCreature = GetClosestCreatureWithEntry(pTarget, NPC_DARKSPINE_MYRMIDON, 25.0f)) { - dynamic_cast(pAura->GetTarget())->AI()->AttackStart(pCreature); + pTarget->AI()->AttackStart(pCreature); return true; } - if (Creature* pCreature = GetClosestCreatureWithEntry(pAura->GetTarget(), NPC_DARKSPINE_SIREN, 25.0f)) + if (Creature* pCreature = GetClosestCreatureWithEntry(pTarget, NPC_DARKSPINE_SIREN, 25.0f)) { - dynamic_cast(pAura->GetTarget())->AI()->AttackStart(pCreature); + pTarget->AI()->AttackStart(pCreature); return true; } return false; } + case SPELL_SHROUD_OF_DEATH: + case SPELL_SPIRIT_PARTICLES: + { + Creature* pCreature = (Creature*)pAura->GetTarget(); + + if (!pCreature || (pCreature->GetEntry() != NPC_FRANCLORN_FORGEWRIGHT && pCreature->GetEntry() != NPC_GAERIYAN && pCreature->GetEntry() != NPC_GANJO)) + return false; + + if (bApply) + pCreature->m_AuraFlags |= UNIT_AURAFLAG_ALIVE_INVISIBLE; + else + 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: { @@ -440,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; } @@ -475,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; @@ -492,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; @@ -500,7 +616,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE } pCreatureTarget->SetStandState(UNIT_STAND_STATE_STAND); - pCreatureTarget->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_WORK); + pCreatureTarget->HandleEmote(EMOTE_STATE_WORK); break; } } @@ -517,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; @@ -596,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; @@ -663,11 +780,11 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { if (uiEffIndex == EFFECT_INDEX_0) { - if (pCreatureTarget->isDead()) + if (pCreatureTarget->IsCorpse()) { 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; @@ -680,7 +797,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { pCaster->CastSpell(pCreatureTarget, pSpell->Id, true); - if (Pet* pPet = pCaster->FindGuardianWithEntry(pSpell->EffectMiscValue[uiEffIndex])) + if (Pet* pPet = pCaster->FindGuardianWithEntry(pSpell->GetEffectMiscValue(SpellEffectIndex(uiEffIndex)))) pPet->CastSpell(pCaster, SPELL_REPROGRAM_KILL_CREDIT, true); pCreatureTarget->ForcedDespawn(); @@ -694,8 +811,8 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { pCreatureTarget->CastSpell(pCaster, SPELL_GREENGILL_SLAVE_FREED, true); - if (pCreatureTarget->GetTypeId() == TYPEID_UNIT) - dynamic_cast(pCreatureTarget)->UpdateEntry(NPC_FREED_GREENGILL_SLAVE); // Freed Greengill Slave + // Freed Greengill Slave + pCreatureTarget->UpdateEntry(NPC_FREED_GREENGILL_SLAVE); pCreatureTarget->CastSpell(pCreatureTarget, SPELL_ENRAGE, true); @@ -705,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: { @@ -714,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; @@ -735,6 +852,206 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE } return true; } + case SPELL_AHUNAES_KNIFE: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() != TYPEID_PLAYER) + return true; + + ((Player*)pCaster)->KilledMonsterCredit(NPC_SCALPS_KILL_CREDIT_BUNNY); + pCreatureTarget->ForcedDespawn(); + return true; + } + return true; + } + case SPELL_TAILS_UP_GENDER_MASTER: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + bool isMale = urand(0, 1); + Player* pPlayer = pCreatureTarget->GetLootRecipient(); + + if (!pPlayer) + return true; + + if (isMale) + DoScriptText(SAY_ITS_MALE, pCreatureTarget, pPlayer); + else + DoScriptText(SAY_ITS_FEMALE, pCreatureTarget, pPlayer); + + switch (pCreatureTarget->GetEntry()) + { + case NPC_FROST_LEOPARD: + { + if (isMale) + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_TAILS_UP_AURA, true); + else + { + pPlayer->KilledMonsterCredit(NPC_LEOPARD_KILL_CREDIT, pCreatureTarget->GetObjectGuid()); + pCreatureTarget->CastSpell(pPlayer, SPELL_FORCE_LEOPARD_SUMMON, true); + pCreatureTarget->ForcedDespawn(); + } + + break; + } + case NPC_ICEPAW_BEAR: + { + if (isMale) + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_TAILS_UP_AURA, true); + else + { + pPlayer->KilledMonsterCredit(NPC_BEAR_KILL_CREDIT, pCreatureTarget->GetObjectGuid()); + pCreatureTarget->CastSpell(pPlayer, SPELL_FORCE_BEAR_SUMMON, true); + pCreatureTarget->ForcedDespawn(); + } + + break; + } + } + return true; + } + return true; + } + case SPELL_THROW_GORDAWG_BOULDER: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + 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); + } + + if (pCreatureTarget->getVictim()) + { + pCaster->DealDamage(pCreatureTarget, pCreatureTarget->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + return true; + } + + // If not in combat, no xp or loot + pCreatureTarget->SetDeathState(JUST_DIED); + pCreatureTarget->SetHealth(0); + return true; + } + return true; + } + case SPELL_HIT_APPLE: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() == TYPEID_PLAYER) + ((Player*)pCaster)->KilledMonsterCredit(pCreatureTarget->GetEntry(), pCreatureTarget->GetObjectGuid()); + + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_APPLE_FALLS_TO_GROUND, false); + + if (Creature* pLuckyWilhelm = GetClosestCreatureWithEntry(pCreatureTarget, NPC_LUCKY_WILHELM, 2 * INTERACTION_DISTANCE)) + DoScriptText(SAY_LUCKY_HIT_APPLE, pLuckyWilhelm); + } + return true; + } + case SPELL_MISS_APPLE: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + switch (urand(1, 3)) + { + case 1: DoScriptText(SAY_LUCKY_HIT_1, pCreatureTarget); break; + case 2: DoScriptText(SAY_LUCKY_HIT_2, pCreatureTarget); break; + case 3: DoScriptText(SAY_LUCKY_HIT_3, pCreatureTarget); break; + } + + 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; + } + case SPELL_MISS_APPLE_HIT_BIRD: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + 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); + } + return true; + } + case SPELL_LURIELLES_PENDANT: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() != NPC_CHILL_NYMPH || pCaster->GetTypeId() != TYPEID_PLAYER) + return true; + + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_FREE_1, pCreatureTarget); break; + case 1: DoScriptText(SAY_FREE_2, pCreatureTarget); break; + case 2: DoScriptText(SAY_FREE_3, pCreatureTarget); break; + } + + ((Player*)pCaster)->KilledMonsterCredit(NPC_LURIELLE); + pCreatureTarget->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + pCreatureTarget->DeleteThreatList(); + pCreatureTarget->AttackStop(true); + pCreatureTarget->GetMotionMaster()->MoveFleeing(pCaster, 7); + pCreatureTarget->ForcedDespawn(7 * IN_MILLISECONDS); + } + return true; + } + case SPELL_EXPOSE_RAZORTHORN_ROOT: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + 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; + + 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; + } } return false; @@ -742,16 +1059,12 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE void AddSC_spell_scripts() { - Script* newscript; - - newscript = new Script; - newscript->Name = "spell_dummy_go"; - newscript->pEffectDummyGameObj = &EffectDummyGameObj_spell_dummy_go; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name = "spell_dummy_npc"; - newscript->pEffectDummyCreature = &EffectDummyCreature_spell_dummy_npc; - newscript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_npc; - newscript->RegisterSelf(); + AutoScript s; + + s.newScript("spell_dummy_go"); + s->pEffectDummyGO = &EffectDummyGameObj_spell_dummy_go; + + s.newScript("spell_dummy_npc"); + s->pEffectDummyNPC = &EffectDummyCreature_spell_dummy_npc; + s->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_npc; } diff --git a/scripts/world/world_map_scripts.cpp b/scripts/world/world_map_scripts.cpp new file mode 100644 index 0000000000..eb1d2ea1e9 --- /dev/null +++ b/scripts/world/world_map_scripts.cpp @@ -0,0 +1,217 @@ +/* Copyright (C) 2006 - 2013 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: world_map_scripts +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 +{ + world_map_eastern_kingdoms(Map* pMap) : ScriptedMap(pMap) {} + + void OnCreatureCreate(Creature* pCreature) override + { + 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) +{ + return new world_map_eastern_kingdoms(pMap); +} + +/* ********************************************************* + * KALIMDOR + */ +struct MANGOS_DLL_DECL world_map_kalimdor : public ScriptedMap +{ + world_map_kalimdor(Map* pMap) : ScriptedMap(pMap) { Initialize(); } + + uint8 m_uiMurkdeepAdds_KilledAddCount; + + void Initialize() override + { + m_uiMurkdeepAdds_KilledAddCount = 0; + } + + void OnCreatureCreate(Creature* pCreature) override + { + if (pCreature->GetEntry() == NPC_MURKDEEP) + m_mNpcEntryGuidStore[NPC_MURKDEEP] = pCreature->GetObjectGuid(); + } + + void OnCreatureDeath(Creature* pCreature) override + { + switch (pCreature->GetEntry()) + { + case NPC_GREYMIST_COASTRUNNNER: + if (pCreature->IsTemporarySummon()) // Only count the ones summoned for Murkdeep quest + { + ++m_uiMurkdeepAdds_KilledAddCount; + + // 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) +{ + return new world_map_kalimdor(pMap); +} + +/* ********************************************************* + * OUTLAND + */ +struct MANGOS_DLL_DECL world_map_outland : public ScriptedMap +{ + world_map_outland(Map* pMap) : ScriptedMap(pMap) { Initialize(); } + + uint8 m_uiEmissaryOfHate_KilledAddCount; + + void Initialize() override + { + m_uiEmissaryOfHate_KilledAddCount = 0; + } + + void OnCreatureCreate(Creature* pCreature) override + { + if (pCreature->GetEntry() == NPC_EMISSARY_OF_HATE) + m_mNpcEntryGuidStore[NPC_EMISSARY_OF_HATE] = pCreature->GetObjectGuid(); + } + + void OnCreatureDeath(Creature* pCreature) override + { + switch (pCreature->GetEntry()) + { + case NPC_IRESPEAKER: + case NPC_UNLEASHED_HELLION: + if (!GetSingleCreatureFromStorage(NPC_EMISSARY_OF_HATE, true)) + { + ++m_uiEmissaryOfHate_KilledAddCount; + if (m_uiEmissaryOfHate_KilledAddCount == 6) + { + 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; + } + } + break; + } + } + + void SetData(uint32 /*uiType*/, uint32 /*uiData*/) {} +}; + +InstanceData* GetInstanceData_world_map_outland(Map* pMap) +{ + return new world_map_outland(pMap); +} + +/* ********************************************************* + * NORTHREND + */ +struct MANGOS_DLL_DECL world_map_northrend : public ScriptedMap +{ + world_map_northrend(Map* pMap) : ScriptedMap(pMap) {} + + void SetData(uint32 /*uiType*/, uint32 /*uiData*/) {} +}; + +InstanceData* GetInstanceData_world_map_northrend(Map* pMap) +{ + return new world_map_northrend(pMap); +} + +void AddSC_world_map_scripts() +{ + AutoScript s; + + s.newScript("world_map_eastern_kingdoms"); + s->GetInstanceData = &GetInstanceData_world_map_eastern_kingdoms; + + s.newScript("world_map_kalimdor"); + s->GetInstanceData = &GetInstanceData_world_map_kalimdor; + + s.newScript("world_map_outland"); + s->GetInstanceData = &GetInstanceData_world_map_outland; + + s.newScript("world_map_northrend"); + s->GetInstanceData = &GetInstanceData_world_map_northrend; +} diff --git a/scripts/world/world_map_scripts.h b/scripts/world/world_map_scripts.h new file mode 100644 index 0000000000..27d41b262d --- /dev/null +++ b/scripts/world/world_map_scripts.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 + * 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_R2.h b/sd2_revision_R2.h new file mode 100644 index 0000000000..64642e3def --- /dev/null +++ b/sd2_revision_R2.h @@ -0,0 +1,4 @@ +#ifndef __SD2_REVISION_R2_H__ +#define __SD2_REVISION_R2_H__ + #define SD2_REVISION_R2 "0711" +#endif // __SD2_REVISION_R2_H__ diff --git a/sd2_revision_nr.h b/sd2_revision_nr.h new file mode 100644 index 0000000000..b189c75f6d --- /dev/null +++ b/sd2_revision_nr.h @@ -0,0 +1,4 @@ +#ifndef __SD2_REVISION_NR_H__ +#define __SD2_REVISION_NR_H__ + #define SD2_REVISION_NR "3035" +#endif // __SD2_REVISION_NR_H__ diff --git a/sd2_revision_sql.h b/sd2_revision_sql.h new file mode 100644 index 0000000000..997c333551 --- /dev/null +++ b/sd2_revision_sql.h @@ -0,0 +1,5 @@ +#ifndef __SD2_REVISION_SQL_H__ +#define __SD2_REVISION_SQL_H__ + #define REVISION_DB_SCRIPTDEV2 "required__scriptdev2" + #define REVISION_DB_SD2_MANGOS "required__mangos" +#endif // __SD2_REVISION_SQL_H__ diff --git a/sql/Makefile.am b/sql/Makefile.am deleted file mode 100644 index 7a664de989..0000000000 --- a/sql/Makefile.am +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse -SUBDIRS = Updates - -## Change installation location -# datadir = scriptdev2/sql -pkgdatadir = $(datadir)/scriptdev2/sql - -## Files to be installed -# Install basic SQL files to datadir -pkgdata_DATA = \ - mangos_scriptname_full.sql \ - scriptdev2_create_database.sql \ - scriptdev2_create_structure_mysql.sql \ - scriptdev2_create_structure_pgsql.sql \ - scriptdev2_script_full.sql diff --git a/sql/Updates/0.0.1/Makefile.am b/sql/Updates/0.0.1/Makefile.am deleted file mode 100644 index eed44c8ff9..0000000000 --- a/sql/Updates/0.0.1/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse - -## Change installation location -# datadir = scriptdev2/sql/updates/0.0.1 -pkgdatadir = $(datadir)/scriptdev2/sql/updates/0.0.1 - -## Files to be installed -# Install basic SQL files to datadir -pkgdata_DATA = \ - 09_BraveWindfeather.sql \ - 11_SilvaFilnaveth.sql \ - 27_Vaelastraz.sql diff --git a/sql/Updates/0.0.2/Makefile.am b/sql/Updates/0.0.2/Makefile.am deleted file mode 100644 index 5e652b1822..0000000000 --- a/sql/Updates/0.0.2/Makefile.am +++ /dev/null @@ -1,270 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse - -## Change installation location -# datadir = scriptdev2/sql/updates/0.0.2 -pkgdatadir = $(datadir)/scriptdev2/sql/updates/0.0.2 - -## Files to be installed -# Install basic SQL files to datadir -pkgdata_DATA = \ - r56.sql \ - r59.sql \ - r63.sql \ - r65.sql \ - r72.sql \ - r78.sql \ - r81.sql \ - r91.sql \ - r92.sql \ - r97.sql \ - r108.sql \ - r110.sql \ - r121.sql \ - r123.sql \ - r124.sql \ - r125.sql \ - r128.sql \ - r131.sql \ - r134.sql \ - r136.sql \ - r139.sql \ - r142.sql \ - r144.sql \ - r145.sql \ - r149.sql \ - r150.sql \ - r152.sql \ - r153.sql \ - r157.sql \ - r161.sql \ - r163.sql \ - r169.sql \ - r170.sql \ - r171.sql \ - r172.sql \ - r174.sql \ - r176.sql \ - r177.sql \ - r178.sql \ - r181.sql \ - r182.sql \ - r183.sql \ - r184.sql \ - r186.sql \ - r187.sql \ - r189.sql \ - r191.sql \ - r192.sql \ - r197.sql \ - r204.sql \ - r206.sql \ - r211.sql \ - r213.sql \ - r214.sql \ - r215.sql \ - r218.sql \ - r219.sql \ - r221_scriptdev2.sql \ - r227_scriptdev2.sql \ - r230_mangos.sql \ - r234_mangos.sql \ - r237_mangos.sql \ - r238_mangos.sql \ - r239_mangos.sql \ - r240_scriptdev2.sql \ - r241_mangos.sql \ - r242_mangos.sql \ - r243_mangos.sql \ - r249_mangos.sql \ - r250_mangos.sql \ - r253_mangos.sql \ - r255_mangos.sql \ - r256_mangos.sql \ - r257_mangos.sql \ - r258_mangos.sql \ - r260_mangos.sql \ - r261_mangos.sql \ - r262_mangos.sql \ - r263_mangos.sql \ - r264_mangos.sql \ - r265_mangos.sql \ - r269_mangos.sql \ - r270_mangos.sql \ - r271_mangos.sql \ - r272_mangos.sql \ - r273_mangos.sql \ - r274_mangos.sql \ - r275_mangos.sql \ - r281_scriptdev2.sql \ - r282_mangos.sql \ - r286_mangos.sql \ - r289_mangos.sql \ - r291_mangos.sql \ - r295_mangos.sql \ - r297_mangos.sql \ - r298_scriptdev2.sql \ - r299_scriptdev2.sql \ - r304_mangos.sql \ - r306_scriptdev2.sql \ - r307_mangos.sql \ - r308_mangos.sql \ - r309_mangos.sql \ - r311_mangos.sql \ - r312_mangos.sql \ - r318_mangos.sql \ - r324_mangos.sql \ - r327_mangos.sql \ - r332_scriptdev2.sql \ - r333_mangos.sql \ - r334_mangos.sql \ - r336_mangos.sql \ - r352_mangos.sql \ - r355_mangos.sql \ - r358_mangos.sql \ - r364_mangos.sql \ - r367_mangos.sql \ - r368_mangos.sql \ - r369_mangos.sql \ - r374_mangos.sql \ - r386_mangos.sql \ - r417_mangos.sql \ - r428_mangos.sql \ - r431_mangos.sql \ - r444_mangos.sql \ - r445_mangos.sql \ - r446_mangos.sql \ - r448_scriptdev2.sql \ - r462_mangos.sql \ - r465_mangos.sql \ - r467_mangos.sql \ - r473_mangos.sql \ - r476_mangos.sql \ - r477_mangos.sql \ - r479_mangos.sql \ - r482_mangos.sql \ - r484_mangos.sql \ - r486_mangos.sql \ - r487_mangos.sql \ - r494_mangos.sql \ - r501_mangos.sql \ - r513_mangos.sql \ - r514_mangos.sql \ - r515_mangos.sql \ - r516_mangos.sql \ - r517_mangos.sql \ - r518_mangos.sql \ - r519_mangos.sql \ - r520_mangos.sql \ - r521_mangos.sql \ - r522_mangos.sql \ - r526_mangos.sql \ - r528_mangos.sql \ - r533_mangos.sql \ - r538_scriptdev2.sql \ - r547_mangos.sql \ - r554_mangos.sql \ - r555_mangos.sql \ - r575_mangos.sql \ - r576_mangos.sql \ - r578_mangos.sql \ - r584_mangos.sql \ - r590_mangos.sql \ - r591_mangos.sql \ - r593_mangos.sql \ - r594_mangos.sql \ - r596_mangos.sql \ - r610_mangos.sql \ - r615_scriptdev2.sql \ - r617_mangos.sql \ - r621_mangos.sql \ - r628_mangos.sql \ - r632_mangos.sql \ - r633_mangos.sql \ - r634_scriptdev2.sql \ - r636_mangos.sql \ - r637_mangos.sql \ - r638_mangos.sql \ - r639_mangos.sql \ - r642_mangos.sql \ - r643_mangos.sql \ - r646_mangos.sql \ - r647_scriptdev2.sql \ - r656_scriptdev2.sql \ - r658_mangos.sql \ - r659_mangos.sql \ - r681_scriptdev2.sql \ - r695_scriptdev2.sql \ - r699_scriptdev2_script_texts.sql \ - r700_scriptdev2_script_texts.sql \ - r701_scriptdev2_script_texts.sql \ - r702_scriptdev2_script_texts.sql \ - r703_scriptdev2_script_texts.sql \ - r704_scriptdev2_script_texts.sql \ - r705_scriptdev2_script_texts.sql \ - r706_mangos.sql \ - r707_scriptdev2_script_texts.sql \ - r709_scriptdev2_script_texts.sql \ - r710_scriptdev2_script_texts.sql \ - r713_scriptdev2_script_texts.sql \ - r715_scriptdev2_script_texts.sql \ - r725_scriptdev2_script_texts.sql \ - r726_scriptdev2_script_texts.sql \ - r727_scriptdev2_script_texts.sql \ - r728_scriptdev2_script_texts.sql \ - r729_scriptdev2_script_texts.sql \ - r730_scriptdev2_script_texts.sql \ - r732_scriptdev2_script_texts.sql \ - r735_mangos.sql \ - r735_scriptdev2_script_texts.sql \ - r740_mangos.sql \ - r740_scriptdev2_script_texts.sql \ - r743_mangos.sql \ - r743_scriptdev2_script_texts.sql \ - r745_scriptdev2_script_texts.sql \ - r747_scriptdev2_script_texts.sql \ - r751_scriptdev2_script_texts.sql \ - r755_scriptdev2_script_texts.sql \ - r757_mangos.sql \ - r757_scriptdev2_script_texts.sql \ - r764_mangos.sql \ - r764_scriptdev2_script_texts.sql \ - r766_mangos.sql \ - r766_scriptdev2_script_texts.sql \ - r767_mangos.sql \ - r768_scriptdev2_script_texts.sql \ - r769_mangos.sql \ - r771_scriptdev2_script_texts.sql \ - r772_mangos.sql \ - r777_mangos.sql \ - r778_mangos.sql \ - r779_scriptdev2_script_texts.sql \ - r779_mangos.sql \ - r782_mangos.sql \ - r783_mangos.sql \ - r783_scriptdev2_script_texts.sql \ - r790_mangos.sql \ - r794_mangos.sql \ - r796_scriptdev2_script_texts.sql \ - r802_mangos.sql \ - r804_mangos.sql \ - r804_scriptdev2_script_texts.sql \ - r809_mangos.sql \ - r809_scriptdev2_script_texts.sql \ - r810_mangos.sql diff --git a/sql/Updates/0.0.3/Makefile.am b/sql/Updates/0.0.3/Makefile.am deleted file mode 100644 index 876f4f9936..0000000000 --- a/sql/Updates/0.0.3/Makefile.am +++ /dev/null @@ -1,304 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse - -## Change installation location -# datadir = scriptdev2/sql/updates/0.0.3 -pkgdatadir = $(datadir)/scriptdev2/sql/updates/0.0.3 - -## Files to be installed -# Install basic SQL files to datadir -pkgdata_DATA = \ - r814_scriptdev2_eventai_scripts.sql \ - r820_scriptdev2_script_texts.sql \ - r822_mangos.sql \ - r822_scriptdev2_script_texts.sql \ - r823_scriptdev2_script_texts.sql \ - r824_mangos.sql \ - r824_scriptdev2_script_texts.sql \ - r825_scriptdev2_script_texts.sql \ - r826_scriptdev2.sql \ - r827_mangos.sql \ - r828_mangos.sql \ - r834_mangos.sql \ - r834_scriptdev2_script_texts.sql \ - r835_mangos.sql \ - r845_mangos.sql \ - r846_scriptdev2.sql \ - r847_scriptdev2_script_texts.sql \ - r848_scriptdev2_script_texts.sql \ - r849_scriptdev2_script_texts.sql \ - r850_mangos.sql \ - r851_scriptdev2_script_texts.sql \ - r852_scriptdev2_script_texts.sql \ - r854_scriptdev2_script_texts.sql \ - r855_scriptdev2_script_texts.sql \ - r856_scriptdev2_script_texts.sql \ - r860_scriptdev2_script_texts.sql \ - r862_scriptdev2_script_texts.sql \ - r863_mangos.sql \ - r872_mangos.sql \ - r883_mangos.sql \ - r895_mangos.sql \ - r900_mangos.sql \ - r903_mangos.sql \ - r903_scriptdev2_script_texts.sql \ - r907_mangos.sql \ - r907_scriptdev2_script_texts.sql \ - r909_mangos.sql \ - r910_scriptdev2_script_texts.sql \ - r912_mangos.sql \ - r912_scriptdev2_script_texts.sql \ - r916_mangos.sql \ - r916_scriptdev2_script_texts.sql \ - r919_mangos.sql \ - r922_scriptdev2_script_waypoint.sql \ - r924_scriptdev2_script_waypoint.sql \ - r936_scriptdev2_script_waypoint.sql \ - r937_mangos.sql \ - r937_scriptdev2_script_texts.sql \ - r937_scriptdev2_script_waypoint.sql \ - r939_scriptdev2_script_texts.sql \ - r940_mangos.sql \ - r941_mangos.sql \ - r945_mangos.sql \ - r945_scriptdev2_script_texts.sql \ - r945_scriptdev2_script_waypoint.sql \ - r947_mangos.sql \ - r949_scriptdev2_script_waypoint.sql \ - r951_scriptdev2_script_waypoint.sql \ - r953_scriptdev2_script_waypoint.sql \ - r956_scriptdev2.sql \ - r963_mangos.sql \ - r964_mangos.sql \ - r965_mangos.sql \ - r965_scriptdev2.sql \ - r972_mangos.sql \ - r972_scriptdev2.sql \ - r973_mangos.sql \ - r973_scriptdev2_script_waypoint.sql \ - r975_mangos.sql \ - r975_scriptdev2.sql \ - r976_mangos.sql \ - r976_scriptdev2.sql \ - r978_mangos.sql \ - r979_mangos.sql \ - r979_scriptdev2_script_texts.sql \ - r980_mangos.sql \ - r982_mangos.sql \ - r982_scriptdev2_script_texts.sql \ - r989_mangos.sql \ - r990_mangos.sql \ - r991_scriptdev2.sql \ - r992_mangos.sql \ - r993_mangos.sql \ - r993_scriptdev2_script_texts.sql \ - r995_mangos.sql \ - r995_scriptdev2.sql \ - r997_mangos.sql \ - r998_mangos.sql \ - r998_scriptdev2_script_texts.sql \ - r1002_scriptdev2.sql \ - r1006_scriptdev2.sql \ - r1008_mangos.sql \ - r1008_scriptdev2.sql \ - r1009_scriptdev2.sql \ - r1010_mangos.sql \ - r1010_scriptdev2.sql \ - r1012_mangos.sql \ - r1012_scriptdev2.sql \ - r1014_mangos.sql \ - r1014_scriptdev2.sql \ - r1016_scriptdev2.sql \ - r1023_scriptdev2.sql \ - r1025_mangos.sql \ - r1030_scriptdev2.sql \ - r1032_mangos.sql \ - r1032_scriptdev2.sql \ - r1039_mangos.sql \ - r1056_scriptdev2.sql \ - r1058_mangos.sql \ - r1058_scriptdev2.sql \ - r1062_mangos.sql \ - r1067_mangos.sql \ - r1068_mangos.sql \ - r1068_scriptdev2.sql \ - r1069_mangos.sql \ - r1073_mangos.sql \ - r1074_scriptdev2.sql \ - r1075_mangos.sql \ - r1080_scriptdev2.sql \ - r1082_mangos.sql \ - r1098_scriptdev2.sql \ - r1099_mangos.sql \ - r1100_mangos.sql \ - r1103_mangos.sql \ - r1104_scriptdev2.sql \ - r1106_mangos.sql \ - r1112_mangos.sql \ - r1116_mangos.sql \ - r1119_mangos.sql \ - r1119_scriptdev2.sql \ - r1120_scriptdev2.sql \ - r1121_mangos.sql \ - r1121_scriptdev2.sql \ - r1123_scriptdev2.sql \ - r1128_mangos.sql \ - r1129_mangos.sql \ - r1129_scriptdev2.sql \ - r1131_mangos.sql \ - r1136_mangos.sql \ - r1136_scriptdev2.sql \ - r1140_scriptdev2.sql \ - r1141_mangos.sql \ - r1145_scriptdev2.sql \ - r1146_scriptdev2.sql \ - r1149_scriptdev2.sql \ - r1152_scriptdev2.sql \ - r1154_mangos.sql \ - r1155_mangos.sql \ - r1169_mangos.sql \ - r1169_scriptdev2.sql \ - r1171_scriptdev2.sql \ - r1173_scriptdev2.sql \ - r1180_mangos.sql \ - r1184_mangos.sql \ - r1197_mangos.sql \ - r1199_mangos.sql \ - r1202_mangos.sql \ - r1202_scriptdev2.sql \ - r1207_mangos.sql \ - r1207_scriptdev2.sql \ - r1210_mangos.sql \ - r1212_mangos.sql \ - r1212_scriptdev2.sql \ - r1215_mangos.sql \ - r1215_scriptdev2.sql \ - r1218_scriptdev2.sql \ - r1221_mangos.sql \ - r1221_scriptdev2.sql \ - r1222_scriptdev2.sql \ - r1234_mangos.sql \ - r1241_scriptdev2.sql \ - r1242_mangos.sql \ - r1242_scriptdev2.sql \ - r1243_mangos.sql \ - r1243_scriptdev2.sql \ - r1249_mangos.sql \ - r1249_scriptdev2.sql \ - r1250_mangos.sql \ - r1250_scriptdev2.sql \ - r1251_scriptdev2.sql \ - r1257_scriptdev2.sql \ - r1258_mangos.sql \ - r1258_scriptdev2.sql \ - r1260_scriptdev2.sql \ - r1261_mangos.sql \ - r1263_mangos.sql \ - r1265_mangos.sql \ - r1265_scriptdev2.sql \ - r1266_mangos.sql \ - r1266_scriptdev2.sql \ - r1280_mangos.sql \ - r1280_scriptdev2.sql \ - r1281_mangos.sql \ - r1282_mangos.sql \ - r1283_mangos.sql \ - r1299_scriptdev2.sql \ - r1300_mangos.sql \ - r1307_mangos.sql \ - r1317_mangos.sql \ - r1317_scriptdev2.sql \ - r1321_mangos.sql \ - r1321_scriptdev2.sql \ - r1322_scriptdev2.sql \ - r1326_scriptdev2.sql \ - r1333_mangos.sql \ - r1334_mangos.sql \ - r1335_scriptdev2.sql \ - r1336_mangos.sql \ - r1336_scriptdev2.sql \ - r1341_scriptdev2.sql \ - r1351_mangos.sql \ - r1351_scriptdev2.sql \ - r1352_mangos.sql \ - r1352_scriptdev2.sql \ - r1354_scriptdev2.sql \ - r1358_mangos.sql \ - r1359_mangos.sql \ - r1359_scriptdev2.sql \ - r1367_mangos.sql \ - r1368_mangos.sql \ - r1369_mangos.sql \ - r1370_mangos.sql \ - r1371_scriptdev2.sql \ - r1374_mangos.sql \ - r1374_scriptdev2.sql \ - r1378_mangos.sql \ - r1378_scriptdev2.sql \ - r1379_mangos.sql \ - r1379_scriptdev2.sql \ - r1380_mangos.sql \ - r1380_scriptdev2.sql \ - r1382_mangos.sql \ - r1383_scriptdev2.sql \ - r1384_scriptdev2.sql \ - r1385_mangos.sql \ - r1385_scriptdev2.sql \ - r1386_mangos.sql \ - r1386_scriptdev2.sql \ - r1388_mangos.sql \ - r1388_scriptdev2.sql \ - r1391_mangos.sql \ - r1391_scriptdev2.sql \ - r1392_mangos.sql \ - r1392_scriptdev2.sql \ - r1394_mangos.sql \ - r1394_scriptdev2.sql \ - r1405_mangos.sql \ - r1405_scriptdev2.sql \ - r1406_mangos.sql \ - r1408_mangos.sql \ - r1408_scriptdev2.sql \ - r1409_mangos.sql \ - r1409_scriptdev2.sql \ - r1410_mangos.sql \ - r1410_scriptdev2.sql \ - r1411_mangos.sql \ - r1411_scriptdev2.sql \ - r1412_mangos.sql \ - r1412_scriptdev2.sql \ - r1413_mangos.sql \ - r1413_scriptdev2.sql \ - r1414_mangos.sql \ - r1414_scriptdev2.sql \ - r1415_mangos.sql \ - r1417_mangos.sql \ - r1418_scriptdev2.sql \ - r1419_mangos.sql \ - r1421_scriptdev2.sql \ - r1422_mangos.sql \ - r1422_scriptdev2.sql \ - r1428_scriptdev2.sql \ - r1430_mangos.sql \ - r1433_mangos.sql \ - r1435_mangos.sql \ - r1436_mangos.sql \ - r1437_scriptdev2.sql \ - r1439_scriptdev2.sql \ - r1441_mangos.sql diff --git a/sql/Updates/0.0.4/Makefile.am b/sql/Updates/0.0.4/Makefile.am deleted file mode 100644 index f9e7ebf10d..0000000000 --- a/sql/Updates/0.0.4/Makefile.am +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse - -## Change installation location -# datadir = scriptdev2/sql/updates/0.0.4 -pkgdatadir = $(datadir)/scriptdev2/sql/updates/0.0.4 - -## Files to be installed -# Install basic SQL files to datadir -pkgdata_DATA = \ - r1453_scriptdev2.sql \ - r1457_scriptdev2.sql \ - r1459_mangos.sql \ - r1460_mangos.sql \ - r1461_mangos.sql \ - r1461_scriptdev2.sql \ - r1463_mangos.sql \ - r1465_scriptdev2.sql \ - r1466_scriptdev2.sql \ - r1470_scriptdev2.sql \ - r1473_scriptdev2.sql \ - r1474_scriptdev2.sql \ - r1476_mangos.sql \ - r1476_scriptdev2.sql \ - r1478_scriptdev2.sql \ - r1486_mangos.sql \ - r1490_scriptdev2.sql \ - r1492_mangos.sql \ - r1493_scriptdev2.sql \ - r1494_mangos.sql \ - r1496_mangos.sql \ - r1498_mangos.sql \ - r1500_mangos.sql \ - r1502_mangos.sql \ - r1503_scriptdev2.sql \ - r1504_scriptdev2.sql \ - r1506_scriptdev2.sql \ - r1508_mangos.sql \ - r1513_scriptdev2.sql \ - r1516_mangos.sql \ - r1516_scriptdev2.sql \ - r1517_scriptdev2.sql \ - r1519_mangos.sql \ - r1523_mangos.sql \ - r1524_scriptdev2.sql \ - r1525_mangos.sql \ - r1525_scriptdev2.sql \ - r1531_mangos.sql \ - r1536_mangos.sql \ - r1538_mangos.sql \ - r1540_mangos.sql \ - r1540_scriptdev2.sql \ - r1542_mangos.sql diff --git a/sql/Updates/Makefile.am b/sql/Updates/Makefile.am deleted file mode 100644 index a566f8618c..0000000000 --- a/sql/Updates/Makefile.am +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (C) 2005-2009 MaNGOS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Process this file with automake to produce Makefile.in - -## Sub-directories to parse - -## Change installation location -# datadir = scriptdev2/sql/updates -pkgdatadir = $(datadir)/scriptdev2/sql/updates - -## Files to be installed -# Install basic SQL files to datadir -pkgdata_DATA = \ - r1543_scriptdev2.sql \ - r1544_mangos.sql \ - r1545_scriptdev2.sql \ - r1548_scriptdev2.sql \ - r1549_mangos.sql \ - r1549_scriptdev2.sql \ - r1551_mangos.sql \ - r1554_mangos.sql \ - r1554_scriptdev2.sql \ - r1555_scriptdev2.sql \ - r1556_mangos.sql \ - r1557_scriptdev2.sql \ - r1563_mangos.sql \ - r1567_mangos.sql \ - r1567_scriptdev2.sql \ - r1570_scriptdev2.sql \ - r1577_mangos.sql \ - r1577_scriptdev2.sql \ - r1583_scriptdev2.sql \ - r1584_scriptdev2.sql \ - r1587_scriptdev2.sql \ - r1589_mangos.sql \ - r1590_mangos.sql \ - r1591_mangos.sql \ - r1592_mangos.sql \ - r1593_mangos.sql \ - r1594_mangos.sql \ - r1595_mangos.sql \ - r1596_mangos.sql \ - r1599_mangos.sql \ - r1600_scriptdev2.sql \ - r1602_mangos.sql \ - r1604_mangos.sql \ - r1605_mangos.sql \ - r1607_mangos.sql \ - r1608_mangos.sql \ - r1615_mangos.sql \ - r1615_scriptdev2.sql \ - r1616_mangos.sql \ - r1617_mangos.sql \ - r1621_scriptdev2.sql \ - r1622_mangos.sql \ - r1622_scriptdev2.sql \ - r1624_mangos.sql \ - r1624_scriptdev2.sql \ - r1627_mangos.sql \ - r1627_scriptdev2.sql \ - r1629_mangos.sql \ - r1629_scriptdev2.sql \ - r1632_mangos.sql \ - r1636_mangos.sql \ - r1637_scriptdev2.sql \ - r1642_scriptdev2.sql \ - r1644_scriptdev2.sql \ - r1647_scriptdev2.sql \ - r1647_mangos.sql \ - r1650_mangos.sql \ - r1651_scriptdev2.sql \ - r1652_scriptdev2.sql \ - r1653_mangos.sql \ - r1658_scriptdev2.sql \ - r1660_scriptdev2.sql \ - r1661_mangos.sql \ - r1662_scriptdev2.sql \ - r1665_mangos.sql \ - r1667_mangos.sql \ - r1667_scriptdev2.sql \ - r1668_mangos.sql \ - r1671_mangos.sql \ - r1671_scriptdev2.sql \ - r1679_mangos.sql \ - r1680_mangos.sql \ - r1681_mangos.sql \ - r1683_scriptdev2.sql \ - r1685_mangos.sql \ - r1685_scriptdev2.sql \ - r1687_mangos.sql \ - r1691_mangos.sql \ - r1694_mangos.sql \ - r1698_mangos.sql \ - r1704_mangos.sql \ - r1705_mangos.sql \ - r1705_scriptdev2.sql \ - r1706_scriptdev2.sql \ - r1711_scriptdev2.sql \ - r1715_mangos.sql \ - r1715_scriptdev2.sql \ - r1720_mangos.sql \ - r1720_scriptdev2.sql \ - r1726_mangos.sql \ - r1727_scriptdev2.sql \ - r1728_mangos.sql \ - r1729_scriptdev2.sql \ - r1734_scriptdev2.sql \ - r1736_scriptdev2.sql \ - r1737_scriptdev2.sql \ - r1741_mangos.sql \ - r1750_scriptdev2.sql \ - r1751_scriptdev2.sql \ - r1752_mangos.sql \ - r1753_scriptdev2.sql \ - r1754_scriptdev2.sql \ - r1759_mangos.sql \ - r1763_mangos.sql \ - r1767_mangos.sql \ - r1771_scriptdev2.sql \ - r1777_scriptdev2.sql \ - r1780_scriptdev2.sql \ - r1782_scriptdev2.sql \ - r1783_scriptdev2.sql \ - r1784_scriptdev2.sql \ - r1785_scriptdev2.sql \ - r1786_scriptdev2.sql \ - r1789_scriptdev2.sql \ - r1791_scriptdev2.sql \ - r1797_mangos.sql \ - r1798_mangos.sql \ - r1800_mangos.sql \ - r1800_scriptdev2.sql \ - r1807_scriptdev2.sql \ - r1810_scriptdev2.sql \ - r1813_mangos.sql \ - r1816_scriptdev2.sql \ - r1818_mangos.sql \ - r1818_scriptdev2.sql \ - r1819_mangos.sql \ - r1822_scriptdev2.sql \ - r1824_mangos.sql \ - r1825_mangos.sql \ - r1825_scriptdev2.sql \ - r1826_mangos.sql \ - r1826_scriptdev2.sql \ - r1827_scriptdev2.sql \ - r1828_scriptdev2.sql \ - r1829_mangos.sql \ - r1830_scriptdev2.sql \ - r1831_scriptdev2.sql \ - r1836_mangos.sql \ - r1842_scriptdev2.sql \ - r1843_mangos.sql \ - r1843_scriptdev2.sql \ - r1844_mangos.sql \ - r1845_mangos.sql \ - r1845_scriptdev2.sql \ - r1850_mangos.sql \ - r1850_scriptdev2.sql \ - r1851_mangos.sql \ - r1852_scriptdev2.sql \ - r1853_mangos.sql \ - r1855_scriptdev2.sql \ - r1858_scriptdev2.sql \ - r1859_mangos.sql \ - r1860_scriptdev2.sql \ - r1862_mangos.sql \ - r1863_mangos.sql \ - r1864_mangos.sql \ - r1864_scriptdev2.sql \ - r1865_mangos.sql \ - r1865_scriptdev2.sql \ - r1866_scriptdev2.sql \ - r1868_scriptdev2.sql \ - r1869_mangos.sql \ - r1871_mangos.sql \ - r1875_mangos.sql \ - r1875_scriptdev2.sql \ - r1876_mangos.sql \ - r1876_scriptdev2.sql \ - r1878_mangos.sql \ - r1881_mangos.sql \ - r1882_scriptdev2.sql - diff --git a/sql/mangos_scriptname_clear.sql b/sql/mangos_scriptname_clear.sql new file mode 100644 index 0000000000..9be32f4eaf --- /dev/null +++ b/sql/mangos_scriptname_clear.sql @@ -0,0 +1,10 @@ +-- Clear all ScriptNames +-- This will clear all ScriptNames from any table in the World-Database + +TRUNCATE scripted_areatrigger; +TRUNCATE scripted_event_id; +UPDATE creature_template SET ScriptName=''; +UPDATE gameobject_template SET ScriptName=''; +UPDATE item_template SET ScriptName=''; +UPDATE instance_template SET ScriptName=''; +UPDATE world_template SET ScriptName=''; diff --git a/sql/mangos_scriptname_full.sql b/sql/mangos_scriptname_full.sql index beb8e86e87..0801f94b8f 100644 --- a/sql/mangos_scriptname_full.sql +++ b/sql/mangos_scriptname_full.sql @@ -7,39 +7,91 @@ DELETE FROM scripted_areatrigger WHERE entry=4560; INSERT INTO scripted_areatrigger VALUES (4560,'at_legion_teleporter'); DELETE FROM scripted_areatrigger WHERE entry=3066; INSERT INTO scripted_areatrigger VALUES (3066,'at_ravenholdt'); -DELETE FROM scripted_areatrigger WHERE entry IN (4871, 4872, 4873); +DELETE FROM scripted_areatrigger WHERE entry IN (4871,4872,4873); INSERT INTO scripted_areatrigger VALUES (4871,'at_warsong_farms'), (4872,'at_warsong_farms'), (4873,'at_warsong_farms'); -DELETE FROM scripted_areatrigger WHERE entry IN (5046, 5047); +DELETE FROM scripted_areatrigger WHERE entry IN (5046,5047); INSERT INTO scripted_areatrigger VALUES -(5046, 'at_waygate'), -(5047, 'at_waygate'); +(5046,'at_waygate'), +(5047,'at_waygate'); DELETE FROM scripted_areatrigger WHERE entry BETWEEN 5284 AND 5287; INSERT INTO scripted_areatrigger VALUES (5284,'at_aldurthar_gate'), (5285,'at_aldurthar_gate'), (5286,'at_aldurthar_gate'), (5287,'at_aldurthar_gate'); -DELETE FROM scripted_areatrigger WHERE entry=4112; -INSERT INTO scripted_areatrigger VALUES (4112,'at_naxxramas'); +DELETE FROM scripted_areatrigger WHERE entry IN (4112,4113); +INSERT INTO scripted_areatrigger VALUES +(4112,'at_naxxramas'), +(4113,'at_naxxramas'); DELETE FROM scripted_areatrigger WHERE entry=5108; INSERT INTO scripted_areatrigger VALUES (5108,'at_stormwright_shelf'); -DELETE FROM scripted_areatrigger WHERE entry IN (3546, 3547, 3548, 3549, 3550, 3552); +DELETE FROM scripted_areatrigger WHERE entry IN (3546,3547,3548,3549,3550,3552); INSERT INTO scripted_areatrigger VALUES -(3546, 'at_childrens_week_spot'), -- Darnassian bank -(3547, 'at_childrens_week_spot'), -- Undercity - thone room -(3548, 'at_childrens_week_spot'), -- Stonewrought Dam -(3549, 'at_childrens_week_spot'), -- The Mor'shan Rampart -(3550, 'at_childrens_week_spot'), -- Ratchet Docks -(3552, 'at_childrens_week_spot'); -- Westfall Lighthouse -DELETE FROM scripted_areatrigger WHERE entry IN (2026, 2046); +(3546,'at_childrens_week_spot'), -- Darnassian bank +(3547,'at_childrens_week_spot'), -- Undercity - thone room +(3548,'at_childrens_week_spot'), -- Stonewrought Dam +(3549,'at_childrens_week_spot'), -- The Mor'shan Rampart +(3550,'at_childrens_week_spot'), -- Ratchet Docks +(3552,'at_childrens_week_spot'); -- Westfall Lighthouse +DELETE FROM scripted_areatrigger WHERE entry IN (2026,2046); INSERT INTO scripted_areatrigger VALUES -(2026, 'at_blackrock_spire'), -(2046, 'at_blackrock_spire'); +(2026,'at_blackrock_spire'), +(2046,'at_blackrock_spire'); DELETE FROM scripted_areatrigger WHERE entry=5030; INSERT INTO scripted_areatrigger VALUES (5030,'at_spearborn_encampment'); +DELETE FROM scripted_areatrigger WHERE entry IN (3958,3960); +INSERT INTO scripted_areatrigger VALUES +(3958,'at_zulgurub'), +(3960,'at_zulgurub'); +DELETE FROM scripted_areatrigger WHERE entry=3626; +INSERT INTO scripted_areatrigger VALUES (3626,'at_vaelastrasz'); +DELETE FROM scripted_areatrigger WHERE entry=4937; +INSERT INTO scripted_areatrigger VALUES (4937,'at_sunwell_plateau'); +DELETE FROM scripted_areatrigger WHERE entry=4524; +INSERT INTO scripted_areatrigger VALUES (4524,'at_shattered_halls'); +DELETE FROM scripted_areatrigger WHERE entry BETWEEN 1726 AND 1740; +INSERT INTO scripted_areatrigger VALUES +(1726,'at_scent_larkorwi'), +(1727,'at_scent_larkorwi'), +(1728,'at_scent_larkorwi'), +(1729,'at_scent_larkorwi'), +(1730,'at_scent_larkorwi'), +(1731,'at_scent_larkorwi'), +(1732,'at_scent_larkorwi'), +(1733,'at_scent_larkorwi'), +(1734,'at_scent_larkorwi'), +(1735,'at_scent_larkorwi'), +(1736,'at_scent_larkorwi'), +(1737,'at_scent_larkorwi'), +(1738,'at_scent_larkorwi'), +(1739,'at_scent_larkorwi'), +(1740,'at_scent_larkorwi'); +DELETE FROM scripted_areatrigger WHERE entry IN (5709,5732); +INSERT INTO scripted_areatrigger VALUES +(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'); + /* BATTLEGROUNDS */ UPDATE creature_template SET ScriptName='npc_spirit_guide' WHERE entry IN (13116, 13117); @@ -48,37 +100,24 @@ 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_northern_crystal_pylon' WHERE entry=164955; -UPDATE gameobject_template SET ScriptName='go_western_crystal_pylon' WHERE entry=164956; -UPDATE gameobject_template SET ScriptName='go_eastern_crystal_pylon' WHERE entry=164957; 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_field_repair_bot_74A' where entry=179552; -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_orb_of_command' WHERE entry=179879; -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_tablet_of_madness' WHERE entry=180368; -UPDATE gameobject_template SET ScriptName='go_tablet_of_the_seven' WHERE entry=169294; 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); /* GUARD */ UPDATE creature_template SET ScriptName='guard_azuremyst' WHERE entry=18038; @@ -107,7 +146,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) */ @@ -116,45 +154,56 @@ 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_kingdom_of_dalaran_quests' WHERE entry IN (29169,23729,26673,27158,29158,29161,26471,29155,29159,29160,29162); -UPDATE creature_template SET ScriptName='npc_lunaclaw_spirit' WHERE entry=12144; -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='' 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_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_engineering_tele_trinket' WHERE entry IN (14742,14743,21493,21494); 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_rogue_trainer' WHERE entry IN (918,4163,3328,4583,5165,5167,13283,16684); -UPDATE creature_template SET ScriptName='npc_sayge' WHERE entry=14822; -UPDATE creature_template SET ScriptName='npc_tabard_vendor' WHERE entry=28776; -UPDATE creature_template SET ScriptName='npc_locksmith' WHERE entry IN (29665,29725,29728); +-- 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 (16880,1200,26616,26643,16518,25793,25758,25752,25792,25753,26421,26841,27808,27122,28068,12298,12296,24918,17326,17654,16847,18879,26270,26268,30146,25084,25085,32149,22105,29330,29338,29329); +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN ( +-- eastern kingdoms +1200,8888,13016, +-- kalimdor +9299,12296,12298, +-- outland +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,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, 609); +INSERT INTO world_template VALUES +(0, 'world_map_eastern_kingdoms'), +(1, 'world_map_kalimdor'), +(530, 'world_map_outland'), +(571, 'world_map_northrend'), +(609, 'world_map_ebon_hold'); + /* */ /* ZONE */ /* */ /* 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; UPDATE gameobject_template SET ScriptName='go_naga_brazier' WHERE entry=178247; UPDATE creature_template SET ScriptName='npc_ruul_snowhoof' WHERE entry=12818; UPDATE creature_template SET ScriptName='npc_torek' WHERE entry=12858; +UPDATE creature_template SET ScriptName='npc_feero_ironhand' WHERE entry=4484; /* */ /* AUCHINDOUN */ @@ -163,21 +212,20 @@ UPDATE creature_template SET ScriptName='npc_torek' WHERE entry=12858; /* 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; @@ -185,6 +233,7 @@ UPDATE creature_template SET ScriptName='boss_murmur' WHERE entry=18708; UPDATE creature_template SET ScriptName='boss_grandmaster_vorpil' WHERE entry=18732; UPDATE creature_template SET ScriptName='boss_blackheart_the_inciter' WHERE entry=18667; UPDATE creature_template SET ScriptName='boss_ambassador_hellmaw' WHERE entry=18731; +UPDATE creature_template SET ScriptName='npc_void_traveler' WHERE entry=19226; /* */ /* AZJOL-NERUB */ @@ -193,7 +242,7 @@ UPDATE creature_template SET ScriptName='boss_ambassador_hellmaw' WHERE entry=18 /* AHN'KAHET */ UPDATE creature_template SET ScriptName='boss_jedoga' WHERE entry=29310; 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='mob_ahnkahar_egg' WHERE entry IN (30172,30173); UPDATE creature_template SET ScriptName='boss_taldaram' WHERE entry=29308; UPDATE gameobject_template SET ScriptName='go_nerubian_device' WHERE entry IN (193093,193094); UPDATE creature_template SET ScriptName='boss_volazj' WHERE entry=29311; @@ -201,6 +250,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; @@ -209,7 +259,7 @@ UPDATE instance_template SET ScriptName='instance_azjol-nerub' WHERE map=601; UPDATE creature_template SET ScriptName='npc_rizzle_sprysprocket' WHERE entry=23002; UPDATE creature_template SET ScriptName='npc_depth_charge' WHERE entry=23025; UPDATE gameobject_template SET ScriptName='go_southfury_moonstone' WHERE entry=185566; -UPDATE creature_template SET ScriptName='mobs_spitelashes' WHERE entry IN (6190,6193,6194,6195,6196,7885,7886,12204,12205); +UPDATE creature_template SET ScriptName='mobs_spitelashes' WHERE entry IN (6190,6193,6194,6195,6196); UPDATE creature_template SET ScriptName='npc_loramus_thalipedes' WHERE entry=7783; /* AZUREMYST ISLE */ @@ -217,15 +267,12 @@ UPDATE creature_template SET ScriptName='npc_draenei_survivor' WHERE entry=16483 UPDATE creature_template SET ScriptName='npc_engineer_spark_overgrind' WHERE entry=17243; UPDATE creature_template SET ScriptName='npc_injured_draenei' WHERE entry=16971; UPDATE creature_template SET ScriptName='npc_magwin' WHERE entry=17312; -UPDATE creature_template SET ScriptName='npc_susurrus' WHERE entry=17435; /* 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; @@ -254,22 +301,16 @@ 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; @@ -282,41 +323,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_lokhtos_darkbargainer' WHERE entry=12944; +UPDATE creature_template SET ScriptName='npc_theldren_trigger' WHERE entry=16079; 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 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; @@ -327,33 +361,31 @@ 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_overseer_nuaar' WHERE entry=21981; -UPDATE creature_template SET ScriptName='npc_saikkal_the_elder' WHERE entry=22932; -UPDATE creature_template SET ScriptName='npc_skyguard_handler_deesak' WHERE entry=23415; +UPDATE creature_template SET ScriptName='npc_bloodmaul_stout_trigger' WHERE entry=21241; +UPDATE creature_template SET ScriptName='npc_simon_game_bunny' WHERE entry=22923; /* BLASTED LANDS */ -UPDATE creature_template SET ScriptName='npc_deathly_usher' WHERE entry=8816; UPDATE creature_template SET ScriptName='npc_fallen_hero_of_horde' WHERE entry=7572; /* BLOODMYST ISLE */ UPDATE creature_template SET ScriptName='mob_webbed_creature' WHERE entry=17680; -UPDATE creature_template SET ScriptName='npc_captured_sunhawk_agent' WHERE entry=17824; /* BOREAN TUNDRA */ -UPDATE creature_template SET ScriptName='npc_fizzcrank_fullthrottle' WHERE entry=25590; -UPDATE creature_template SET ScriptName='npc_iruk' WHERE entry=26219; -UPDATE creature_template SET ScriptName='npc_kara_thricestar' WHERE entry=26602; UPDATE creature_template SET ScriptName='npc_nesingwary_trapper' WHERE entry=25835; -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_surristrasz' WHERE entry=24795; -UPDATE creature_template SET ScriptName='npc_tiare' WHERE entry=30051; +UPDATE creature_template SET ScriptName='npc_oil_stained_wolf' WHERE entry=25791; +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 */ @@ -365,20 +397,16 @@ 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; @@ -390,15 +418,17 @@ UPDATE creature_template SET ScriptName='boss_chrono_lord_deja' WHERE entry=1787 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; -UPDATE creature_template SET ScriptName='npc_saat' WHERE entry=20201; /* */ /* COILFANG RESERVOIR */ /* */ /* 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; @@ -410,7 +440,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; @@ -419,7 +448,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; @@ -431,9 +459,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; @@ -448,6 +474,8 @@ UPDATE creature_template SET ScriptName='boss_the_lurker_below' WHERE entry=2121 /* TRIAL OF THE CRUSADER */ UPDATE instance_template SET ScriptName='instance_trial_of_the_crusader' WHERE map=649; +UPDATE creature_template SET ScriptName='npc_barrett_ramsey' WHERE entry IN (34816, 35035, 35766, 35770, 35771); +UPDATE creature_template SET ScriptName='npc_beast_combat_stalker' WHERE entry=36549; UPDATE creature_template SET ScriptName='boss_gormok' WHERE entry=34796; UPDATE creature_template SET ScriptName='boss_acidmaw' WHERE entry=35144; UPDATE creature_template SET ScriptName='boss_dreadscale' WHERE entry=34799; @@ -459,71 +487,66 @@ UPDATE creature_template SET ScriptName='boss_eydis' WHERE entry=34496; /* DALARAN */ UPDATE creature_template SET ScriptName='npc_dalaran_guardian_mage' WHERE entry IN (29255, 29254); -UPDATE creature_template SET ScriptName='npc_zidormi' WHERE entry=31848; /* DARKSHORE */ 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; UPDATE gameobject_template SET ScriptName='go_defias_cannon' WHERE entry=16398; -UPDATE gameobject_template SET ScriptName='go_door_lever_dm' WHERE entry=101833; /* 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; +UPDATE creature_template SET ScriptName='npc_melizza_brimbuzzle' WHERE entry=12277; /* DIRE MAUL */ - +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_alexstrasza_wr_gate' WHERE entry=31333; -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_destructive_ward' WHERE entry=27430; +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; +UPDATE creature_template SET ScriptName='npc_crystal_channel_target' WHERE entry=26712; UPDATE creature_template SET ScriptName='boss_tharonja' WHERE entry=26632; 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_deserter_agitator' WHERE entry=23602; -UPDATE creature_template SET ScriptName='npc_lady_jaina_proudmoore' WHERE entry=4968; 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_nat_pagle' WHERE entry=12919; -UPDATE creature_template SET ScriptName='npc_cassa_crimsonwing' WHERE entry=23704; 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_augustus_the_touched' WHERE entry=12384; -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; @@ -532,15 +555,22 @@ UPDATE creature_template SET ScriptName='npc_unworthy_initiate' WHERE entry IN ( 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; /* ELWYNN FOREST */ -UPDATE creature_template SET ScriptName='npc_henze_faulk' WHERE entry=6172; +UPDATE creature_template SET ScriptName='npc_hogger' WHERE entry=448; /* EVERSONG WOODS */ UPDATE creature_template SET ScriptName='npc_kelerun_bloodmourn' WHERE entry=17807; UPDATE gameobject_template SET ScriptName='go_harbinger_second_trial' WHERE entry=182052; UPDATE creature_template SET ScriptName='npc_prospector_anvilward' WHERE entry=15420; UPDATE creature_template SET ScriptName='npc_apprentice_mirveda' WHERE entry=15402; +UPDATE creature_template SET ScriptName='npc_infused_crystal' WHERE entry=16364; /* FELWOOD */ DELETE FROM scripted_event_id WHERE id=8328; @@ -548,29 +578,28 @@ 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_blood_knight_dawnstar' WHERE entry=17832; -UPDATE creature_template SET ScriptName='npc_budd_nedreck' WHERE entry=23559; UPDATE creature_template SET ScriptName='npc_ranger_lilatha' WHERE entry=16295; -UPDATE creature_template SET ScriptName='npc_rathis_tomber' WHERE entry=16224; /* GNOMEREGAN */ 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_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; /* GRUUL'S LAIR */ UPDATE instance_template SET ScriptName='instance_gruuls_lair' WHERE map =565; @@ -583,7 +612,7 @@ 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_eck' WHERE entry=29932; UPDATE creature_template SET ScriptName='boss_galdarah' WHERE entry=29306; UPDATE creature_template SET ScriptName='boss_moorabi' WHERE entry=29305; @@ -603,6 +632,7 @@ UPDATE creature_template SET ScriptName='boss_broggok' WHERE entry=17380; UPDATE creature_template SET ScriptName='boss_kelidan_the_breaker' WHERE entry=17377; UPDATE creature_template SET ScriptName='mob_broggok_poisoncloud' WHERE entry=17662; UPDATE creature_template SET ScriptName='mob_shadowmoon_channeler' WHERE entry=17653; +UPDATE gameobject_template SET ScriptName='go_prison_cell_lever' WHERE entry=181982; UPDATE instance_template SET ScriptName='instance_blood_furnace' WHERE map=542; /* HELLFIRE RAMPARTS */ @@ -629,41 +659,55 @@ 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 gameobject_template SET ScriptName='go_haaleshi_altar' WHERE entry=181606; 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_gryphoneer_windbellow' WHERE entry=20235; -UPDATE creature_template SET ScriptName='npc_naladu' WHERE entry=19361; -UPDATE creature_template SET ScriptName='npc_tracy_proudwell' WHERE entry=18266; -UPDATE creature_template SET ScriptName='npc_trollbane' WHERE entry=16819; -UPDATE creature_template SET ScriptName='npc_wing_commander_brack' WHERE entry=19401; -UPDATE creature_template SET ScriptName='npc_wing_commander_dabiree' WHERE entry=19409; 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; /* 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 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_mcgoyver' WHERE entry=24040; 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='boss_lady_deathwhisper' WHERE entry=36855; +UPDATE creature_template SET ScriptName='boss_deathbringer_saurfang' WHERE entry=37813; +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; UPDATE creature_template SET ScriptName='boss_devourer_of_souls' WHERE entry=36502; UPDATE instance_template SET ScriptName='instance_forge_of_souls' WHERE map=632; @@ -671,10 +715,21 @@ UPDATE instance_template SET ScriptName='instance_forge_of_souls' WHERE map=632; /* 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_arete' WHERE entry=29344; -UPDATE creature_template SET ScriptName='npc_dame_evniki_kapsalis' WHERE entry=34885; +UPDATE creature_template SET ScriptName='npc_saronite_mine_slave' WHERE entry=31397; /* IRONFORGE */ UPDATE creature_template SET ScriptName='npc_royal_historian_archesonus' WHERE entry=8879; @@ -685,7 +740,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; @@ -694,29 +749,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; @@ -729,26 +796,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; @@ -767,24 +833,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='mob_shattered_rumbler' WHERE entry=17157; -UPDATE creature_template SET ScriptName='mob_sunspring_villager' WHERE entry=18240; -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_lantresor_of_the_blade' WHERE entry=18261; -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; @@ -803,12 +863,14 @@ UPDATE creature_template SET ScriptName='boss_sir_zeliek' WHERE entry=16063; UPDATE creature_template SET ScriptName='boss_lady_blaumeux' WHERE entry=16065; UPDATE creature_template SET ScriptName='boss_rivendare_naxx' WHERE entry=30549; UPDATE creature_template SET ScriptName='boss_patchwerk' WHERE entry=16028; --- UPDATE creature_template SET ScriptName='boss_grobbulus' WHERE entry=15931; +UPDATE creature_template SET ScriptName='boss_grobbulus' WHERE entry=15931; UPDATE creature_template SET ScriptName='boss_gluth' WHERE entry=15932; --- UPDATE creature_template SET ScriptName='boss_thaddius' WHERE entry=15928; --- 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='boss_thaddius' WHERE entry=15928; +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 */ @@ -817,16 +879,24 @@ 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_veronia' WHERE entry=20162; 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; /* */ /* 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; +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; @@ -838,7 +908,9 @@ UPDATE gameobject_template SET ScriptName='go_containment_sphere' WHERE entry IN UPDATE instance_template SET ScriptName='instance_nexus' WHERE map=576; /* OCULUS */ - +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; /* OBSIDIAN SANCTUM */ UPDATE instance_template SET ScriptName='instance_obsidian_sanctum' WHERE map=615; @@ -846,75 +918,77 @@ 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; UPDATE creature_template SET ScriptName='boss_onyxia' WHERE entry=10184; /* ORGRIMMAR */ -UPDATE creature_template SET ScriptName='npc_neeru_fireblade' WHERE entry=3216; UPDATE creature_template SET ScriptName='npc_shenthul' WHERE entry=3401; 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 creature_template SET ScriptName='npc_henry_stern' WHERE entry=8696; +UPDATE creature_template SET ScriptName='npc_belnistrasz' WHERE entry=8516; /* 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; + /* 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; UPDATE creature_template SET ScriptName='boss_kurinnaxx' WHERE entry=15348; UPDATE creature_template SET ScriptName='boss_ayamiss' WHERE entry=15369; UPDATE creature_template SET ScriptName='boss_moam' WHERE entry=15340; +UPDATE creature_template SET ScriptName='boss_ossirian' WHERE entry=15339; +UPDATE gameobject_template SET ScriptName='go_ossirian_crystal' WHERE entry=180619; +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_lord_alexei_barov' WHERE entry=10504; -UPDATE creature_template SET ScriptName='boss_instructor_malicia' WHERE entry=10505; -UPDATE creature_template SET ScriptName='boss_boss_ras_frostwhisper' WHERE entry=10508; -UPDATE creature_template SET ScriptName='boss_the_ravenian' WHERE entry=10507; -UPDATE creature_template SET ScriptName='boss_vectus' WHERE entry=10432; -UPDATE creature_template SET ScriptName='boss_illucia_barov' WHERE entry=10502; -UPDATE creature_template SET ScriptName='boss_doctor_theolen_krastinov' WHERE entry=11261; UPDATE creature_template SET ScriptName='boss_jandice_barov' WHERE entry=10503; -UPDATE creature_template SET ScriptName='boss_lorekeeper_polkelt' WHERE entry=10901; -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'), +(5619,'event_spell_gandling_shadow_portal'), +(5620,'event_spell_gandling_shadow_portal'), +(5621,'event_spell_gandling_shadow_portal'), +(5622,'event_spell_gandling_shadow_portal'), +(5623,'event_spell_gandling_shadow_portal'); /* SEARING GORGE */ -UPDATE creature_template SET ScriptName='npc_kalaran_windblade' WHERE entry=8479; -UPDATE creature_template SET ScriptName='npc_lothos_riftwaker' WHERE entry=14387; -UPDATE creature_template SET ScriptName='npc_zamael_lunthistle' WHERE entry=8436; +UPDATE creature_template SET ScriptName='npc_dorius_stonetender' WHERE entry=8284; /* SHADOWFANG KEEP */ UPDATE instance_template SET ScriptName='instance_shadowfang_keep' WHERE map=33; @@ -923,66 +997,69 @@ UPDATE creature_template SET ScriptName='npc_arugal' WHERE entry=10000; UPDATE creature_template SET ScriptName='npc_deathstalker_vincent' WHERE entry=4444; UPDATE creature_template SET ScriptName='mob_arugal_voidwalker' WHERE entry=4627; UPDATE creature_template SET ScriptName='boss_arugal' WHERE entry=4275; +UPDATE creature_template SET ScriptName='npc_apothecary_hummel' WHERE entry=36296; +UPDATE creature_template SET ScriptName='npc_valentine_boss_manager' WHERE entry=36643; /* 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='npcs_flanis_swiftwing_and_kagrosh' WHERE entry IN (21725,21727); -UPDATE creature_template SET ScriptName='npc_murkblood_overseer' WHERE entry=23309; -UPDATE creature_template SET ScriptName='npc_neltharaku' WHERE entry=21657; -UPDATE creature_template SET ScriptName='npc_oronok_tornheart' WHERE entry=21183; +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; +DELETE FROM scripted_event_id WHERE id IN (13513,13514,13515,13516); +INSERT INTO scripted_event_id VALUES +(13513,'event_spell_soul_captured_credit'), +(13514,'event_spell_soul_captured_credit'), +(13515,'event_spell_soul_captured_credit'), +(13516,'event_spell_soul_captured_credit'); 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_ishanah' WHERE entry=18538; -UPDATE creature_template SET ScriptName='npc_khadgar' WHERE entry=18166; UPDATE creature_template SET ScriptName='npc_khadgars_servant' WHERE entry=19685; -UPDATE creature_template SET ScriptName='npc_raliq_the_drunk' WHERE entry=18585; UPDATE creature_template SET ScriptName='npc_salsalabim' WHERE entry=18584; -UPDATE creature_template SET ScriptName='npc_shattrathflaskvendors' WHERE entry IN (23483,23484); -UPDATE creature_template SET ScriptName='npc_zephyr' WHERE entry=25967; /* 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_vekjik' WHERE entry=28315; +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_astor_hadren' WHERE entry=6497; UPDATE creature_template SET ScriptName='npc_deathstalker_erland' WHERE entry=1978; UPDATE creature_template SET ScriptName='npc_deathstalker_faerleia' WHERE entry=2058; /* 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_loklira_the_crone' WHERE entry=29975; -UPDATE creature_template SET ScriptName='npc_thorim' WHERE entry=29445; -UPDATE creature_template SET ScriptName='npc_roxi_ramrocket' WHERE entry=31247; -UPDATE creature_template SET ScriptName = 'npc_frostborn_scout' WHERE entry = 29811; +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_archmage_malin' WHERE entry=2708; 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; @@ -990,26 +1067,34 @@ 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); /* SUNKEN TEMPLE */ UPDATE instance_template SET ScriptName='instance_sunken_temple' WHERE map=109; DELETE FROM scripted_areatrigger WHERE entry=4016; INSERT INTO scripted_areatrigger VALUES (4016,'at_shade_of_eranikus'); UPDATE creature_template SET ScriptName='npc_malfurion_stormrage' WHERE entry=15362; +DELETE FROM scripted_event_id WHERE id IN (3094,3095,3097,3098,3099,3100); +INSERT INTO scripted_event_id VALUES +(3094,'event_antalarion_statue_activation'), +(3095,'event_antalarion_statue_activation'), +(3097,'event_antalarion_statue_activation'), +(3098,'event_antalarion_statue_activation'), +(3099,'event_antalarion_statue_activation'), +(3100,'event_antalarion_statue_activation'); +UPDATE creature_template SET ScriptName='npc_shade_of_hakkar' WHERE entry=8440; +UPDATE gameobject_template SET ScriptName='go_eternal_flame' WHERE entry IN (148418,148419,148420,148421); +DELETE FROM scripted_event_id WHERE id=8502; +INSERT INTO scripted_event_id VALUES +(8502,'event_avatar_of_hakkar'); /* SUNWELL PLATEAU */ UPDATE instance_template SET ScriptName='instance_sunwell_plateau' WHERE map=580; @@ -1017,9 +1102,22 @@ UPDATE creature_template SET ScriptName='boss_brutallus' WHERE entry=24882; UPDATE creature_template SET ScriptName='boss_kalecgos' WHERE entry=24850; UPDATE creature_template SET ScriptName='boss_kalecgos_humanoid' WHERE entry=24891; UPDATE creature_template SET ScriptName='boss_sathrovarr' WHERE entry=24892; -UPDATE gameobject_template SET ScriptName='go_spectral_rift' WHERE entry=187055; DELETE FROM scripted_areatrigger WHERE entry=4853; INSERT INTO scripted_areatrigger VALUES (4853,'at_madrigosa'); +UPDATE creature_template SET ScriptName='boss_alythess' WHERE entry=25166; +UPDATE creature_template SET ScriptName='boss_sacrolash' WHERE entry=25165; +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; /* SWAMP OF SORROWS */ UPDATE creature_template SET ScriptName='npc_galen_goodward' WHERE entry=5391; @@ -1027,9 +1125,7 @@ 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_steward_of_time' WHERE entry=20142; UPDATE creature_template SET ScriptName='npc_stone_watcher_of_norgannon' WHERE entry=7918; UPDATE creature_template SET ScriptName='npc_tooga' WHERE entry=5955; @@ -1041,9 +1137,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; @@ -1056,16 +1150,16 @@ 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 */ UPDATE creature_template SET ScriptName='boss_void_reaver' WHERE entry=19516; /* Astromancer event */ @@ -1089,34 +1183,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_viscidus' WHERE entry=15299; -- UPDATE creature_template SET ScriptName='boss_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_skyguard_handler_irena' WHERE entry=23413; -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; @@ -1125,7 +1220,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; @@ -1139,7 +1233,6 @@ INSERT INTO scripted_event_id VALUES (2268,'event_spell_altar_boss_aggro'); UPDATE creature_template SET ScriptName='boss_archaedas' WHERE entry=2748; UPDATE creature_template SET ScriptName='mob_archaeras_add' WHERE entry IN (7309,7076,7077,10120); -UPDATE creature_template SET ScriptName='npc_lore_keeper_of_norgannon' WHERE entry=7172; UPDATE instance_template SET ScriptName='instance_uldaman' WHERE map=70; /* */ @@ -1162,9 +1255,101 @@ 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='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; +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'), -- 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; @@ -1172,8 +1357,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; -UPDATE creature_template SET ScriptName='npc_parqual_fintallas' WHERE entry=4488; /* */ /* UTGARDE KEEP */ @@ -1202,21 +1385,25 @@ UPDATE instance_template SET ScriptName='instance_pinnacle' WHERE map=575; /* 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_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); /* 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='npcs_dithers_and_arbington' WHERE entry IN (11056,11057); -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; @@ -1227,19 +1414,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_rivern_frostwind' WHERE entry=10618; -UPDATE creature_template SET ScriptName='npc_witch_doctor_mauari' WHERE entry=10307; +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_elder_kuruti' WHERE entry=18197; UPDATE creature_template SET ScriptName='npc_kayra_longmane' WHERE entry=17969; -UPDATE creature_template SET ScriptName='npc_mortog_steamhead' WHERE entry=23373; -UPDATE creature_template SET ScriptName='npc_timothy_daniels' WHERE entry=18019; +UPDATE creature_template SET ScriptName='npc_fhwoor' WHERE entry=17877; /* ZUL'AMAN */ UPDATE instance_template SET ScriptName='instance_zulaman' WHERE map=568; @@ -1251,33 +1434,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='mob_jandalai_firebomb' WHERE entry=23920; -UPDATE creature_template SET ScriptName='mob_amanishi_hatcher' WHERE entry IN (23818,24504); -UPDATE creature_template SET ScriptName='mob_hatchling' WHERE entry=23598; +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_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; @@ -1286,21 +1465,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_create_database.sql b/sql/scriptdev2_create_database.sql index 747dab2acb..2aa367fd53 100644 --- a/sql/scriptdev2_create_database.sql +++ b/sql/scriptdev2_create_database.sql @@ -1,4 +1,3 @@ CREATE DATABASE `scriptdev2` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -GRANT ALL PRIVILEGES ON `scriptdev2` . * TO 'mangos'@'localhost' WITH GRANT OPTION; - +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, LOCK TABLES ON `scriptdev2`.* TO 'mangos'@'localhost'; diff --git a/sql/scriptdev2_script_full.sql b/sql/scriptdev2_script_full.sql index 3a78857a0e..b1ac7b9415 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 10610+) '); +INSERT INTO sd2_db_version (version) VALUES ('ScriptDev2 (for MangosR2 3157+ / for CMaNGOS 12682+) '); -- -- Below contains data for table `script_texts` mainly used in C++ parts. @@ -47,7 +47,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000101,'Follow me, $N. I\'ll take you to the Defias hideout. But you better protect me or I am as good as dead',0,0,7,0,'defias traitor SAY_START'), (-1000102,'The entrance is hidden here in Moonbrook. Keep your eyes peeled for thieves. They want me dead.',0,0,7,0,'defias traitor SAY_PROGRESS'), (-1000103,'You can go tell Stoutmantle this is where the Defias Gang is holed up, $N.',0,0,7,0,'defias traitor SAY_END'), -(-1000104,'%s coming in fast! Prepare to fight!',0,0,7,0,'defias traitor SAY_AGGRO_1'), +(-1000104,'$N coming in fast! Prepare to fight!',0,0,7,0,'defias traitor SAY_AGGRO_1'), (-1000105,'Help!',0,0,7,0,'defias traitor SAY_AGGRO_2'), (-1000106,'Everyone ready?',0,0,1,0,'torek SAY_READY'), @@ -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,'I choose the third option: KILLING YOU!',0,0,0,0,'floon SAY_FLOON_ATTACK'), +(-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,'Frenzyheart kill you if you come back. You no welcome here no more!',0,0,0,0,'vekjik SAY_TEXTID_VEKJIK1'), +(-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'), @@ -584,9 +585,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000559,'I\'d rather die fighting than live like a slave.',0,0,0,0,'exhausted vrykul SAY_RAND_ATTACK2'), (-1000560,'Enough! I will teach you some manners, wench!',0,0,0,0,'exhausted vrykul SAY_RAND_ATTACK3'), -(-1000561,'My wounds are grave. Forgive my slow pace but my injuries won''t allow me to walk any faster.',0,0,0,0,'SAY_CORPORAL_KEESHAN_1'), +(-1000561,'My wounds are grave. Forgive my slow pace but my injuries won\'t allow me to walk any faster.',0,0,0,0,'SAY_CORPORAL_KEESHAN_1'), (-1000562,'Ah, fresh air, at last! I need a moment to rest.',0,0,0,0,'SAY_CORPORAL_KEESHAN_2'), -(-1000563,'The Blackrock infestation is thick in these parts. I will do my best to keep the pace. Let''s go!',0,0,0,0,'SAY_CORPORAL_KEESHAN_3'), +(-1000563,'The Blackrock infestation is thick in these parts. I will do my best to keep the pace. Let\'s go!',0,0,0,0,'SAY_CORPORAL_KEESHAN_3'), (-1000564,'Marshal Marris, sir. Corporal Keeshan of the 12th Sabre Regiment returned from battle and reporting for duty!',0,0,0,0,'SAY_CORPORAL_KEESHAN_4'), (-1000565,'Brave adventurer, thank you for rescuing me! I am sure Marshal Marris will reward your kind deed.',0,0,0,0,'SAY_CORPORAL_KEESHAN_5'), @@ -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'), @@ -649,7 +650,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000610,'The mosswalker victim groans in pain.',0,2,0,0,'mosswalker victim EMOTE_PAIN'), (-1000611,'Maybe you make weather better too?',0,0,0,0,'mosswalker victim SAY_RESCUE_1'), -(-1000612,'We saved. You nice, $N.',0,0,0,0,'mosswalker victim SAY_RESCUE_2'), +(-1000612,'We saved. You nice, dryskin.',0,0,0,0,'mosswalker victim SAY_RESCUE_2'), (-1000613,'You save us! Yay for you!',0,0,0,0,'mosswalker victim SAY_RESCUE_3'), (-1000614,'Thank you! You good!',0,0,0,0,'mosswalker victim SAY_RESCUE_4'), @@ -663,7 +664,608 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000621,'All systems on-line. Prepare yourself, we leave shortly.',0,0,0,0,'maxx SAY_START'), (-1000622,'Be careful in there and come back in one piece!',0,0,0,0,'maxx SAY_ALLEY_FAREWELL'), (-1000623,'Proceed.',0,0,0,0,'maxx SAY_CONTINUE'), -(-1000624,'You\'re back! Were you able to get all of the machines?',0,0,0,0,'maxx SAY_ALLEY_FINISH'); +(-1000624,'You\'re back! Were you able to get all of the machines?',0,0,0,0,'maxx SAY_ALLEY_FINISH'), + +(-1000625,'%s gathers the warp chaser\'s blood.',0,2,0,0,'zeppit EMOTE_GATHER_BLOOD'), + +(-1000626,'Intiating energy collection.',0,0,0,0,'depleted golem SAY_GOLEM_CHARGE'), +(-1000627,'Energy collection complete.',0,0,0,0,'depleted golem SAY_GOLEM_COMPLETE'), + +(-1000628,'%s feeds on the freshly-killed warp chaser.',0,2,0,0,'hungry ray EMOTE_FEED'), + +(-1000629,' Damsel in distress over here!',0,0,0,0,'isla starmane - SAY_ISLA_PERIODIC_1'), +(-1000630,'Hello? Help?',0,0,0,0,'isla starmane - SAY_ISLA_PERIODIC_2'), +(-1000631,'Don\'t leave me in here! Cause if you do I will find you!',0,0,0,0,'isla starmane - SAY_ISLA_PERIODIC_3'), +(-1000632,'Ok, let\'s get out of here!',0,0,0,0,'isla starmane - SAY_ISLA_START'), +(-1000633,'You sure you\'re ready? Take a moment.',0,0,0,0,'isla starmane - SAY_ISLA_WAITING'), +(-1000634,'Alright, let\'s do this!',0,0,0,0,'isla starmane - SAY_ISLA_LEAVE_BUILDING'), + +(-1000635,'So then we too are cursed?',0,0,0,0,'ancient vrykul SAY_VRYKUL_CURSED'), +(-1000636,'%s points to the infant.',0,2,0,0,'ancient vrykul EMOTE_VRYKUL_POINT'), +(-1000637,'%s sobs.',0,2,0,0,'ancient vrykul EMOTE_VRYKUL_SOB'), +(-1000638,'The gods have forsaken us! We must dispose of it before Ymiron is notified!',0,0,0,0,'ancient vrykul SAY_VRYKUL_DISPOSE'), +(-1000639,'NO! You cannot! I beg of you! It is our child!',0,0,0,0,'ancient vrykul SAY_VRYKUL_BEG'), +(-1000640,'Then what are we to do, wife? The others cannot find out. Should they learn of this aberration, we will all be executed.',0,0,0,0,'ancient vrykul SAY_VRYKUL_WHAT'), +(-1000641,'I... I will hide it. I will hide it until I find it a home, far away from here...',0,0,0,0,'ancient vrykul SAY_VRYKUL_HIDE'), + +(-1000642,'It\'s a female.',0,5,0,0,'leopard icepaw SAY_ITS_FEMALE'), +(-1000643,'It\'s an angry male!',0,5,0,0,'leopard icepaw SAY_ITS_MALE'), + +(-1000644,'Ouch! That\'s it, I quit the target business!',0,0,0,0,'SAY_LUCKY_HIT_1'), +(-1000645,'My ear! You grazed my ear!',0,0,0,0,'SAY_LUCKY_HIT_2'), +(-1000646,'Not the \'stache! Now I\'m asymmetrical!',0,0,0,5,'SAY_LUCKY_HIT_3'), +(-1000647,'Good shot!',0,0,0,4,'SAY_LUCKY_HIT_APPLE'), +(-1000648,'Stop whining. You\'ve still got your luck.',0,0,0,0,'SAY_DROSTAN_GOT_LUCKY_1'), +(-1000649,'Bah, it\'s an improvement.',0,0,0,11,'SAY_DROSTAN_GOT_LUCKY_2'), +(-1000650,'Calm down lad, it\'s just a birdshot!',0,0,0,0,'SAY_DROSTAN_HIT_BIRD_1'), +(-1000651,'The only thing hurt is your pride, lad! Buck up!',0,0,0,0,'SAY_DROSTAN_HIT_BIRD_2'), + +(-1000652,'Me so hungry! YUM!',0,0,0,71,'dragonmaw peon SAY_PEON_1'), +(-1000653,'Hey... me not feel so good.',0,0,0,0,'dragonmaw peon SAY_PEON_2'), +(-1000654,'You is bad orc... baaad... or... argh!',0,0,0,0,'dragonmaw peon SAY_PEON_3'), +(-1000655,'Time for eating!?',0,0,0,71,'dragonmaw peon SAY_PEON_4'), +(-1000656,'It put the mutton in the stomach!',0,0,0,71,'dragonmaw peon SAY_PEON_5'), + +(-1000657,'Let\'s get the hell out of here.',0,0,0,5,'helice SAY_HELICE_ACCEPT'), +(-1000658,'Listen up, Venture Company goons! Rule #1: Never keep the prisoner near the explosives.',0,0,0,25,'helice SAY_HELICE_EXPLOSIVES_1'), +(-1000659,'Or THIS is what you get.',0,0,0,0,'helice SAY_HELICE_EXPLODE_1'), +(-1000660,'It\'s getting a little hot over here. Shall we move on?',0,0,0,11,'helice SAY_HELICE_MOVE_ON'), +(-1000661,'Oh, look, it\'s another cartload of explosives! Let\'s help them dispose of it.',0,0,0,25,'helice SAY_HELICE_EXPLOSIVES_2'), +(-1000662,'You really shouldn\'t play with this stuff. Someone could get hurt.',0,0,0,5,'helice SAY_HELICE_EXPLODE_2'), +(-1000663,'We made it! Thank you for getting me out of that hell hole. Tell Hemet to expect me!',0,0,0,4,'helice SAY_HELICE_COMPLETE'), + +(-1000664,'The Destructive Ward gains in power.',0,5,0,0,'destructive ward SAY_WARD_POWERUP'), +(-1000665,'The Destructive Ward is fully charged!',0,5,0,0,'destructive ward SAY_WARD_CHARGED'), + +(-1000666,'I can sense the SHADOW on your hearts. There can be no rest for the wicked!',0,1,0,0,'lethon SAY_LETHON_AGGRO'), +(-1000667,'Your wicked souls shall feed my power!',0,1,0,0,'lethon SAY_LETHON_SHADE'), + +(-1000668,'%s releases the last of its energies into the nearby runestone, successfully reactivating it.',0,2,0,0,'infused crystal SAY_DEFENSE_FINISH'), + +(-1000669,'We will locate the origin of the Nightmare through the fragments you collected, $N. From there, we will pull Eranikus through a rift in the Dream. Steel yourself, $C. We are inviting the embodiment of the Nightmare into our world.',0,0,0,0,'remulos SAY_REMULOS_INTRO_1'), +(-1000670,'To Nighthaven! Keep your army close, champion. ',0,0,0,0,'remulos SAY_REMULOS_INTRO_2'), +(-1000671,'The rift will be opened there, above the Lake Elun\'ara. Prepare yourself, $N. Eranikus entry into our world will be wrought with chaos and strife.',0,0,0,0,'remulos SAY_REMULOS_INTRO_3'), +(-1000672,'He will stop at nothing to get to Malfurion\'s physical manifistation. That must not happen... We must keep the beast occupied long enough for Tyrande to arrive.',0,0,0,0,'remulos SAY_REMULOS_INTRO_4'), +(-1000673,'Defend Nightaven, hero...',0,0,0,0,'remulos SAY_REMULOS_INTRO_5'), +(-1000674,'%s has entered our world',0,3,0,0,'eranikus EMOTE_SUMMON_ERANIKUS'), +(-1000675,'Pitful predictable mortals... You know not what you have done! The master\'s will fulfilled. The Moonglade shall be destroyed and Malfurion along with it!',0,1,0,0,'eranikus SAY_ERANIKUS_SPAWN'), +(-1000676,'Fiend! Face the might of Cenarius!',0,1,0,1,'remulos SAY_REMULOS_TAUNT_1'), +(-1000677,'%s lets loose a sinister laugh.',0,2,0,0,'eranikus EMOTE_ERANIKUS_LAUGH'), +(-1000678,'You are certanly not your father, insect. Should it interest me, I would crush you with but a swipe of my claws. Turn Shan\'do Stormrage over to me and your pitiful life will be spared along with the lives of your people.',0,1,0,0,'eranikus SAY_ERANIKUS_TAUNT_2'), +(-1000679,'Who is the predictable one, beast? Surely you did not think that we would summon you on top of Malfurion? Your redemption comes, Eranikus. You will be cleansed of this madness - this corruption.',0,1,0,1,'remulos SAY_REMULOS_TAUNT_3'), +(-1000680,'My redemption? You are bold, little one. My redemption comes by the will of my god.',0,1,0,0,'eranikus SAY_ERANIKUS_TAUNT_4'), +(-1000681,'%s roars furiously.',0,2,0,0,'eranikus EMOTE_ERANIKUS_ATTACK'), +(-1000682,'Hurry, $N! We must find protective cover!',0,0,0,0,'remulos SAY_REMULOS_DEFEND_1'), +(-1000683,'Please, champion, protect our people.',0,0,0,1,'remulos SAY_REMULOS_DEFEND_2'), +(-1000684,'Rise, servants of the Nightmare! Rise and destroy this world! Let there be no survivors...',0,1,0,0,'eranikus SAY_ERANIKUS_SHADOWS'), +(-1000685,'We will battle these fiends, together! Nighthaven\'s Defenders are also among us. They will fight to the death if asked. Now, quickly, we must drive these aberations back to the Nightmare. Destroy them all!',0,0,0,1,'remulos SAY_REMULOS_DEFEND_3'), +(-1000686,'Where is your savior? How long can you hold out against my attacks?',0,1,0,0,'eranikus SAY_ERANIKUS_ATTACK_1'), +(-1000687,'Defeated my minions? Then face me, mortals!',0,1,0,0,'eranikus SAY_ERANIKUS_ATTACK_2'), +(-1000688,'Remulos, look how easy they fall before me? You can stop this, fool. Turn the druid over to me and it will all be over...',0,1,0,0,'eranikus SAY_ERANIKUS_ATTACK_3'), +(-1000689,'Elune, hear my prayers. Grant us serenity! Watch over our fallen...',0,1,0,0,'tyrande SAY_TYRANDE_APPEAR'), +(-1000690,'Tend to the injuries of the wounded, sisters!',0,0,0,0,'tyrande SAY_TYRANDE_HEAL'), +(-1000691,'Seek absolution, Eranikus. All will be forgiven...',0,1,0,0,'tyrande SAY_TYRANDE_FORGIVEN_1'), +(-1000692,'You will be forgiven, Eranikus. Elune will always love you. Break free of the bonds that command you!',0,1,0,0,'tyrande SAY_TYRANDE_FORGIVEN_2'), +(-1000693,'The grasp of the Old Gods is unmoving. He is consumed by their dark thoughts... I... I... I cannot... cannot channel much longer... Elune aide me.',0,0,0,0,'tyrande SAY_TYRANDE_FORGIVEN_3'), +(-1000694,'IT BURNS! THE PAIN.. SEARING...',0,1,0,0,'eranikus SAY_ERANIKUS_DEFEAT_1'), +(-1000695,'WHY? Why did this happen to... to me? Where were you Tyrande? Where were you when I fell from the grace of Elune?',0,1,0,0,'eranikus SAY_ERANIKUS_DEFEAT_2'), +(-1000696,'I... I feel... I feel the touch of Elune upon my being once more... She smiles upon me... Yes... I...', 0,1,0,0,'eranikus SAY_ERANIKUS_DEFEAT_3'), +(-1000697,'%s is wholly consumed by the Light of Elune. Tranquility sets in over the Moonglade',0,2,0,0,'eranikus EMOTE_ERANIKUS_REDEEM'), +(-1000698,'%s falls to one knee.',0,2,0,0,'tyrande EMOTE_TYRANDE_KNEEL'), +(-1000699,'Praise be to Elune... Eranikus is redeemed.',0,1,0,0,'tyrande SAY_TYRANDE_REDEEMED'), +(-1000700,'For so long, I was lost... The Nightmare\'s corruption had consumed me... And now, you... all of you.. you have saved me. Released me from its grasp.',0,0,0,0,'eranikus SAY_REDEEMED_1'), +(-1000701,'But... Malfurion, Cenarius, Ysera... They still fight. They need me. I must return to the Dream at once.', 0,0,0,0,'eranikus SAY_REDEEMED_2'), +(-1000702,'My lady, I am unworthy of your prayer. Truly, you are an angel of light. Please, assist me in returning to the barrow den so that I may return to the Dream. I like Malfurion, also have a love awaiting me... I must return to her... to protect her...', 0,0,0,0,'eranikus SAY_REDEEMED_3'), +(-1000703,'And heroes... I hold that which you seek. May it once more see the evil dissolved. Remulos, see to it that our champion receives the shard of the Green Flight.',0,0,0,0,'eranikus SAY_REDEEMED_4'), +(-1000704,'It will be done, Eranikus. Be well, ancient one.',0,0,0,0,'remulos SAY_REMULOS_OUTRO_1'), +(-1000705,'Let us leave Nighthave, hero. Seek me out at the grove.',0,0,0,0,'remulos SAY_REMULOS_OUTRO_2'), +(-1000706,'Your world shall suffer an unmerciful end. The Nightmare comes for you!',0,0,0,0,'eranikus SAY_ERANIKUS_KILL'), + +(-1000707,'This blue light... It\'s strange. What do you think it means?',0,0,0,0,'Ranshalla SAY_ENTER_OWL_THICKET'), +(-1000708,'We\'ve found it!',0,0,0,0,'Ranshalla SAY_REACH_TORCH_1'), +(-1000709,'Please, light this while I am channeling',0,0,0,0,'Ranshalla SAY_REACH_TORCH_2'), +(-1000710,'This is the place. Let\'s light it.',0,0,0,0,'Ranshalla SAY_REACH_TORCH_3'), +(-1000711,'Let\'s find the next one.',0,0,0,0,'Ranshalla SAY_AFTER_TORCH_1'), +(-1000712,'We must continue on now.',0,0,0,0,'Ranshalla SAY_AFTER_TORCH_2'), +(-1000713,'It is time for the final step; we must activate the altar.',0,0,0,0,'Ranshalla SAY_REACH_ALTAR_1'), +(-1000714,'I will read the words carved into the stone, and you must find a way to light it.',0,0,0,0,'Ranshalla SAY_REACH_ALTAR_2'), +(-1000715,'The altar is glowing! We have done it!',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_1'), +(-1000716,'What is happening? Look!',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_2'), +(-1000717,'It has been many years...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_3'), +(-1000718,'Who has disturbed the altar of the goddess?',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_4'), +(-1000719,'Please, priestesses, forgive us for our intrusion. We do not wish any harm here.',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_5'), +(-1000720,'We only wish to know why the wildkin guard this area...',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_6'), +(-1000721,'Enu thora\'serador. This is a sacred place.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_7'), +(-1000722,'We will show you...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_8'), +(-1000723,'Look above you; thara dormil dorah...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_9'), +(-1000724,'This gem once allowed direct communication with Elune, herself.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_10'), +(-1000725,'Through the gem, Elune channeled her infinite wisdom...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_11'), +(-1000726,'Realizing that the gem needed to be protected, we turned to the goddess herself.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_12'), +(-1000727,'Soon after, we began to have visions of a creature... A creature with the feathers of an owl, but the will and might of a bear...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_13'), +(-1000728,'It was on that day that the wildkin were given to us. Fierce guardians, the goddess assigned the wildkin to protect all of her sacred places.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_14'), +(-1000729,'Anu\'dorini Talah, Ru shallora enudoril.',0,0,0,0,'Voice of Elune SAY_VOICE_ALTAR_15'), +(-1000730,'But now, many years later, the wildkin have grown more feral, and without the guidance of the goddess, they are confused...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_16'), +(-1000731,'Without a purpose, they wander... But many find their way back to the sacred areas that they once were sworn to protect.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_17'), +(-1000732,'Wildkin are inherently magical; this power was bestowed upon them by the goddess.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_18'), +(-1000733,'Know that wherever you might find them in the world, they are protecting something of importance, as they were entrusted to do so long ago.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_19'), +(-1000734,'Please, remember what we have shown you...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_20'), +(-1000735,'Farewell.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_21'), +(-1000736,'Thank you for you help, $n. I wish you well in your adventures.',0,0,0,0,'Ranshalla SAY_QUEST_END_1'), +(-1000737,'I want to stay here and reflect on what we have seen. Please see Erelas and tell him what we have learned.',0,0,0,0,'Ranshalla SAY_QUEST_END_2'), +(-1000738,'%s begins chanting a strange spell...',0,2,0,0,'Ranshalla EMOTE_CHANT_SPELL'), +(-1000739,'Remember, I need your help to properly channel. I will ask you to aid me several times in our path, so please be ready.',0,0,0,0,'Ranshalla SAY_QUEST_START'), + +(-1000740,'We must act quickly or shall be lost!',0,0,0,1,'SAY_ANACHRONOS_INTRO_1'), +(-1000741,'My forces cannot overcome the Qiraji defenses. We will not be able to get close enough to place our precious barrier, dragon.',0,0,0,0,'SAY_FANDRAL_INTRO_2'), +(-1000742,'There is a way...',0,0,0,22,'SAY_MERITHRA_INTRO_3'), +(-1000743,'%s nods knowingly.',0,2,0,0,'EMOTE_ARYGOS_NOD'), +(-1000744,'Aye, Fandral, remember these words: Let not your grief guide your faith. These thoughts you hold... dark places you go, night elf.Absolution cannot be had through misguided vengeance.',0,0,0,1,'SAY_CAELESTRASZ_INTRO_4'), +(-1000745,'%s glances at her compatriots.',0,2,0,0,'EMOTE_MERITHRA_GLANCE'), +(-1000746,'We will push him back, Anachronos. This is wow. Uphold your end of this task. Let not your hands falter as you seal our fates behind the barrier.',0,0,0,1,'SAY_MERITHRA_INTRO_5'), +(-1000747,'Succumb to the endless dream, little ones. Let it comsume you!',0,1,0,22,'SAY_MERITHRA_ATTACK_1'), +(-1000748,'Anachronos, the diversion will give you an the young druid time enough to seal the gate. Do not falter. Now, let us see how they deal with chaotic magic.',0,0,0,1,'SAY_ARYGOS_ATTACK_2'), +(-1000749,'Let them feelt the wrath of the blue flight! May Malygos protect me!',0,1,0,22,'SAY_ARYGOS_ATTACK_3'), +(-1000750,'Do not forget sacrifices made on this day, night elf. We have all suffered immensely at the hands of these beasts.',0,0,0,1,'SAY_CAELESTRASZ_ATTACK_4'), +(-1000751,'Alexstrasza, give me the resolve to drive your enemies back.',0,1,0,22,'SAY_CAELESTRASZ_ATTACK_5'), +(-1000752,'NOW,STAGHELM! WE GO NOW! Prepare your magic!',0,0,0,22,'SAY_ANACHRONOS_SEAL_1'), +(-1000753,'It is done, dragon. Lead the way!',0,0,0,25,'SAY_FANDRAL_SEAL_2'), +(-1000754,'Stay close.',0,0,0,0,'SAY_ANACHRONOS_SEAL_3'), +(-1000755,'The sands of time will halt, but only for a moment! I will now conjure the barrier.',0,0,0,0,'SAY_ANACHRONOS_SEAL_4'), +(-1000756,'FINISH THE SPELL, STAGHELM! I CANNOT HOLD THE GLYPHS OF WARDING IN PLACE MUCH LONGER! CALL FORTH THE ROOTS!', 0,0,0,0,'SAY_ANACHRONOS_SEAL_5'), +(-1000757,'Ancient ones guide my hand... Wake from your slumber! WAKE AND SEAL THIS CURSED PLACE!',0,0,0,0, 'SAY_FANDRAL_SEAL_6'), +(-1000758,'%s falls to one knee - exhausted.',0,2,0,0,'EMOTE_FANDRAL_EXHAUSTED'), +(-1000759,'It... It is over, Lord Staghelm. We are victorious. Albeit the cost for this victory was great.',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_1'), +(-1000760,'There is but one duty that remains',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_2'), +(-1000761,'Before I leave this place, I make one final offering for you, Lord Staghelm. Should a time arise in which you must gain entry to this accursed fortress, use the scepter of the shifting sands on the sacred gong. The magic holding the barrier together will dissipate an the horrors of the Ahn\'Qiraj will be unleashed upon the world once more.',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_3'), +(-1000762,'%s hands the Scepter of the Shifting Sands to $N.',0,2,0,0,'EMOTE_ANACHRONOS_SCEPTER'), +(-1000763,'After the savagery that my people have witnessed and felt, you expect me to accept another burden, dragon? Surely you are mad.',0,0,0,1,'SAY_FANDRAL_EPILOGUE_4'), +(-1000764,'I want nothing to do with Silithus, the Qiraji and least of all, any damed dragons!',0,0,0,1,'SAY_FANDRAL_EPILOGUE_5'), +(-1000765,'%s hurls the Scepter of the Shifting Sands into the barrier, shattering it.',0,2,0,0,'EMOTE_FANDRAL_SHATTER'), +(-1000766,'Lord Staghelm, where are you going? You would shatter our bond for the sake of pride?',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_6'), +(-1000767,'My son\'s soul will find no comfort in this hollow victory, dragon! I will have him back. Though it takes a millenia. I WILL have my son back!',0,0,0,1,'SAY_FANDRAL_EPILOGUE_7'), +(-1000768,'%s shakes his head in disappointment.',0,2,0,25,'EMOTE_ANACHRONOS_DISPPOINTED'), +(-1000769,'%s kneels down to pickup the fragments of the shattered scepter.',0,2,0,0,'EMOTE_ANACHRONOS_PICKUP'), +(-1000770,'And now you know all that there is to know, mortal',0,0,0,0,'SAY_ANACHRONOS_EPILOGUE_8'), + +(-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'), +(-1000773,'Assassins from that cult you found... Let\'s get moving before someone else finds us out here.',0,0,0,0,'Feero Ironhand SAY_FIRST_AMBUSH_END'), +(-1000774,'Hold! I sense an evil presence... Undead!',0,0,0,0,'Feero Ironhand SAY_SECOND_AMBUSH_START'), +(-1000775,'A $C! Slaying him would please the master. Attack!',0,0,0,0,'Forsaken Scout SAY_SCOUT_SECOND_AMBUSH'), +(-1000776,'They\'re coming out of the woodwork today. Let\'s keep moving or we may find more things that want me dead.',0,0,0,0,'Feero Ironhand SAY_SECOND_AMBUSH_END'), +(-1000777,'These three again?',0,0,0,0,'Feero Ironhand SAY_FINAL_AMBUSH_START'), +(-1000778,'Not quite so sure of yourself without the Purifier, hm?',0,0,0,0,'Balizar the Umbrage SAY_BALIZAR_FINAL_AMBUSH'), +(-1000779,'I\'ll finish you off for good this time!',0,0,0,0,'Feero Ironhand SAY_FINAL_AMBUSH_ATTACK'), +(-1000780,'Well done! I should be fine on my own from here. Remember to talk to Delgren when you return to Maestra\'s Post in Ashenvale.',0,0,0,0,'Feero Ironhand SAY_QUEST_END'), + +(-1000781,'I knew Lurielle would send help! Thank you, friend, and give Lurielle my thanks as well!',0,0,0,0,'Chill Nymph SAY_FREE_1'), +(-1000782,'Where am I? What happend to me? You... you freed me?',0,0,0,0,'Chill Nymph SAY_FREE_2'), +(-1000783,'Thank you. I thought I would die without seeing my sisters again!',0,0,0,0,'Chill Nymph SAY_FREE_3'), + +(-1000784,'Thanks $N. Now let\'s get out of here!',0,0,0,0,'melizza SAY_MELIZZA_START'), +(-1000785,'We made it! Thanks again! I\'m going to run ahead!',0,0,0,0,'melizza SAY_MELIZZA_FINISH'), +(-1000786,'Hey Hornizz! I\'m back! And there are some people behind me who helped me out of a jam.',0,0,0,1,'melizza SAY_MELIZZA_1'), +(-1000787,'We\'re going to have to scratch the Maraudines off our list. Too hard to work with...',0,0,0,1,'melizza SAY_MELIZZA_2'), +(-1000788,'Well, I\'m off to the Gelkis. They\'re not as dumb as the Maraudines, but they\'re more reasonable.',0,0,0,3,'melizza SAY_MELIZZA_3'), + +(-1000789,'Well, now or never I suppose. Remember, once we get to the road safety, return to Terenthis to let him know we escaped.',0,0,0,0,'volcor SAY_START'), +(-1000790,'We made it, My friend. Remember to find Terenthis and let him know we\'re safe. Thank you again.',0,0,0,0,'volcor SAY_END'), +(-1000791,'Here they come.',0,0,0,0,'volcor SAY_FIRST_AMBUSH'), +(-1000792,'We can overcome these foul creatures.',0,0,0,0,'volcor SAY_AGGRO_1'), +(-1000793,'We shall earn our deaths at the very least!',0,0,0,0,'volcor SAY_AGGRO_2'), +(-1000794,'Don\'t give up! Fight, to the death!',0,0,0,0,'volcor SAY_AGGRO_3'), + +(-1000795,'OK boss, I get back to tree hitting.',0,0,0,0,'lazy peon SAY_AWAKE_1'), +(-1000796,'Sleepy... so sleepy...',0,0,0,0,'lazy peon SAY_AWAKE_2'), + +(-1000797,'%s squawks and heads toward Veil Shalas. Hurry and follow!',0,2,0,0,'skywing SAY_SKYWING_START'), +(-1000798,'%s pauses briefly before the tree and then heads inside.',0,2,0,0,'skywing SAY_SKYWING_TREE_DOWN'), +(-1000799,'%s seems to be looking for something. He wants you to follow.',0,2,0,0,'skywing SAY_SKYWING_TREE_UP'), +(-1000800,'%s flies to the platform below! You\'d better jump if you want to keep up. Hurry!',0,2,0,0,'skywing SAY_SKYWING_JUMP'), +(-1000801,'%s bellows a loud squawk!',0,2,0,0,'skywing SAY_SKYWING_SUMMON'), +(-1000802,'Free at last from that horrible curse! Thank you! Please send word to Rilak the Redeemed that I am okay. My mission lies in Skettis. Terokk must be defeated!',0,0,0,0,'skywing SAY_SKYWING_END'), + +(-1000803,'You do not fight alone, %n! Together, we will banish this spawn of hellfire!',0,1,0,0,'Oronok SAY_ORONOK_TOGETHER'), +(-1000804,'We will fight when you are ready.',0,0,0,0, 'Oronok SAY_ORONOK_READY'), +(-1000805,'We will set the elements free of your grasp by force!',0,1,0,0,'Oronok SAY_ORONOK_ELEMENTS'), +(-1000806,'What say the elements, Torlok? I only hear silence.',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_1'), +(-1000807,'I hear what you hear, brother. Look behind you...',0,0,0,1,'Torlok SAY_TORLOK_EPILOGUE_2'), +(-1000808,'They are redeemed! Then we have won?',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_3'), +(-1000809,'It is now as it should be, shaman. You have done well.',0,0,0,0,'Spirit of Earth SAY_EARTH_EPILOGUE_4'), +(-1000810,'Yes... Well enough for the elements that are here, but the cipher is known to another... The spirits of fire are in turmoil... If this force is not stopped, the world where these mortals came from will cease.',0,0,0,0,'Spirit of Fire SAY_FIRE_EPILOGUE_5'), +(-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'), + +(-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'); -- -1 033 000 SHADOWFANG KEEP INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -690,18 +1292,62 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1033016,'Arrrgh!',0,0,0,0,'deathstalker vincent SAY_VINCENT_DIE'), (-1033017,'You, too, shall serve!',5793,1,0,0,'boss_arugal YELL_AGGRO'), (-1033018,'Another Falls!',5795,1,0,0,'boss_arugal YELL_KILLED_PLAYER'), -(-1033019,'Release your rage!',5797,1,0,0,'boss_arugal YELL_COMBAT'); +(-1033019,'Release your rage!',5797,1,0,0,'boss_arugal YELL_COMBAT'), + +(-1033020,'Did they bother to tell you who I am and why I am doing this?',0,0,0,0,'hummel SAY_INTRO_1'), +(-1033021,'...or are they just using you like they do everybody else?',0,0,0,0,'hummel SAY_INTRO_2'), +(-1033022,'But what does it matter. It is time for this to end.',0,0,0,0,'hummel SAY_INTRO_3'), +(-1033023,'Baxter! Get in there and help! NOW!',0,0,0,0,'hummel SAY_CALL_BAXTER'), +(-1033024,'It is time, Frye! Attack!',0,0,0,0,'hummel SAY_CALL_FRYE'), +(-1033025,'...please don\'t think less of me.',0,0,0,0,'hummel SAY_DEATH'); -- -1 034 000 STOCKADES -- -1 036 000 DEADMINES INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1036000,'You there, check out that noise!',5775,1,7,0,'smite INST_SAY_ALARM1'), -(-1036001,'We\'re under attack! A vast, ye swabs! Repel the invaders!',5777,1,7,0,'smite INST_SAY_ALARM2'); +(-1036000,'You there! Check out that noise.',5775,6,7,0,'smite INST_SAY_ALARM1'), +(-1036001,'We\'re under attack! A vast, ye swabs! Repel the invaders!',5777,6,7,0,'smite INST_SAY_ALARM2'), +(-1036002,'You land lubbers are tougher than I thought! I\'ll have to improvise!',5778,0,0,21,'smite SAY_PHASE_2'), +(-1036003,'D\'ah! Now you\'re making me angry!',5779,0,0,15,'smite SAY_PHASE_3'); -- -1 043 000 WAILING CAVERNS +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1043000,'At last! Naralex can be awakened! Come aid me, brave adventurers!',0,6,0,0,'Disciple of Naralex - SAY_INTRO'), +(-1043001,'I must make the necessary preparations before the awakening ritual can begin. You must protect me!',0,0,0,0,'SAY_PREPARE'), +(-1043002,'These caverns were once a temple of promise for regrowth in the Barrens. Now, they are the halls of nightmares.',0,0,0,0,'Disciple of Naralex - SAY_FIRST_CORNER'), +(-1043003,'Come. We must continue. There is much to be done before we can pull Naralex from his nightmare.',0,0,0,0,'Disciple of Naralex - SAY_CONTINUE'), +(-1043004,'Within this circle of fire I must cast the spell to banish the spirits of the slain Fanglords.',0,0,0,0,'Disciple of Naralex - SAY_CIRCLE_BANISH'), +(-1043005,'The caverns have been purified. To Naralex\'s chamber we go!',0,0,0,0,'Disciple of Naralex - SAY_PURIFIED'), +(-1043006,'Beyond this corridor, Naralex lies in fitful sleep. Let us go awaken him before it is too late.',0,0,0,0,'Disciple of Naralex - SAY_NARALEX_CHAMBER'), +(-1043007,'Protect me brave souls as I delve into the Emerald Dream to rescue Naralex and put an end to this corruption!',0,1,0,0,'Disciple of Naralex - SAY_BEGIN_RITUAL'), +(-1043008,'%s begins to perform the awakening ritual on Naralex.',0,2,0,0,'Disciple of Naralex - EMOTE_RITUAL_BEGIN'), +(-1043009,'%s tosses fitfully in troubled sleep.',0,2,0,0,'Naralex - EMOTE_NARALEX_AWAKE'), +(-1043010,'%s writhes in agony. The Disciple seems to be breaking through.',0,2,0,0,'Naralex - EMOTE_BREAK_THROUGH'), +(-1043011,'%s dreams up a horrendous vision. Something stirs beneath the murky waters.',0,2,0,0,'Naralex - EMOTE_VISION'), +(-1043012,'This $N is a minion from Naralex\'s nightmare no doubt!.',0,0,0,0,'Disciple of Naralex - SAY_MUTANUS'), +(-1043013,'I AM AWAKE, AT LAST!',5789,1,0,0,'Naralex - SAY_NARALEX_AWAKE'), +(-1043014,'At last! Naralex awakes from the nightmare.',0,0,0,0,'Disciple of Naralex - SAY_AWAKE'), +(-1043015,'Ah, to be pulled from the dreaded nightmare! I thank you, my loyal Disciple, along with your brave companions.',0,0,0,0,'Naralex - SAY_NARALEX_THANKYOU'), +(-1043016,'We must go and gather with the other Disciplies. There is much work to be done before I can make another attempt to restore the Barrens. Farewell, brave souls!',0,0,0,0,'Naralex - SAY_FAREWELL'), +(-1043017,'Attacked! Help get this $N off of me!',0,0,0,0,'Disciple of Naralex - SAY_AGGRO_1'), +(-1043018,'Help!',0,0,0,0,'Disciple of Naralex - SAY_AGGRO_2'), +(-1043019,'Deal with this $N! I need to prepare to awake Naralex!',0,0,0,0,'Disciple of Naralex - SAY_AGGRO_3'); -- -1 047 000 RAZORFEN KRAUL +INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,comment) VALUES +(-1047000,'Woo hoo! Finally getting out of here. It\'s going to be rough though. Keep your eyes peeled for trouble.',0,0,0,0,'willix SAY_READY'), +(-1047001,'Up there is where Charlga Razorflank resides. Blasted old crone.',0,0,0,25,'willix SAY_1'), +(-1047002,'There\'s blueleaf tuber in this trench! It\'s like gold waiting to be mined I tell you!',0,0,0,0,'willix SAY_2'), +(-1047003,'There could be danger around every corner here.',0,0,0,0,'willix SAY_3'), +(-1047004,'I don\'t see how these foul animals live in this place... sheesh it smells!',0,0,0,0,'willix SAY_4'), +(-1047005,'I think I see a way for us to get out of this big twisted mess of a bramble.',0,0,0,0,'willix SAY_5'), +(-1047006,'Glad to be out of that wretched trench. Not much nicer up here though!',0,0,0,0,'willix SAY_6'), +(-1047007,'Finally! I\'ll be glad to get out of this place.',0,0,0,0,'willix SAY_7'), +(-1047008,'I think I\'ll rest a moment and catch my breath before heading back to Ratchet. Thanks for all the help!',0,0,0,0,'willix SAY_END'), +(-1047009,'$N heading this way fast! To arms!',0,0,0,0,'willix SAY_AGGRO_1'), +(-1047010,'Eek! $N coming right at us!',0,0,0,0,'willix SAY_AGGRO_2'), +(-1047011,'Egads! $N on me!',0,0,0,0,'willix SAY_AGGRO_3'), +(-1047012,'Help! Get this $N off of me!',0,0,0,0,'willix SAY_AGGRO_4'); -- -1 048 000 BLACKFATHOM DEEPS @@ -711,40 +1357,43 @@ 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 (-1090000,'With your help, I can evaluate these tunnels.',0,0,0,1,'emi shortfuse SAY_START'), -(-1090001,'Let\'s see if we can find out where these Troggs are coming from.... and put a stop to the invasion!',0,0,0,1,'emi shortfuse SAY_INTRO_1'), -- ' -(-1090002,'Such devastation... what a horrible mess....',0,0,0,5,'emi shortfuse SAY_INTRO_2'), -(-1090003,'It\'s quiet here....',0,0,0,1,'emi shortfuse SAY_INTRO_3'), -- ' +(-1090001,'Let\'s see if we can find out where these Troggs are coming from.... and put a stop to the invasion!',0,0,0,1,'emi shortfuse SAY_INTRO_1'), +(-1090002,'Such devastation... what a horrible mess...',0,0,0,5,'emi shortfuse SAY_INTRO_2'), +(-1090003,'It\'s quiet here....',0,0,0,1,'emi shortfuse SAY_INTRO_3'), (-1090004,'...too quiet.',0,0,0,1,'emi shortfuse SAY_INTRO_4'), (-1090005,'Look! Over there at the tunnel wall!',0,0,0,25,'emi shortfuse SAY_LOOK_1'), (-1090006,'Trogg incursion! Defend me while I blast the hole closed!',0,0,0,5,'emi shortfuse SAY_HEAR_1'), -(-1090007,'Get this, $n off of me!',0,0,0,0,'emi shortfuse SAY_AGGRO'), -(-1090008,'I don\'t think one charge is going to cut it. Keep fending them off!',0,0,0,0,'emi shortfuse SAY_CHARGE_1'), -- ' +(-1090007,'Get this, $n off of me!',0,0,0,0,'emi shortfuse SAY_AGGRO_1'), +(-1090008,'I don\'t think one charge is going to cut it. Keep fending them off!',0,0,0,0,'emi shortfuse SAY_CHARGE_1'), (-1090009,'The charges are set. Get back before they blow!',0,0,0,5,'emi shortfuse SAY_CHARGE_2'), (-1090010,'Incoming blast in 10 seconds!',0,1,0,5,'emi shortfuse SAY_BLOW_1_10'), -(-1090011,'Incoming blast in 5 seconds. Clear the tunnel!',0,1,0,5,'emi shortfuse SAY_BLOW_1_5'), +(-1090011,'Incoming blast in 5 seconds. Clear the tunnel! Stay back!',0,1,0,5,'emi shortfuse SAY_BLOW_1_5'), (-1090012,'FIRE IN THE HOLE!',0,1,0,25,'emi shortfuse SAY_BLOW_1'), -(-1090013,'Well done! without your help I would have never been able to thwart that wave of troggs.',0,0,0,4,'emi shortfuse SAY_FINISH_1'), +(-1090013,'Well done! Without your help I would have never been able to thwart that wave of troggs.',0,0,0,4,'emi shortfuse SAY_FINISH_1'), (-1090014,'Did you hear something?',0,0,0,6,'emi shortfuse SAY_LOOK_2'), (-1090015,'I heard something over there.',0,0,0,25,'emi shortfuse SAY_HEAR_2'), (-1090016,'More troggs! Ward them off as I prepare the explosives!',0,0,0,0,'emi shortfuse SAY_CHARGE_3'), -(-1090017,'The final charges are set. Stand back!',0,0,0,1,'emi shortfuse SAY_CHARGE_4'), -(-1090018,'10 seconds to blast! Stand back!',0,1,0,5,'emi shortfuse SAY_BLOW_2_10'), -(-1090019,'5 seconds until detonation!',0,1,0,5,'emi shortfuse SAY_BLOW_2_5'), -(-1090020,'Good work! I detonate the explosives that no more troggs can reach the surface.',0,0,0,1,'emi shortfuse SAY_BLOW_SOON'), +(-1090017,'The final charge is set. Stand back!',0,0,0,1,'emi shortfuse SAY_CHARGE_4'), +(-1090018,'10 seconds to blast! Stand back!!!',0,1,0,5,'emi shortfuse SAY_BLOW_2_10'), +(-1090019,'5 seconds until detonation!!!!!',0,1,0,5,'emi shortfuse SAY_BLOW_2_5'), +(-1090020,'Nice work! I\'ll set off the charges to prevent any more troggs from making it to the surface.',0,0,0,1,'emi shortfuse SAY_BLOW_SOON'), (-1090021,'FIRE IN THE HOLE!',0,1,0,0,'emi shortfuse SAY_BLOW_2'), -(-1090022,'Superb! Because of your help, my people stand a chance of re-taking our belowed city. Three cheers to you!',0,0,0,0,'emi shortfuse SAY_FINISH_2'), +(-1090022,'Superb! Because of your help, my people stand a chance of re-taking our beloved city. Three cheers to you!',0,0,0,0,'emi shortfuse SAY_FINISH_2'), (-1090023,'We come from below! You can never stop us!',0,1,0,1,'grubbis SAY_GRUBBIS_SPAWN'), (-1090024,'Usurpers! Gnomeregan is mine!',5807,1,0,0,'thermaplugg SAY_AGGRO'), (-1090025,'My machines are the future! They\'ll destroy you all!',5808,1,0,0,'thermaplugg SAY_PHASE'), (-1090026,'Explosions! MORE explosions! I\'ve got to have more explosions!',5809,1,0,0,'thermaplugg SAY_BOMB'), -(-1090027,'...and stay dead! He got served',5810,1,0,0,'thermaplugg SAY_SLAY'); +(-1090027,'...and stay dead! He got served',5810,1,0,0,'thermaplugg SAY_SLAY'), + +(-1090028,'$n attacking! Help!',0,0,0,0,'emi shortfuse SAY_AGGRO_2'); -- -1 109 000 SUNKEN TEMPLE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -752,15 +1401,32 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1109001,'Be steadfast, champion. I know why it is that you are here and I know what it is that you seek. Eranikus will not give up the shard freely. He has been twisted... twisted by the same force that you seek to destroy.',0,0,0,0,'malfurion stormrge SAY_MALFURION1'), (-1109002,'Are you really surprised? Is it hard to believe that the power of an Old God could reach even inside the Dream? It is true - Eranikus, Tyrant of the Dream, wages a battle against us all. The Nightmare follows in his wake of destruction.',0,0,0,0,'malfurion stormrge SAY_MALFURION2'), (-1109003,'Understand this, Eranikus wants nothing more than to be brought to Azeroth from the Dream. Once he is out, he will stop at nothing to destroy my physical manifestation. This, however, is the only way in which you could recover the scepter shard.',0,0,0,0,'malfurion stormrge SAY_MAFLURION3'), -(-1109004,'You will bring him back into this world, champion.',0,0,0,0,'malfurion Stormrge SAY_MALFURION4'); +(-1109004,'You will bring him back into this world, champion.',0,0,0,0,'malfurion Stormrge SAY_MALFURION4'), + +(-1109005,'The shield be down! Rise up Atal\'ai! Rise up!',5861,6,0,0,'jammalan SAY_JAMMALAN_INTRO'), + +(-1109006,'HAKKAR LIVES!',5870,1,0,0,'avatar SAY_AVATAR_BRAZIER_1'), +(-1109007,'I TASTE THE BLOOD OF LIFE!',5868,1,0,0,'avatar SAY_AVATAR_BRAZIER_2'), +(-1109008,'I DRAW CLOSER TO YOUR WORLD!',5867,1,0,0,'avatar SAY_AVATAR_BRAZIER_3'), +(-1109009,'I AM NEAR!',5869,1,0,0,'avatar SAY_AVATAR_BRAZIER_4'), +(-1109010,'I AM HERE!',0,1,0,0,'avatar SAY_AVATAR_SPAWN'); -- -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'), +(-1129007,'You\'ll rue the day you crossed me, $N',0,0,0,0,'belnistrasz SAY_AGGRO_1'), +(-1129008,'Incoming $N - look sharp, friends!',0,0,0,0,'belnistrasz SAY_AGGRO_2'), +(-1129009,'Three minutes left -- I can feel the energy starting to build! Keep up the solid defense!',0,1,0,0,'belnistrasz SAY_3_MIN'), +(-1129010,'Just two minutes to go! We\'re half way there, but don\'t let your guard down!',0,1,0,0,'belnistrasz SAY_2_MIN'), +(-1129011,'One more minute! Hold on now, the ritual is about to take hold!',0,1,0,0,'belnistrasz SAY_1_MIN'), +(-1129012,'That\'s it -- we made it! The ritual is set in motion, and idol fires are about to go out for good! You truly are the heroes I thought you would be!',0,1,0,4,'belnistrasz SAY_FINISH'); -- -1 189 000 SCARLET MONASTERY INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -778,20 +1444,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'), @@ -810,8 +1477,38 @@ 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 +(-1229000,'%s begins to regain its strength!',0,2,0,0,'pyroguard EMOTE_BEGIN'), +(-1229001,'%s is nearly at full strength!',0,2,0,0,'pyroguard EMOTE_NEAR'), +(-1229002,'%s regains its power and breaks free of its bonds!',0,2,0,0,'pyroguard EMOTE_FULL'), +(-1229003,'Ha! Ha! Ha! Thank you for freeing me, fools. Now let me repay you by charring the flesh from your bones.',0,1,0,0,'pyroguard SAY_FREE'), + +(-1229004,'Excellent... it would appear as if the meddlesome insects have arrived just in time to feed my legion. Welcome, mortals!',0,1,0,1,'nefarius SAY_INTRO_1'), +(-1229005,'Let not even a drop of their blood remain upon the arena floor, my children. Feast on their souls!',0,1,0,1,'nefarius SAY_INTRO_2'), +(-1229006,'Foolsss...Kill the one in the dress!',0,1,0,0,'nefarius SAY_ATTACK_1'), +(-1229007,'Sire, let me join the fray! I shall tear their spines out with my bare hands!',0,1,0,1,'rend SAY_REND_JOIN'), +(-1229008,'Concentrate your attacks upon the healer!',0,1,0,0,'nefarius SAY_ATTACK_2'), +(-1229009,'Inconceivable!',0,1,0,0,'nefarius SAY_ATTACK_3'), +(-1229010,'Do not force my hand, children! I shall use your hides to line my boots.',0,1,0,0,'nefarius SAY_ATTACK_4'), +(-1229011,'Defilers!',0,1,0,0,'rend SAY_LOSE_1'), +(-1229012,'Impossible!',0,1,0,0,'rend SAY_LOSE_2'), +(-1229013,'Your efforts will prove fruitless. None shall stand in our way!',0,1,0,0,'nefarius SAY_LOSE_3'), +(-1229014,'THIS CANNOT BE!!! Rend, deal with these insects.',0,1,0,1,'nefarius SAY_LOSE_4'), +(-1229015,'With pleasure...',0,1,0,0,'rend SAY_REND_ATTACK'), +(-1229016,'The Warchief shall make quick work of you, mortals. Prepare yourselves!',0,1,0,25,'nefarius SAY_WARCHIEF'), +(-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'), + +(-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 @@ -825,7 +1522,34 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-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'); +(-1230009,'Good Riddance!',0,1,0,0,'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'); -- -1 249 000 ONYXIA'S LAIR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -872,6 +1596,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1269028,'Gul\'dan speaks the truth! We should return at once to tell our brothers of the news! Retreat back trought the portal!',0,1,0,0,'medivh SAY_ORCS_ANSWER'); -- -1 289 000 SCHOLOMANCE +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1289000,'School is in session!',0,1,0,0,'gandling SAY_GANDLING_SPAWN'); -- -1 309 000 ZUL'GURUB INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -904,10 +1630,15 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1309020,'PRIDE HERALDS THE END OF YOUR WORLD. COME, MORTALS! FACE THE WRATH OF THE SOULFLAYER!',8414,1,0,0,'hakkar SAY_AGGRO'), (-1309021,'Fleeing will do you no good, mortals!',0,1,0,0,'hakkar SAY_FLEEING'), -(-1309022,'You dare set foot upon Hakkari holy ground? Minions of Hakkar, destroy the infidels!',0,1,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,1,0,0,'hakkar SAY_PROTECT_ALTAR'), +(-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 @@ -919,7 +1650,20 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1329004,'An Ash\'ari Crystal has fallen! Stay true to the Lich King, my brethren, and attempt to resummon it.',0,6,0,0,'thuzadin acolyte SAY_ANNOUNCE_ZIGGURAT_1'), (-1329005,'One of the Ash\'ari Crystals has been destroyed! Slay the intruders!',0,6,0,0,'thuzadin acolyte SAY_ANNOUNCE_ZIGGURAT_2'), (-1329006,'An Ash\'ari Crystal has been toppled! Restore the ziggurat before the Necropolis is vulnerable!',0,6,0,0,'thuzadin acolyte SAY_ANNOUNCE_ZIGGURAT_3'), -(-1329007,'The Ash\'ari Crystals have been destroyed! The Slaughterhouse is vulnerable!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RIVENDARE'); +(-1329007,'The Ash\'ari Crystals have been destroyed! The Slaughterhouse is vulnerable!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RIVENDARE'), + +(-1329008,'Intruders at the Service Gate! Lord Rivendare must be warned!',0,6,0,0,'barthilas SAY_WARN_BARON'), +(-1329009,'Intruders! More pawns of the Argent Dawn, no doubt. I already count one of their number among my prisoners. Withdraw from my domain before she is executed!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_START'), +(-1329010,'You\'re still here? Your foolishness is amusing! The Argent Dawn wench needn\'t suffer in vain. Leave at once and she shall be spared!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_10_MIN'), +(-1329011,'I shall take great pleasure in taking this poor wretch\'s life! It\'s not too late, she needn\'t suffer in vain. Turn back and her death shall be merciful!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_5_MIN'), +(-1329012,'May this prisoner\'s death serve as a warning. None shall defy the Scourge and live!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_FAIL'), +(-1329013,'So you see fit to toy with the Lich King\'s creations? Ramstein, be sure to give the intruders a proper greeting.',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RAMSTEIN'), +(-1329014,'Time to take matters into my own hands. Come. Enter my domain and challenge the might of the Scourge!',0,6,0,0,'baron rivendare SAY_UNDEAD_DEFEAT'), +(-1329015,'You did it... you\'ve slain Baron Rivendare! The Argent Dawn shall hear of your valiant deeds!',0,0,0,0,'ysida SAY_EPILOGUE'), + +(-1329016,'Today you have unmade what took me years to create! For this you shall all die by my hand!',0,1,0,0,'dathrohan SAY_AGGRO'), +(-1329017,'You fools think you can defeat me so easily? Face the true might of the Nathrezim!',0,1,0,0,'dathrohan SAY_TRANSFORM'), +(-1329018,'Damn you mortals! All my plans of revenge, all my hate... all burned to ash...',0,0,0,0,'dathrohan SAY_DEATH'); -- -1 349 000 MARAUDON @@ -932,10 +1676,10 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1409002,'%s refuses to die while its master is in trouble.',0,2,0,0,'core rager EMOTE_LOWHP'), (-1409003,'Reckless mortals, none may challenge the sons of the living flame!',8035,1,0,0,'majordomo SAY_AGGRO'), -(-1409004,'The runes of warding have been destroyed! Hunt down the infedels my bretheren.',8039,1,0,0,'majordomo SAY_SPAWN'), +(-1409004,'The runes of warding have been destroyed! Hunt down the infedels my bretheren.',8039,6,0,0,'majordomo SAY_SPAWN'), (-1409005,'Ashes to Ashes!',8037,1,0,0,'majordomo SAY_SLAY'), (-1409006,'Burn mortals! Burn for this transgression!',8036,1,0,0,'majordomo SAY_SPECIAL'), -(-1409007,'Impossible! Stay your attack mortals! I submitt! I submitt! Brashly you have come to rest the secrets of the living flame. You will soon regret the recklessness of your quest. I go now to summon the lord whos house this is. Should you seek an audiance with him your paltry lives will surly be forfit. Nevertheless seek out his lair if you dare!',8038,1,0,0,'majordomo SAY_DEFEAT'), +(-1409007,'Impossible! Stay your attack mortals! I submitt! I submitt!',8038,1,0,0,'majordomo SAY_DEFEAT_1'), (-1409008,'Behold Ragnaros, the Firelord! He who was ancient when this world was young! Bow before him, mortals! Bow before your ending!',8040,1,0,0,'ragnaros SAY_SUMMON_MAJ'), (-1409009,'TOO SOON! YOU HAVE AWAKENED ME TOO SOON, EXECUTUS! WHAT IS THE MEANING OF THIS INTRUSION?',8043,1,0,0,'ragnaros SAY_ARRIVAL1_RAG'), @@ -948,28 +1692,40 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1409015,'BY FIRE BE PURGED!',8046,1,0,0,'ragnaros SAY_HAND'), (-1409016,'TASTE THE FLAMES OF SULFURON!',8047,1,0,0,'ragnaros SAY_WRATH'), (-1409017,'DIE INSECT!',8051,1,0,0,'ragnaros SAY_KILL'), -(-1409018,'MY PATIENCE IS DWINDILING! COME NATS TO YOUR DEATH!',8048,1,0,0,'ragnaros SAY_MAGMABURST'); +(-1409018,'MY PATIENCE IS DWINDILING! COME NATS TO YOUR DEATH!',8048,1,0,0,'ragnaros SAY_MAGMABURST'), + +(-1409019,'You think you\'ve won already? Perhaps you\'ll need another lesson in pain!',0,1,0,0,'majordomo SAY_LAST_ADD'), +(-1409020,'Brashly you have come to rest the secrets of the living flame. You will soon regret the recklessness of your quest.',0,1,0,0,'majordomo SAY_DEFEAT_2'), +(-1409021,'I go now to summon the lord whos house this is. Should you seek an audiance with him your paltry lives will surly be forfit. Nevertheless seek out his lair if you dare!',0,1,0,0,'majordomo SAY_DEFEAT_3'), +(-1409022,'My flame! Please don\'t take away my flame... ',8042,1,0,0,'ragnaros SAY_ARRIVAL4_MAJ'), +(-1409023,'Very well, $N.',0,0,0,0,'majordomo SAY_SUMMON_0'), +(-1409024,'Impudent whelps! You\'ve rushed headlong to your own deaths! See now, the master stirs!',0,1,0,0,'majordomo SAY_SUMMON_1'); -- -1 429 000 DIRE MAUL +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-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'); -- -1 469 000 BLACKWING LAIR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES (-1469000,'None of your kind should be here! You\'ve doomed only yourselves!',8286,1,0,0,'broodlord SAY_AGGRO'), (-1469001,'Clever Mortals but I am not so easily lured away from my sanctum!',8287,1,0,0,'broodlord SAY_LEASH'), -(-1469002,'REUSE ME',0,0,0,0,'REUSE ME'), +(-1469002,'Run! They are coming!',0,1,0,0,'vaelastrasz blackwing tech SAY_INTRO_TECH'), (-1469003,'%s flinches as its skin shimmers.',0,2,0,0,'chromaggus EMOTE_SHIMMER'), -(-1469004,'In this world where time is your enemy, it is my greatest ally. This grand game of life that you think you play in fact plays you. To that I say...',0,0,0,0,'victor_nefarius SAY_GAMESBEGIN_1'), -(-1469005,'Let the games begin!',8280,1,0,0,'victor_nefarius SAY_GAMESBEGIN_2'), -(-1469006,'Ah, the heroes. You are persistent, aren\'t you. Your allied attempted to match his power against mine, and had to pay the price. Now he shall serve me, by slaughtering you. Get up little red wyrm and destroy them!',8279,1,0,0,'victor_nefarius SAY_VAEL_INTRO'), +(-1469004,'In this world where time is your enemy, it is my greatest ally. This grand game of life that you think you play in fact plays you. To that I say...',0,1,0,1,'victor_nefarius SAY_GAMESBEGIN_1'), +(-1469005,'Let the games begin!',8280,1,0,22,'victor_nefarius SAY_GAMESBEGIN_2'), +(-1469006,'Ah...the heroes. You are persistent, aren\'t you? Your ally here attempted to match his power against mine - and paid the price. Now he shall serve me...by slaughtering you.',8279,1,0,23,'victor_nefarius SAY_NEFARIUS_CORRUPT'), (-1469007,'Well done, my minions. The mortals\' courage begins to wane! Now, let\'s see how they contend with the true Lord of Blackrock Spire!',8288,1,0,0,'nefarian SAY_AGGRO'), (-1469008,'Enough! Now you vermin shall feel the force of my birthright, the fury of the earth itself.',8289,1,0,0,'nefarian SAY_XHEALTH'), -(-1469009,'Burn, you wretches! Burn!',8290,1,0,0,'nefarian SAY_SHADOWFLAME'), +(-1469009,'BURN! You wretches! BURN!',8290,1,0,0,'nefarian SAY_SHADOWFLAME'), (-1469010,'Impossible! Rise my minions! Serve your master once more!',8291,1,0,0,'nefarian SAY_RAISE_SKELETONS'), (-1469011,'Worthless $N! Your friends will join you soon enough!',8293,1,0,0,'nefarian SAY_SLAY'), -(-1469012,'This cannot be! I am the Master here! You mortals are nothing to my kind! DO YOU HEAR? NOTHING!',8292,1,0,0,'nefarian SAY_DEATH'), +(-1469012,'This cannot be! I am the master here! You mortals are nothing to my kind! Do you hear me? Nothing!',8292,1,0,0,'nefarian SAY_DEATH'), (-1469013,'Mages too? You should be more careful when you play with magic...',0,1,0,0,'nefarian SAY_MAGE'), (-1469014,'Warriors, I know you can hit harder than that! Let\'s see it!',0,1,0,0,'nefarian SAY_WARRIOR'), (-1469015,'Druids and your silly shapeshifting. Let\'s see it in action!',0,1,0,0,'nefarian SAY_DRUID'), @@ -981,17 +1737,25 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1469021,'Rogues? Stop hiding and face me!',0,1,0,0,'nefarian SAY_ROGUE'), (-1469022,'You\'ll pay for forcing me to do this.',8275,1,0,0,'razorgore SAY_EGGS_BROKEN1'), -(-1469023,'Fools! These eggs are more precious than you know.',8276,1,0,0,'razorgore SAY_EGGS_BROKEN2'), -(-1469024,'No! Not another one! I\'ll have your heads for this atrocity.',8277,1,0,0,'razorgore SAY_EGGS_BROKEN3'), +(-1469023,'Fools! These eggs are more precious than you know!',8276,1,0,0,'razorgore SAY_EGGS_BROKEN2'), +(-1469024,'No - not another one! I\'ll have your heads for this atrocity!',8277,1,0,0,'razorgore SAY_EGGS_BROKEN3'), (-1469025,'If I fall into the abyss I\'ll take all of you mortals with me...',8278,1,0,0,'razorgore SAY_DEATH'), -(-1469026,'Too late...friends. Nefarius\' corruption has taken hold. I cannot...control myself.',8281,1,0,0,'vaelastrasz SAY_LINE1'), -(-1469027,'I beg you Mortals, flee! Flee before I lose all control. The Black Fire rages within my heart. I must release it!',8282,1,0,0,'vaelastrasz SAY_LINE2'), -(-1469028,'FLAME! DEATH! DESTRUCTION! COWER MORTALS BEFORE THE WRATH OF LORD....NO! I MUST FIGHT THIS!',8283,1,0,0,'vaelastrasz SAY_LINE3'), -(-1469029,'Nefarius\' hate has made me stronger than ever before. You should have fled, while you could, mortals! The fury of Blackrock courses through my veins!',8285,1,0,0,'vaelastrasz SAY_HALFLIFE'), -(-1469030,'Forgive me $N, your death only adds to my failure.',8284,1,0,0,'vaelastrasz SAY_KILLTARGET'), +(-1469026,'Too late, friends! Nefarius\' corruption has taken hold...I cannot...control myself.',8281,1,0,1,'vaelastrasz SAY_LINE1'), +(-1469027,'I beg you, mortals - FLEE! Flee before I lose all sense of control! The black fire rages within my heart! I MUST- release it!',8282,1,0,1,'vaelastrasz SAY_LINE2'), +(-1469028,'FLAME! DEATH! DESTRUCTION! Cower, mortals before the wrath of Lord...NO - I MUST fight this! Alexstrasza help me, I MUST fight it!',8283,1,0,1,'vaelastrasz SAY_LINE3'), +(-1469029,'Nefarius\' hate has made me stronger than ever before! You should have fled while you could, mortals! The fury of Blackrock courses through my veins!',8285,1,0,0,'vaelastrasz SAY_HALFLIFE'), +(-1469030,'Forgive me, $N! Your death only adds to my failure!',8284,1,0,0,'vaelastrasz SAY_KILLTARGET'), + +(-1469031,'Death Knights, get over here!',0,1,0,0,'nefarian SAY_DEATH_KNIGHT'), -(-1469031,'REUSE ME',0,0,0,0,'REUSE ME'); +(-1469032,'Get up, little red wyrm...and destroy them!',0,1,0,1,'victor_nefarius SAY_NEFARIUS_CORRUPT_2'), + +(-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'), + +(-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 @@ -1001,8 +1765,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'), @@ -1022,12 +1786,16 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1509019,'My powers are renewed!',8595,1,0,0,'ossirian SAY_SURPREME2'), (-1509020,'My powers return!',8596,1,0,0,'ossirian SAY_SURPREME3'), (-1509021,'Protect the city at all costs!',8597,1,0,0,'ossirian SAY_RAND_INTRO1'), -(-1509022,'The walls have been breached!',8599,1,0,0,'ossirian SAY_RAND_INTRO2'), +(-1509022,'The walls have been breached!',8599,6,0,0,'ossirian SAY_RAND_INTRO2'), (-1509023,'To your posts. Defend the city.',8600,1,0,0,'ossirian SAY_RAND_INTRO3'), (-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 @@ -1044,7 +1812,40 @@ 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'); -- -1 532 000 KARAZHAN INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1151,8 +1952,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'), @@ -1178,7 +1979,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 @@ -1235,25 +2057,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'), @@ -1264,9 +2086,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'), @@ -1277,15 +2099,15 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1533080,'Breathe no more!',8850,1,0,0,'noth SAY_SLAY2'), (-1533081,'I will serve the master... in... death!',8848,1,0,0,'noth SAY_DEATH'), -(-1533082,'%s takes in a deep breath...',0,2,0,0,'sapphiron EMOTE_BREATH'), -(-1533083,'%s resumes his attacks!',0,2,0,0,'sapphiron EMOTE_GROUND'), +(-1533082,'%s takes in a deep breath...',0,3,0,0,'sapphiron EMOTE_BREATH'), +(-1533083,'%s resumes his attacks!',0,3,0,0,'sapphiron EMOTE_GROUND'), -(-1533084,'Our preparations continue as planned, master.',14467,1,0,0,'kelthuzad SAY_SAPP_DIALOG1'), -(-1533085,'It is good that you serve me so faithfully. Soon, all will serve the Lich King and in the end, you shall be rewarded...so long as you do not falter.',8881,1,0,0,'kelthuzad SAY_SAPP_DIALOG2_LICH'), -(-1533086,'I see no complications... Wait... What is this?',14468,1,0,0,'kelthuzad SAY_SAPP_DIALOG3'), -(-1533087,'Your security measures have failed! See to this interruption immediately!',8882,1,0,0,'kelthuzad SAY_SAPP_DIALOG4_LICH'), -(-1533088,'Yes, master!',14469,1,0,0,'kelthuzad SAY_SAPP_DIALOG5'), -(-1533089,'No!!! A curse upon you, interlopers! The armies of the Lich King will hunt you down. You will not escape your fate...',14484,1,0,0,'kelthuzad SAY_CAT_DIED'), +(-1533084,'Your forces are nearly marshalled to strike back against your enemies, my liege.',14467,6,0,0,'kelthuzad SAY_SAPP_DIALOG1'), +(-1533085,'Soon we will eradicate the Alliance and Horde, then the rest of Azeroth will fall before the might of my army.',14768,6,0,0,'lich_king SAY_SAPP_DIALOG2_LICH'), +(-1533086,'Yes, Master. The time of their ultimate demise grows close...What is this?',14468,6,0,0,'kelthuzad SAY_SAPP_DIALOG3'), +(-1533087,'Invaders...here?! DESTROY them, Kel\'Thuzad! Naxxramas must not fall!',14769,6,0,0,'lich_king SAY_SAPP_DIALOG4_LICH'), +(-1533088,'As you command, Master!',14469,6,0,0,'kelthuzad SAY_SAPP_DIALOG5'), +(-1533089,'No!!! A curse upon you, interlopers! The armies of the Lich King will hunt you down. You will not escape your fate...',14484,6,0,0,'kelthuzad SAY_CAT_DIED'), (-1533090,'Who dares violate the sanctity of my domain? Be warned, all who trespass here are doomed.',14463,6,0,0,'kelthuzad SAY_TAUNT1'), (-1533091,'Fools, you think yourselves triumphant? You have only taken one step closer to the abyss! ',14464,6,0,0,'kelthuzad SAY_TAUNT2'), (-1533092,'I grow tired of these games. Proceed, and I will banish your souls to oblivion!',14465,6,0,0,'kelthuzad SAY_TAUNT3'), @@ -1366,7 +2188,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1533155,'Corpse Scarabs appear from a Crypt Guard\'s corpse!',0,3,0,0,'anubrekhan EMOTE_CORPSE_SCARABS'), (-1533156,'%s casts Unyielding Pain on everyone!',0,3,0,0,'lady_blaumeux EMOTE_UNYIELDING_PAIN'), -(-1533157,'%s casts Condemation on everyone!',0,3,0,0,'sir_zeliek EMOTE_CONDEMATION'); +(-1533157,'%s casts Condemation on everyone!',0,3,0,0,'sir_zeliek EMOTE_CONDEMATION'), + +(-1533158,'%s injects you with a mutagen!',0,5,0,0,'grobbulus EMOTE_INJECTION'); -- -1 534 000 THE BATTLE OF MT. HYJAL INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1390,7 +2214,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'), @@ -1455,7 +2279,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1540044,'I am called Bladefist for a reason, as you will see!',10325,1,0,0,'kargath SAY_AGGRO3'), (-1540045,'For the real Horde!',10326,1,0,0,'kargath SAY_SLAY1'), (-1540046,'I am the only Warchief!',10327,1,0,0,'kargath SAY_SLAY2'), -(-1540047,'The true Horde... will.. prevail...',10328,1,0,0,'kargath SAY_DEATH'); +(-1540047,'The true Horde... will.. prevail...',10328,1,0,0,'kargath SAY_DEATH'), +(-1540048,'Cowards! You\'ll never pull me into the shadows!',0,1,0,0,'kargath SAY_EVADE'), + +(-1540049,'The Alliance dares to intrude this far into my fortress? Bring out the Honor Hold prisoners and call for the executioner! They\'ll pay with their lives for this trespass!',0,6,0,0,'kargath SAY_EXECUTE_ALLY'), +(-1540050,'It looks like we have a ranking officer among our captives...how amusing. Execute the green-skinned dog at once!',0,6,0,0,'kargath SAY_EXECUTE_HORDE'); -- -1 542 000 BLOOD FURNACE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1475,7 +2303,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1542011,'Anger... Hate... These are tools I can use.',10288,1,0,0,'the_maker SAY_AGGRO_3'), (-1542012,'Let\'s see what I can make of you.',10289,1,0,0,'the_maker SAY_KILL_1'), (-1542013,'It is pointless to resist.',10290,1,0,0,'the_maker SAY_KILL_2'), -(-1542014,'Stay away from... me.',10291,1,0,0,'the_maker SAY_DIE'); +(-1542014,'Stay away from... me.',10291,1,0,0,'the_maker SAY_DIE'), + +(-1542015,'Kill them!',0,1,0,0,'broggok SAY_BROGGOK_INTRO'), + +(-1542016,'How long do you beleive your pathetic sorcery can hold me?',0,6,0,0,'magtheridon SAY_MAGTHERIDON_WARN'); -- -1 543 000 HELLFIRE RAMPARTS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1510,12 +2342,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'), @@ -1525,7 +2357,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 @@ -1554,7 +2387,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1545020,'Ba\'ahntha sol\'dorei!',10394,1,0,0,'kalithresh SAY_AGGRO3'), (-1545021,'Scram, surface filth!',10395,1,0,0,'kalithresh SAY_SLAY1'), (-1545022,'Ah ha ha ha ha ha ha!',10396,1,0,0,'kalithresh SAY_SLAY2'), -(-1545023,'For her Excellency... for... Vashj!',10397,1,0,0,'kalithresh SAY_DEATH'); +(-1545023,'For her Excellency... for... Vashj!',10397,1,0,0,'kalithresh SAY_DEATH'), + +(-1545024,'Enjoy the storm, warm bloods!',0,1,0,0,'thespia SAY_CLOUD'); -- -1 546 000 THE UNDERBOG @@ -1604,9 +2439,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'), @@ -1621,7 +2456,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 @@ -1674,7 +2511,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 @@ -1710,7 +2549,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 @@ -1732,20 +2599,19 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen -- -1 554 000 THE MECHANAR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1554000,'I predict a painful death.',11101,1,0,0,'gyro SAY_AGGRO'), -(-1554001,'Measure twice; cut once!',11104,1,0,0,'gyro SAY_SAW_ATTACK1'), -(-1554002,'If my division is correct, you should be quite dead.',11105,1,0,0,'gyro SAY_SAW_ATTACK2'), -(-1554003,'Your strategy was flawed!',11102,1,0,0,'gyro SAY_SLAY1'), -(-1554004,'Yes, the only logical outcome.',11103,1,0,0,'gyro SAY_SLAY2'), -(-1554005,'An unforseen... contingency',11106,1,0,0,'gyro SAY_DEATH'), - -(-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'), +(-1554000,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554001,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554002,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-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,'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'), @@ -1762,7 +2628,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 @@ -1825,7 +2692,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 @@ -1857,41 +2732,46 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1558006,'Stare into the darkness of your soul.',10511,1,0,0,'maladaar SAY_SOUL_CLEAVE'), (-1558007,'These walls will be your doom.',10516,1,0,0,'maladaar SAY_SLAY_1'), (-1558008,' Now, you\'ll stay for eternity!',10517,1,0,0,'maladaar SAY_SLAY_2'), -(-1558009,'This is... where.. I belong...',10518,1,0,0,'maladaar SAY_DEATH'); +(-1558009,'This is... where.. I belong...',10518,1,0,0,'maladaar SAY_DEATH'), + +(-1558010,'%s focuses on $N',0,3,0,0,'shirrak EMOTE_FOCUS'); -- -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'), @@ -1944,8 +2824,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'), @@ -2042,39 +2922,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 @@ -2175,22 +3062,27 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1568065,'Lot more gonna fall like you!',12099,1,0,0,'zuljin SAY_KILL2'), (-1568066,'Mebbe me fall...but da Amani empire...never gonna die...',12100,1,0,0,'zuljin SAY_DEATH'), -(-1568067,'Zul\'jin got a surprise for ya...',12052,1,0,0,'zulaman SAY_INST_RELEASE'), -(-1568068,'Da spirits gonna feast today! Begin da ceremonies, sacrifice da prisoners... make room for our new guests!',12053,1,0,0,'zulaman SAY_INST_BEGIN'), -(-1568069,'Take your pick, trespassers! Any of ma priests be happy to accommodate ya.',12054,1,0,0,'zulaman SAY_INST_PROGRESS_1'), -(-1568070,'Don\'t be shy. Thousands have come before you. Ya not be alone in your service.',12055,1,0,0,'zulaman SAY_INST_PROGRESS_2'), -(-1568071,'Ya gonna fail, strangers. Many try before you, but dey only make us stronger!',12056,1,0,0,'zulaman SAY_INST_PROGRESS_3'), -(-1568072,'Your efforts was in vain, trespassers. The rituals nearly be complete.',12057,1,0,0,'zulaman SAY_INST_WARN_1'), -(-1568073,'Soon da cages gonna be empty, da sacrifices be complete, and you gonna take dere places.',12058,1,0,0,'zulaman SAY_INST_WARN_2'), -(-1568074,'Time be running low, strangers. Soon you gonna join da souls of dem ya failed to save.',12059,1,0,0,'zulaman SAY_INST_WARN_3'), -(-1568075,'Make haste, ma priests! Da rituals must not be interrupted!',12060,1,0,0,'zulaman SAY_INST_WARN_4'), -(-1568076,'Ya make a good try... but now you gonna join da ones who already fall.',12061,1,0,0,'zulaman SAY_INST_SACRIF1'), -(-1568077,'Ya not do too bad. Ya efforts [...] for a small time. Come to me now. Ya prove yourself worthy offerings.',12062,1,0,0,'zulaman SAY_INST_SACRIF2'), -(-1568078,'Watch now. Every offering gonna strengthen our ties to da spirit world. Soon, we gonna be unstoppable!',12065,1,0,0,'zulaman SAY_INST_COMPLETE'), +(-1568067,'Zul\'jin got a surprise for ya...',12052,6,0,0,'zulaman SAY_INST_RELEASE'), +(-1568068,'Da spirits gonna feast today! Begin da ceremonies, sacrifice da prisoners... make room for our new guests!',12053,6,0,0,'zulaman SAY_INST_BEGIN'), +(-1568069,'Take your pick, trespassers! Any of ma priests be happy to accommodate ya.',12054,6,0,0,'zulaman SAY_INST_PROGRESS_1'), +(-1568070,'Don\'t be shy. Thousands have come before you. Ya not be alone in your service.',12055,6,0,0,'zulaman SAY_INST_PROGRESS_2'), +(-1568071,'Ya gonna fail, strangers. Many try before you, but dey only make us stronger!',12056,6,0,0,'zulaman SAY_INST_PROGRESS_3'), +(-1568072,'Your efforts was in vain, trespassers. The rituals nearly be complete.',12057,6,0,0,'zulaman SAY_INST_WARN_1'), +(-1568073,'Soon da cages gonna be empty, da sacrifices be complete, and you gonna take dere places.',12058,6,0,0,'zulaman SAY_INST_WARN_2'), +(-1568074,'Time be running low, strangers. Soon you gonna join da souls of dem ya failed to save.',12059,6,0,0,'zulaman SAY_INST_WARN_3'), +(-1568075,'Make haste, ma priests! Da rituals must not be interrupted!',12060,6,0,0,'zulaman SAY_INST_WARN_4'), +(-1568076,'Ya make a good try... but now you gonna join da ones who already fall.',12061,6,0,0,'zulaman SAY_INST_SACRIF1'), +(-1568077,'Ya not do too bad. Ya efforts [...] for a small time. Come to me now. Ya prove yourself worthy offerings.',12062,6,0,0,'zulaman SAY_INST_SACRIF2'), +(-1568078,'Watch now. Every offering gonna strengthen our ties to da spirit world. Soon, we gonna be unstoppable!',12065,6,0,0,'zulaman SAY_INST_COMPLETE'), (-1568079,'Suit yourself. At least five of you must assist me if we\'re to get inside. Follow me.',0,1,0,0,'harrison SAY_START'), (-1568080,'According to my calculations, if enough of us bang the gong at once the seal on these doors will break and we can enter.',0,1,0,0,'harrison SAY_AT_GONG'), -(-1568081,'I\'ve researched this site extensively and I won\'t allow any dim-witted treasure hunters to swoop in and steal what belongs to in a museum. I\'ll lead this charge.',0,1,0,0,'harrison SAY_OPEN_ENTRANCE'); +(-1568081,'I\'ve researched this site extensively and I won\'t allow any dim-witted treasure hunters to swoop in and steal what belongs to in a museum. I\'ll lead this charge.',0,1,0,0,'harrison SAY_OPEN_ENTRANCE'), + +(-1568082,'%s absorbs the essence of the bear spirit!',0,2,0,0,'zuljin EMOTE_BEAR_SPIRIT'), +(-1568083,'%s absorbs the essence of the eagle spirit!',0,2,0,0,'zuljin EMOTE_EAGLE_SPIRIT'), +(-1568084,'%s absorbs the essence of the lynx spirit!',0,2,0,0,'zuljin EMOTE_LYNX_SPIRIT'), +(-1568085,'%s absorbs the essence of the dragonhawk spirit!',0,2,0,0,'zuljin EMOTE_DRAGONHAWK_SPIRIT'); -- -1 574 000 UTGARDE KEEP INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2247,7 +3139,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'), @@ -2269,7 +3161,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 @@ -2302,6 +3196,43 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1576022,'%s shields himself and divert his power to the rifts!',0,3,0,0,'anomalus EMOTE_SHIELD'); -- -1 578 000 OCULUS +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578000,'What do we have here... those would defy the Spell-Weaver? Those without foresight or understanding. How could I make you see? Malygos is saving the world from itself! Bah! You are hardly worth my time!',13635,1,0,0,'urom SAY_SUMMON_1'), +(-1578001,'Clearly my pets failed. Perhaps another demonstration is in order.',13636,1,0,0,'urom SAY_SUMMON_2'), +(-1578002,'Still you fight. Still you cling to misguided principles. If you survive, you\'ll find me in the center ring.',13637,1,0,0,'urom SAY_SUMMON_3'), +(-1578003,'Poor blind fools!',13638,1,0,0,'urom SAY_AGGRO'), +(-1578004,'A taste... just a small taste... of the Spell-Weaver\'s power!',13639,1,0,0,'urom SAY_EXPLOSION_1'), +(-1578005,'So much unstable energy... but worth the risk to destroy you!',13640,1,0,0,'urom SAY_EXPLOSION_2'), +(-1578006,'If only you understood!',13641,1,0,0,'urom SAY_KILL_1'), +(-1578007,'Now do you see? Do you?!',13642,1,0,0,'urom SAY_KILL_2'), +(-1578008,'Unfortunate, but necessary.',13643,1,0,0,'urom SAY_KILL_3'), +(-1578009,'Everything I\'ve done... has been for Azeroth...',13644,1,0,0,'urom SAY_DEATH'), + +(-1578010,'Simpletons! You cannot comprehend the forces you have set in motion. The ley line conduit will not be disrupted! Your defeat shall be absolute!',13622,6,0,0,'eregos SAY_SPAWN'), +(-1578011,'You brash interlopers are out of your element! I will ground you!',13623,1,0,0,'eregos SAY_AGGRO'), +(-1578012,'We command the arcane! It shall not be used against us.',13626,1,0,0,'eregos SAY_ARCANE_SHIELD'), +(-1578013,'It is trivial to extinguish your fire!',13627,1,0,0,'eregos SAY_FIRE_SHIELD'), +(-1578014,'No magic of nature will help you now!',13625,1,0,0,'eregos SAY_NATURE_SHIELD'), +(-1578015,'Such insolence... such arrogance... must be PUNISHED!',13624,1,0,0,'eregos SAY_FRENZY'), +(-1578016,'It\'s a long way down...',13628,1,0,0,'eregos SAY_KILL_1'), +(-1578017,'Back to the earth with you!',13629,1,0,0,'eregos SAY_KILL_2'), +(-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,'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 @@ -2326,7 +3257,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1580017,'Puny lizard! Death is the only answer you\'ll find here!',12458,1,0,0,'brutallus YELL_INTRO'), (-1580018,'Grah! Your magic is weak!',12459,1,0,0,'brutallus YELL_INTRO_BREAK_ICE'), (-1580019,'I will crush you!',12460,1,0,0,'brutallus YELL_INTRO_CHARGE'), -(-1580020,'That was fun.',12461,1,0,0,'brutallus YELL_INTRO_KILL_MADRIGOSA'), +(-1580020,'That was fun, but I still await a true challenge!',12461,1,0,0,'brutallus YELL_INTRO_KILL_MADRIGOSA'), (-1580021,'Come, try your luck!',12462,1,0,0,'brutallus YELL_INTRO_TAUNT'), (-1580022,'Ahh! More lambs to the slaughter!',12463,1,0,0,'brutallus YELL_AGGRO'), (-1580023,'Perish, insect!',12464,1,0,0,'brutallus YELL_KILL1'), @@ -2339,10 +3270,88 @@ 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'); +(-1580035,'Malygos, my lord! I did my best!',12476,1,0,0,'madrigosa YELL_MADR_DEATH'), + +(-1580036,'Glory to Kil\'jaeden! Death to all who oppose!',12477,1,0,0,'felmyst SAY_INTRO'), +(-1580037,'I kill for the master!',12480,1,0,0,'felmyst SAY_KILL_1'), +(-1580038,'The end has come! ',12481,1,0,0,'felmyst SAY_KILL_2'), +(-1580039,'Choke on your final breath! ',12478,1,0,0,'felmyst SAY_BREATH'), +(-1580040,'I am stronger than ever before! ',12479,1,0,0,'felmyst SAY_TAKEOFF'), +(-1580041,'No more hesitation! Your fates are written! ',12482,1,0,0,'felmyst SAY_BERSERK'), +(-1580042,'Kil\'jaeden... will... prevail... ',12483,1,0,0,'felmyst SAY_DEATH'), +(-1580043,'Madrigosa deserved a far better fate. You did what had to be done, but this battle is far from over.',12439,1,0,0,'kalecgos SAY_KALECGOS_OUTRO'), + +(-1580044,'Misery...',12484,1,0,0,'sacrolash SAY_INTRO_1'), +(-1580045,'Depravity...',0,1,0,0,'alythess SAY_INTRO_2'), +(-1580046,'Confusion...',0,1,0,0,'sacrolash SAY_INTRO_3'), +(-1580047,'Hatred...',0,1,0,0,'alythess SAY_INTRO_4'), +(-1580048,'Mistrust...',0,1,0,0,'sacrolash SAY_INTRO_5'), +(-1580049,'Chaos...',0,1,0,0,'alythess SAY_INTRO_6'), +(-1580050,'These are the hallmarks...',0,1,0,0,'sacrolash SAY_INTRO_7'), +(-1580051,'These are the pillars...',0,1,0,0,'alythess SAY_INTRO_8'), + +(-1580052,'Shadow to the aid of fire!',12485,1,0,0,'sacrolash SAY_SACROLASH_SHADOW_NOVA'), +(-1580053,'Alythess! Your fire burns within me!',12488,1,0,0,'sacrolash SAY_SACROLASH_EMPOWER'), +(-1580054,'Shadows, engulf!',12486,1,0,0,'sacrolash SAY_SACROLASH_KILL_1'), +(-1580055,'Ee-nok Kryul!',12487,1,0,0,'sacrolash SAY_SACROLASH_KILL_2'), +(-1580056,'I... fade.',12399,1,0,0,'sacrolash SAY_SACROLASH_DEAD'), +(-1580057,'Time is a luxury you no longer possess!',0,1,0,0,'sacrolash SAY_SACROLASH_BERSERK'), +(-1580058,'Fire to the aid of shadow!',12489,1,0,0,'alythess SAY_ALYTHESS_CANFLAGRATION'), +(-1580059,'Sacrolash!',12492,1,0,0,'alythess SAY_ALYTHESS_EMPOWER'), +(-1580060,'Fire, consume!',12490,1,0,0,'alythess SAY_ALYTHESS_KILL_1'), +(-1580061,'Ed-ir Halach!',12491,1,0,0,'alythess SAY_ALYTHESS_KILL_2'), +(-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,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'), +(-1580072,'Who can you trust?',12503,1,0,0,'kiljaeden SAY_REFLECTION_1'), +(-1580073,'The enemy is among you.',12504,1,0,0,'kiljaeden SAY_REFLECTION_2'), +(-1580074,'Chaos!',12505,1,0,0,'kiljaeden SAY_DARKNESS_1'), +(-1580075,'Destruction!',12506,1,0,0,'kiljaeden SAY_DARKNESS_2'), +(-1580076,'Oblivion!',12507,1,0,0,'kiljaeden SAY_DARKNESS_3'), +(-1580077,'I will not be denied! This world shall fall!',12508,1,0,0,'kiljaeden SAY_PHASE_3'), +(-1580078,'Do not harbor false hope. You cannot win!',12509,1,0,0,'kiljaeden SAY_PHASE_4'), +(-1580079,'Aggghh! The powers of the Sunwell... turn... against me! What have you done? What have you done???',12510,1,0,0,'kiljaeden SAY_PHASE_5'), +(-1580080,'You are not alone. The Blue Dragonflight shall help you vanquish the Deceiver.',12438,1,0,0,'kalecgos SAY_KALECGOS_INTRO'), +(-1580081,'Anveena, you must awaken, this world needs you!',12445,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_1'), +(-1580082,'I serve only the Master now.',12511,0,0,0,'anveena SAY_ANVEENA_IMPRISONED'), +(-1580083,'You must let go! You must become what you were always meant to be! The time is now, Anveena!',12446,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_2'), +(-1580084,'But I\'m... lost. I cannot find my way back.',12512,0,0,0,'anveena SAY_ANVEENA_LOST'), +(-1580085,'Anveena, I love you! Focus on my voice, come back for me now! Only you can cleanse the Sunwell!',12447,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_4'), +(-1580086,'Kalec... Kalec?',12513,0,0,0,'anveena SAY_ANVEENA_AWAKE'), +(-1580087,'Yes, Anveena! Let fate embrace you now!',12448,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_5'), +(-1580088,'The nightmare is over, the spell is broken! Goodbye, Kalec, my love!',12514,0,0,0,'anveena SAY_ANVEENA_SACRIFICE'), +(-1580089,'Goodbye, Anveena, my love. Few will remember your name, yet this day you change the course of destiny. What was once corrupt is now pure. Heroes, do not let her sacrifice be in vain.',12450,0,0,0,'kalecgos SAY_KALECGOS_GOODBYE'), +(-1580090,'Strike now, heroes, while he is weakened! Vanquish the Deceiver!',12449,1,0,0,'kalecgos SAY_KALECGOS_ENCOURAGE'), +(-1580091,'I will channel my power into the orbs, be ready!',12440,1,0,0,'kalecgos SAY_KALECGOS_ORB_1'), +(-1580092,'I have empowered another orb! Use it quickly!',12441,1,0,0,'kalecgos SAY_KALECGOS_ORB_2'), +(-1580093,'Another orb is ready! Make haste!',12442,1,0,0,'kalecgos SAY_KALECGOS_ORB_3'), +(-1580094,'I have channeled all I can! The power is in your hands!',12443,1,0,0,'kalecgos SAY_KALECGOS_ORB_4'), + +(-1580095,'Mortal heroes - your victory here today was foretold long ago. My brother\'s anguished cry of defeat will echo across the universe - bringing renewed hope to all those who still stand against the Burning Crusade.',12515,0,0,1,'velen SAY_OUTRO_1'), +(-1580096,'As the Legion\'s final defeat draws ever-nearer, stand proud in the knowledge that you have saved worlds without number from the flame.',12516,0,0,1,'velen SAY_OUTRO_2'), +(-1580097,'Just as this day marks an ending, so too does it herald a new beginning...',12517,0,0,1,'velen SAY_OUTRO_3'), +(-1580098,'The creature Entropius, whom you were forced to destroy, was once the noble naaru, M\'uru. In life, M\'uru channeled vast energies of LIGHT and HOPE. For a time, a misguided few sought to steal those energies...',12518,0,0,1,'velen SAY_OUTRO_4'), +(-1580099,'Our arrogance was unpardonable. We damned one of the most noble beings of all. We may never atone for this sin.',12524,0,0,1,'liadrin SAY_OUTRO_5'), +(-1580100,'Than fortunate it is, that I have reclaimed the noble naaru\'s spark from where it fell! Where faith dwells, hope is never lost, young blood elf.',12519,0,0,1,'velen SAY_OUTRO_6'), +(-1580101,'Can it be ?',12525,0,0,1,'liadrin SAY_OUTRO_7'), +(-1580102,'Gaz now, mortals - upon the HEART OF M\'URU! Umblemished. Bathed by the light of Creation - just as it was at the Dawn.',12520,0,0,1,'velen SAY_OUTRO_8'), +(-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'), + +(-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 @@ -2372,15 +3381,19 @@ 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'); -- -1 599 000 HALLS OF STONE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2501,19 +3514,23 @@ 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'), (-1601016,'You shall experience my torment, first-hand!',14055,1,0,0,'anubarak SAY_KILL_1'), (-1601017,'You have made your choice.',14056,1,0,0,'anubarak SAY_KILL_2'), (-1601018,'Soon, the Master\'s voice will call to you.',14057,1,0,0,'anubarak SAY_KILL_3'), -(-1601019,'Come forth, my brethren. Feast on their flesh!',14058,1,0,0,'anubarak SAY_SUBMERGE_1'), -(-1601020,'Auum na-l ak-k-k-k, isshhh.',14059,1,0,0,'anubarak SAY_SUBMERGE_2'), +(-1601019,'Come forth, my brethren. Feast on their flesh!',14059,1,0,0,'anubarak SAY_SUBMERGE_1'), +(-1601020,'Auum na-l ak-k-k-k, isshhh.',14058,1,0,0,'anubarak SAY_SUBMERGE_2'), (-1601021,'Your armor is useless against my locusts!',14060,1,0,0,'anubarak SAY_LOCUST_1'), -(-1601022,'The pestilence upon you!',14067,1,0,0,'anubarak SAY_LOCUST_2'), -(-1601023,'Uunak-hissss tik-k-k-k-k!',14068,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'); +(-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'), + +(-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'); -- -1 602 000 HALLS OF LIGHTNING INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2539,7 +3556,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'), @@ -2578,9 +3595,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'), @@ -2612,7 +3630,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'), @@ -2627,8 +3645,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'), @@ -2686,8 +3704,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'), @@ -2704,11 +3722,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'), @@ -2792,10 +3810,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'), @@ -2807,13 +3825,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'), @@ -2826,22 +3844,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 @@ -2879,13 +3936,13 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1604028,'Even the mighty... can fall.',14439,1,0,0,'galdarah SAY_DEATH'), (-1604029,'%s transforms into a Mammoth!',14724,2,0,0,'moorabi EMOTE_TRANSFORMED'), -(-1604030,'%N is impaled!',0,3,0,0,'EMOTE_IMPALED'); +(-1604030,'$N is impaled!',0,3,0,0,'EMOTE_IMPALED'); -- -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'), @@ -2893,7 +3950,30 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1608005,'A Portal Guardian defends the new portal!',0,3,0,0,'EMOTE_GUARDIAN_PORTAL'), (-1608006,'An elite Blue Dragonflight squad appears from the portal!',0,3,0,0,'EMOTE_DRAGONFLIGHT_PORTAL'), -(-1608007,'A Guardian Keeper emerges from the portal!',0,3,0,0,'EMOTE_KEEPER_PORTAL'); +(-1608007,'A Guardian Keeper emerges from the portal!',0,3,0,0,'EMOTE_KEEPER_PORTAL'), + +(-1608008,'Free to--mm--fly now. Ra-aak... Not find us--ekh-ekh! Escape!',14218,1,0,0,'erekem SAY_RELEASE_EREKEM'), +(-1608009,'I... am fury... unrestrained!',14229,1,0,0,'ichoron SAY_RELEASE_ICHORON'), +(-1608010,'Back in business! Now to execute an exit strategy.',14498,1,0,0,'xevozz SAY_RELEASE_XEVOZZ'), +(-1608011,'I am... renewed.',13995,1,0,0,'zuramat SAY_RELEASE_ZURAMAT'), + +(-1608012,'Not--caww--get in way of--rrak-rrak--flee!',14219,1,0,0,'erekem SAY_AGGRO'), +(-1608013,'My---raaak--favorite! Awk awk awk! Raa-kaa!',14220,1,0,0,'erekem SAY_ADD_DIE_1'), +(-1608014,'Nasty little...A-ak,kaw! Kill! Yes,kill you!',14221,1,0,0,'erekem SAY_ADD_DIE_2'), +(-1608018,'No--kaw,kaw--flee...',14225,1,0,0,'erekem SAY_DEATH'), + +(-1608019,'Stand aside, mortals!',14230,1,0,0,'ichoron SAY_AGGRO'), +(-1608020,'I will not be contained! Ngyah!!',14233,1,0,0,'ichoron SAY_SHATTERING'), +(-1608021,'Water can hold any form, take any shape... overcome any obstacle.',14232,1,0,0,'ichoron SAY_SHIELD'), +(-1608022,'I am a force of nature!',14234,1,0,0,'ichoron SAY_SLAY_1'), +(-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'), + +(-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 @@ -2998,7 +4078,107 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-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'); +(-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'), + +(-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,''); -- -1 615 000 OBSIDIAN SANCTUM INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3010,7 +4190,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'), @@ -3020,7 +4200,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'), @@ -3036,7 +4216,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'), @@ -3046,11 +4226,47 @@ 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 +(-1616000,'Lesser beings, intruding here! A shame that your excess courage does not compensate for your stupidity!',14512,1,0,0,'malygos SAY_INTRO_1'), +(-1616001,'None but the blue dragonflight are welcome here! Perhaps this is the work of Alexstrasza? Well then, she has sent you to your deaths.',14513,1,0,0,'malygos SAY_INTRO_2'), +(-1616002,'What could you hope to accomplish, to storm brazenly into my domain? To employ MAGIC? Against ME? ',14514,1,0,0,'malygos SAY_INTRO_3'), +(-1616003,'I am without limits here... the rules of your cherished reality do not apply... In this realm, I am in control...',14515,1,0,0,'malygos SAY_INTRO_4'), +(-1616004,'I give you one chance. Pledge fealty to me, and perhaps I won\'t slaughter you for your insolence!',14516,1,0,0,'malygos SAY_INTRO_5'), +(-1616005,'My patience has reached its limit, I WILL BE RID OF YOU!',14517,1,0,0,'malygos SAY_AGGRO'), +(-1616006,'Watch helplessly as your hopes are swept away...',14525,1,0,0,'malygos SAY_VORTEX'), +(-1616007,'I AM UNSTOPPABLE!',14533,1,0,0,'malygos SAY_SPARK_BUFF'), +(-1616008,'Your stupidity has finally caught up to you!',14519,1,0,0,'malygos SAY_SLAY_1_A'), +(-1616009,'More artifacts to confiscate...',14520,1,0,0,'malygos SAY_SLAY_1_B'), +(-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'), +(-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'), +(-1616017,'Your spirit will linger here forever!',14528,1,0,0, 'malygos SAY_SLAY_2_C'), +(-1616018,'ENOUGH! If you intend to reclaim Azeroth\'s magic, then you shall have it...',14529,1,0,0,'malygos SAY_END_PHASE_2'), +(-1616019,'Now your benefactors make their appearance...But they are too late. The powers contained here are sufficient to destroy the world ten times over! What do you think they will do to you?',14530,1,0,0,'malygos SAY_INTRO_PHASE_3'), +(-1616020,'SUBMIT!',14531,1,0,0,'malygos SAY_START_PHASE_3'), +(-1616021,'Alexstrasza! Another of your brood falls!',14534,1,0,0,'malygos SAY_SLAY_3_A'), +(-1616022,'Little more then gnats!',14535,1,0,0,'malygos SAY_SLAY_3_B'), +(-1616023,'Your red allies will share your fate...',14536,1,0,1,'malygos SAY_SLAY_3_C'), +(-1616024,'The powers at work here exceed anything you could possibly imagine!',14532,1,0,0,'malygos SAY_SURGE'), +(-1616025,'Still standing? Not for long...',14537,1,0,0,'malygos SAY_SPELL_1'), +(-1616026,'Your cause is lost!',14538,1,0,0,'malygos SAY_SPELL_2'), +(-1616027,'Your fragile mind will be shattered!',14539,1,0,0,'malygos SAY_SPELL_3'), +(-1616028,'UNTHINKABLE! The mortals will destroy... e-everything... my sister... what have you-',14540,1,0,0,'malygos SAY_DEATH'), +(-1616029,'I did what I had to, brother. You gave me no alternative.',14406,1,0,1,'alextrasza SAY_OUTRO_1'), +(-1616030,'And so ends the Nexus War.',14407,1,0,1,'alextrasza SAY_OUTRO_2'), +(-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'); -- -1 619 000 AHN'KAHET INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3091,14 +4307,230 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1619032,'I give myself to the master!',0,1,0,0,'jedoga SAY_VOLUNTEER_2'), (-1619033,'Shgla\'yos plahf mh\'naus.',14043,1,0,0,'volazj SAY_AGGRO'), -(-1619034,' ',14044,1,0,0,'volazj SAY_INSANITY'), -(-1619035,' ',14045,1,0,0,'volazj SAY_SLAY_1'), -(-1619036,' ',14046,1,0,0,'volazj SAY_SLAY_2'), -(-1619037,' ',14047,1,0,0,'volazj SAY_SLAY_3'), +(-1619034,'Gul\'kafh an\'shel. Yoq\'al shn ky ywaq nuul.',14044,1,0,0,'volazj SAY_INSANITY'), +(-1619035,'Ywaq puul skshgn: on\'ma yeh\'glu zuq.',14045,1,0,0,'volazj SAY_SLAY_1'), +(-1619036,'Ywaq ma phgwa\'cul hnakf.',14046,1,0,0,'volazj SAY_SLAY_2'), +(-1619037,'Ywaq maq oou; ywaq maq ssaggh. Ywaq ma shg\'fhn.',14047,1,0,0,'volazj SAY_SLAY_3'), (-1619038,' ',14048,1,0,0,'volazj SAY_DEATH_1'), -(-1619039,' ',14049,1,0,0,'volazj SAY_DEATH_2'); +(-1619039,'Iilth vwah, uhn\'agth fhssh za.',14049,1,0,0,'volazj SAY_DEATH_2'); -- -1 631 000 ICC: ICECROWN CITADEL +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1631001,'This is the beginning AND the end, mortals. None may enter the master\'s sanctum!',16950,1,0,0,'marrowgar SAY_INTRO'), +(-1631002,'The Scourge will wash over this world as a swarm of death and destruction!',16941,1,0,0,'marrowgar SAY_AGGRO'), +(-1631003,'BONE STORM!',16946,1,0,0,'marrowgar SAY_BONE_STORM'), +(-1631004,'Bound by bone!',16947,1,0,0,'marrowgar SAY_BONE_SPIKE_1'), +(-1631005,'Stick Around!',16948,1,0,0,'marrowgar SAY_BONE_SPIKE_2'), +(-1631006,'The only escape is death!',16949,1,0,0,'marrowgar SAY_BONE_SPIKE_3'), +(-1631007,'More bones for the offering!',16942,1,0,0,'marrowgar SAY_SLAY_1'), +(-1631008,'Languish in damnation!',16943,1,0,0,'marrowgar SAY_SLAY_2'), +(-1631009,'I see... only darkness...',16944,1,0,0,'marrowgar SAY_DEATH'), +(-1631010,'THE MASTER\'S RAGE COURSES THROUGH ME!',16945,1,0,0,'marrowgar SAY_BERSERK'), + +(-1631011,'You have found your way here, because you are among the few gifted with true vision in a world cursed with blindness.',17272,1,0,0,'deathwhisper SAY_SPEECH_1'), +(-1631012,'You can see through the fog that hangs over this world like a shroud, and grasp where true power lies.',17273,1,0,0,'deathwhisper SAY_SPEECH_2'), +(-1631013,'Fix your eyes upon your crude hands: the sinew, the soft meat, the dark blood coursing within.',16878,1,0,0,'deathwhisper SAY_SPEECH_3'), +(-1631014,'It is a weakness; a crippling flaw.... A joke played by the Creators upon their own creations.',17268,1,0,0,'deathwhisper SAY_SPEECH_4'), +(-1631015,'The sooner you come to accept your condition as a defect, the sooner you will find yourselves in a position to transcend it.',17269,1,0,0,'deathwhisper SAY_SPEECH_5'), +(-1631016,'Through our Master, all things are possible. His power is without limit, and his will unbending.',17270,1,0,0,'deathwhisper SAY_SPEECH_6'), +(-1631017,'Those who oppose him will be destroyed utterly, and those who serve -- who serve wholly, unquestioningly, with utter devotion of mind and soul -- elevated to heights beyond your ken.',17271,1,0,0,'deathwhisper SAY_SPEECH_7'), +(-1631018,'What is this disturbance?! You dare trespass upon this hallowed ground? This shall be your final resting place.',16868,1,0,0,'deathwhisper SAY_AGGRO'), +(-1631019,'Enough! I see I must take matters into my own hands!',16877,1,0,0,'deathwhisper SAY_PHASE_TWO'), +(-1631020,'Take this blessing and show these intruders a taste of our master\'s power.',16873,1,0,0,'deathwhisper SAY_DARK_EMPOWERMENT'), +(-1631021,'I release you from the curse of flesh!',16874,1,0,0,'deathwhisper SAY_DARK_TRANSFORMATION'), +(-1631022,'Arise and exalt in your pure form!',16875,1,0,0,'deathwhisper SAY_ANIMATE_DEAD'), +(-1631023,'You are weak, powerless to resist my will!',16876,1,0,0,'deathwhisper SAY_DOMINATE_MIND'), +(-1631024,'This charade has gone on long enough.',16872,1,0,0,'deathwhisper SAY_BERSERK'), +(-1631025,'All part of the masters plan! Your end is... inevitable!',16871,1,0,0,'deathwhisper SAY_DEATH'), +(-1631026,'Do you yet grasp of the futility of your actions?',16869,1,0,0,'deathwhisper SAY_SLAY_1'), +(-1631027,'Embrace the darkness... Darkness eternal!',16870,1,0,0,'deathwhisper SAY_SLAY_2'), + +(-1631028,'BY THE MIGHT OF THE LICH KING!',16694,1,0,0,'saurfang SAY_AGGRO'), +(-1631029,'The ground runs red with your blood!',16699,1,0,0,'saurfang SAY_FALLENCHAMPION'), +(-1631030,'Feast, my minions!',16700,1,0,0,'saurfang SAY_BLOODBEASTS'), +(-1631031,'You are nothing!',16695,1,0,0,'saurfang SAY_SLAY_1'), +(-1631032,'Your soul will find no redemption here!',16696,1,0,0,'saurfang SAY_SLAY_2'), +(-1631033,'I have become...DEATH!',16698,1,0,0,'saurfang SAY_BERSERK'), +(-1631034,'I... Am... Released.',16697,1,0,0,'saurfang SAY_DEATH'), +(-1631035,'Let\'s get a move on then! Move ou...',16974,1,0,0,'bronzebeard SAY_INTRO_ALLY_0'), +(-1631036,'For every Horde soldier that you killed, for every Alliance dog that fell, the Lich King\'s armies grew. Even now the Val\'kyr work to raise your fallen... As Scourge.',16701,1,0,0,'saurfang SAY_INTRO_ALLY_1'), +(-1631037,'Things are about to get much worse. Come, taste the power that the Lich King has bestowed upon me!',16702,1,0,0,'saurfang SAY_INTRO_ALLY_2'), +(-1631038,'A lone orc, against the might of the Alliance?',16970,1,0,0,'bronzebeard SAY_INTRO_ALLY_3'), +(-1631039,'Charge!',16971,1,0,0,'bronzebeard SAY_INTRO_ALLY_4'), +(-1631040,'Hahahaha! Dwarves...',16703,1,0,0,'saurfang SAY_INTRO_ALLY_5'), +(-1631041,'Kor\'kron, move out! Champions, watch your backs. The Scourge have been..',17103,1,0,0,'overlord SAY_INTRO_HORDE_1'), +(-1631042,'Join me, father. Join me and we will crush this world in the name of the Scourge -- for the glory of the Lich King!',16704,1,0,0,'saurfang SAY_INTRO_HORDE_2'), +(-1631043,'My boy died at the Wrath Gate. I am here only to collect his body.',17097,0,0,0,'overlord SAY_INTRO_HORDE_3'), +(-1631044,'Stubborn and old. What chance do you have? I am stronger, and more powerful than you ever were.',16705,1,0,0,'saurfang SAY_INTRO_HORDE_4'), +(-1631045,'We named him Dranosh. It means "Heart of Draenor" in orcish. I would not let the warlocks take him. My boy would be safe, hidden away by the elders of Garadar.',17098,0,0,0,'overlord SAY_INTRO_HORDE_5'), +(-1631046,'I made a promise to his mother before she died; that I would cross the Dark Portal alone - whether I lived or died, my son would be safe. Untainted...',17099,0,0,0,'overlord SAY_INTRO_HORDE_6'), +(-1631047,'Today, I fulfill that promise.',17100,0,0,0,'overlord SAY_INTRO_HORDE_7'), +(-1631048,'High Overlord Saurfang charges!',17104,2,0,0,'overlord SAY_INTRO_HORDE_8'), +(-1631049,'Pathetic old orc. Come then heroes. Come and face the might of the Scourge!',16706,1,0,0,'saurfang SAY_INTRO_HORDE_9'), +(-1631050,'%s gasps for air',16975,2,0,0,'bronzebeard SAY_OUTRO_ALLY_1'), +(-1631051,'That was Saurfang\'s boy - the Horde commander at the Wrath Gate. Such a tragic end...',16976,0,0,0,'bronzebeard SAY_OUTRO_ALLY_2'), +(-1631052,'What in the... There, in the distance!',16977,0,0,0,'bronzebeard SAY_OUTRO_ALLY_3'), +(-1631053,'Soldiers, fall in! Looks like the Horde are comin\' in to take another shot!',16978,1,0,0,'bronzebeard SAY_OUTRO_ALLY_4'), +(-1631054,'Don\'t force my hand, orc. We can\'t let you pass.',16972,0,0,0,'bronzebeard SAY_OUTRO_ALLY_5'), +(-1631055,'Behind you lies the body of my only son. Nothing will keep me from him.',17094,0,0,0,'overlord SAY_OUTRO_ALLY_6'), +(-1631056,'He... I can\'t do it. Get back on your ship and we\'ll spare your life.',16973,0,0,0,'bronzebeard SAY_OUTRO_ALLY_7'), +(-1631057,'Stand down, Muradin. Let a grieving father pass.',16690,0,0,0,'varian SAY_OUTRO_ALLY_8'), +(-1631058,'No\'ku kil zil\'nok ha tar.',17096,0,1,0,'overlord SAY_OUTRO_ALLY_9'), +(-1631059,'I will not forget this kindess. I thank you, highness.',17095,0,0,0,'overlord SAY_OUTRO_ALLY_10'), +(-1631060,'I... I was not at the Wrathgate. But the soldiers who survived told me much of what happened. Your son fought with honor. He died a hero\'s death. He deserves a hero\'s burial.',16691,0,0,0,'varian SAY_OUTRO_ALLY_11'), +(-1631061,'%s cries.',16651,2,0,0,'proudmore SAY_OUTRO_ALLY_12'), +(-1631062,'Jaina, why are you crying?',16692,0,0,0,'varian SAY_OUTRO_ALLY_13'), +(-1631063,'It was nothing, your majesty. Just... I\'m proud of my king.',16652,0,0,0,'proudmore SAY_OUTRO_ALLY_14'), +(-1631064,'Bah! Muradin, secure the deck and prepare our soldiers for an assault on the upper citadel. I\'ll send out another regiment from Stormwind.',16693,0,0,0,'varian SAY_OUTRO_ALLY_15'), +(-1631065,'Right away, yer majesty!',16979,0,0,0,'bronzebeard SAY_OUTRO_ALLY_16'), +(-1631066,'%s coughs.',17105,2,0,0,'overlord SAY_OUTRO_HORDE_1'), +(-1631067,'%s weeps over the corpse of his son.',17106,2,0,0,'overlord SAY_OUTRO_HORDE_2'), +(-1631068,'You will have a proper ceremony in Nagrand next to the pyres of your mother and ancestors.',17101,0,0,0,'overlord SAY_OUTRO_HORDE_3'), +(-1631069,'Honor, young heroes... no matter how dire the battle... Never forsake it!',17102,0,0,0,'overlord SAY_OUTRO_HORDE_4'), + +(-1631070,'What? Precious? Noooooooooo!!!',16993,6,0,0,'rotface SAY_PRECIOUS_DIES'), +(-1631071,'WEEEEEE!',16986,1,0,0,'rotface SAY_AGGRO'), +(-1631072,'Icky sticky.',16991,1,0,0,'rotface SAY_SLIME_SPRAY'), +(-1631073,'I think I made an angry poo-poo. It gonna blow!',16992,1,0,0,'rotface SAY_OOZE_EXPLODE'), +(-1631074,'Great news, everyone! The slime is flowing again!',17126,1,0,0,'putricide SAY_SLIME_FLOW_1'), +(-1631075,'Good news, everyone! I\'ve fixed the poison slime pipes!',17123,1,0,0,'putricide SAY_SLIME_FLOW_2'), +(-1631076,'Daddy make toys out of you!',16987,1,0,0,'rotface SAY_SLAY_1'), +(-1631077,'I brokes-ded it...',16988,1,0,0,'rotface SAY_SLAY_2'), +(-1631078,'Sleepy Time!',16990,1,0,0,'rotface SAY_BERSERK'), +(-1631079,'Bad news daddy.',16989,1,0,0,'rotface SAY_DEATH'), +(-1631080,'Terrible news, everyone, Rotface is dead! But great news everyone, he left behind plenty of ooze for me to use! Whaa...? I\'m a poet, and I didn\'t know it? Astounding!',17146,6,0,0,'putricide SAY_ROTFACE_DEATH'), + +(-1631081,'NOOOO! You kill Stinky! You pay!',16907,6,0,0,'festergut SAY_STINKY_DIES'), +(-1631082,'Fun time!',16901,1,0,0,'festergut SAY_AGGRO'), +(-1631083,'Just an ordinary gas cloud. But watch out, because that\'s no ordinary gas cloud! ',17119,1,0,0,'putricide SAY_BLIGHT'), +(-1631084,'%s farts.',16911,2,0,0,'festergut SAY_SPORE'), -- TODO Can be wrong +(-1631085,'Gyah! Uhhh, I not feel so good...',16906,1,0,0,'festergut SAY_PUNGUENT_BLIGHT'), +(-1631086,'%s vomits',0,2,0,0,'festergut SAY_PUNGUENT_BLIGHT_EMOTE'), -- TODO Can be wrong +(-1631087,'Daddy, I did it',16902,1,0,0,'festergut SAY_SLAY_1'), +(-1631088,'Dead, dead, dead!',16903,1,0,0,'festergut SAY_SLAY_2'), +(-1631089,'Fun time over!',16905,1,0,0,'festergut SAY_BERSERK'), +(-1631090,'Da ... Ddy...',16904,1,0,0,'festergut SAY_DEATH'), +(-1631091,'Oh, Festergut. You were always my favorite. Next to Rotface. The good news is you left behind so much gas, I can practically taste it!',17124,6,0,0,'putricide SAY_FESTERGUT_DEATH'), + +(-1631092,'Good news, everyone! I think I perfected a plague that will destroy all life on Azeroth!',17114,1,0,0,'putricide SAY_AGGRO'), +(-1631093,'You can\'t come in here all dirty like that! You need that nasty flesh scrubbed off first!',17125,1,0,0,'putricide SAY_AIRLOCK'), +(-1631094,'Two oozes, one room! So many delightful possibilities...',17122,1,0,0,'putricide SAY_PHASE_CHANGE'), +(-1631095,'Hmm. I don\'t feel a thing. Whaa...? Where\'d those come from?',17120,1,0,0,'putricide SAY_TRANSFORM_1'), +(-1631096,'Tastes like... Cherry! Oh! Excuse me!',17121,1,0,0,'putricide SAY_TRANSFORM_2'), +(-1631097,'Hmm... Interesting...',17115,1,0,0,'putricide SAY_SLAY_1'), +(-1631098,'That was unexpected!',17116,1,0,0,'putricide SAY_SLAY_2'), +(-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,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'), +(-1631104,'Blood will flow!',16728,1,0,0,'keleseth SAY_KELESETH_SPECIAL'), +(-1631105,'Were you ever a threat?',16723,1,0,0,'keleseth SAY_KELESETH_SLAY_1'), +(-1631106,'Truth is found in death.',16724,1,0,0,'keleseth SAY_KELESETH_SLAY_2'), +(-1631107,'%s cackles maniacally!',16726,2,0,0,'keleseth SAY_KELESETH_BERSERK'), -- TODO Can be wrong +(-1631108,'My queen... they come...',16725,1,0,0,'keleseth SAY_KELESETH_DEATH'), + +(-1631109,'Tremble before Taldaram, mortals, for the power of the orb flows through me!',16857,1,0,0,'taldaram SAY_TALDARAM_INVOCATION'), +(-1631110,'Delight in the pain!',16858,1,0,0,'taldaram SAY_TALDARAM_SPECIAL'), +(-1631111,'Worm food.',16853,1,0,0,'taldaram SAY_TALDARAM_SLAY_1'), +(-1631112,'Beg for mercy!',16854,1,0,0,'taldaram SAY_TALDARAM_SLAY_2'), +(-1631113,'%s laughs.',16856,2,0,0,'taldaram SAY_TALDARAM_BERSERK'), -- TODO Can be wrong +(-1631114,'%s gurgles and dies.',16855,2,0,0,'taldaram SAY_TALDARAM_DEATH'), -- TODO Can be wrong + +(-1631115,'Naxxanar was merely a setback! With the power of the orb, Valanar will have his vengeance!',16685,1,0,0,'valanar SAY_VALANAR_INVOCATION'), +(-1631116,'My cup runneth over.',16686,1,0,0,'valanar SAY_VALANAR_SPECIAL'), +(-1631117,'Dinner... is served.',16681,1,0,0,'valanar SAY_VALANAR_SLAY_1'), +(-1631118,'Do you see NOW the power of the Darkfallen?',16682,1,0,0,'valanar SAY_VALANAR_SLAY_2'), +(-1631119,'BOW DOWN BEFORE THE SAN\'LAYN!',16684,1,0,0,'valanar SAY_VALANAR_BERSERK'), +(-1631120,'...why...?',16683,1,0,0,'valanar SAY_VALANAR_DEATH'), + +(-1631121,'You have made an... unwise... decision.',16782,1,0,0,'blood_queen SAY_AGGRO'), +(-1631122,'Just a taste...',16783,1,0,0,'blood_queen SAY_BITE_1'), +(-1631123,'Know my hunger!',16784,1,0,0,'blood_queen SAY_BITE_2'), +(-1631124,'SUFFER!',16786,1,0,0,'blood_queen SAY_SHADOWS'), +(-1631125,'Can you handle this?',16787,1,0,0,'blood_queen SAY_PACT'), +(-1631126,'Yes... feed my precious one! You\'re mine now!',16790,1,0,0,'blood_queen SAY_MC'), +(-1631127,'Here it comes.',16788,1,0,0,'blood_queen SAY_AIR_PHASE'), +(-1631128,'THIS ENDS NOW!',16793,1,0,0,'blood_queen SAY_BERSERK'), +(-1631129,'But... we were getting along... so well...',16794,1,0,0,'blood_queen SAY_DEATH'), + +(-1631130,'Ready your arms, my Argent Brothers. The Vrykul will protect the Frost Queen with their lives.',16819,1,0,0,'scourgebane SAY_SVALNA_EVENT_1'), +(-1631131,'Even dying here beats spending another day collecting reagents for that madman, Finklestein.',16585,1,0,0,'arnath SAY_SVALNA_EVENT_2'), +(-1631132,'Enough idle banter! Our champions have arrived - support them as we push our way through the hall!',16820,1,0,0,'scourgebane SAY_SVALNA_EVENT_3'), +(-1631133,'You may have once fought beside me, Crok, but now you are nothing more than a traitor. Come, your second death approaches!',17017,1,0,0,'svalna SAY_SVALNA_EVENT_4'), +(-1631134,'Miserable creatures, Die!',17018,1,0,0,'svalna SAY_KILLING_CRUSADERS'), +(-1631135,'Foolish Crok, you brought my reinforcements with you! Arise Argent Champions and serve the Lich King in death!',17019,1,0,0,'svalna SAY_RESSURECT'), +(-1631136,'Come Scourgebane, I\'ll show the Lich King which one of us is truly worthy of the title, champion!',17020,1,0,0,'svalna SAY_SVALNA_AGGRO'), +(-1631137,'What? They died so easily? No matter.',17022,1,0,0,'svalna SAY_KILL_CAPTAIN'), +(-1631138,'What a pitiful choice of an ally Crok.',17021,1,0,0,'svalna SAY_KILL_PLAYER'), +(-1631139,'Perhaps... you were right... Crok.',17023,1,0,0,'svalna SAY_DEATH'), + +(-1631140,'Heroes, lend me your aid! I... I cannot hold them off much longer! You must heal my wounds!',17064,1,0,0,'dreamwalker SAY_AGGRO'), +(-1631141,'I have opened a portal into the Dream. Your salvation lies within, heroes.',17068,1,0,0,'dreamwalker SAY_PORTAL'), +(-1631142,'My strength is returning! Press on, heroes!',17070,1,0,0,'dreamwalker SAY_75_HEALTH'), +(-1631143,'I will not last much longer!',17069,1,0,0,'dreamwalker SAY_25_HEALTH'), +(-1631144,'Forgive me for what I do! I... cannot... stop... ONLY NIGHTMARES REMAIN!',17072,1,0,0,'dreamwalker SAY_0_HEALTH'), +(-1631145,'A tragic loss...',17066,1,0,0,'dreamwalker SAY_PLAYER_DIES'), +(-1631146,'FAILURES!',17067,1,0,0,'dreamwalker SAY_BERSERK'), +(-1631147,'I am renewed! Ysera grants me the favor to lay these foul creatures to rest!',17071,1,0,0,'dreamwalker SAY_VICTORY'), + +(-1631148,'You are fools who have come to this place! The icy winds of Northrend will consume your souls!',17007,1,0,0,'sindragosa SAY_AGGRO'), +(-1631149,'Suffer, mortals, as your pathetic magic betrays you!',17014,1,0,0,'sindragosa SAY_UNCHAINED_MAGIC'), +(-1631150,'Can you feel the cold hand of death upon your heart?',17013,1,0,0,'sindragosa SAY_BLISTERING_COLD'), +(-1631151,'Aaah! It burns! What sorcery is this?!',17015,1,0,0,'sindragosa SAY_RESPIRE'), +(-1631152,'Your incursion ends here! None shall survive!',17012,1,0,0,'sindragosa SAY_TAKEOFF'), +(-1631153,'Now feel my master\'s limitless power and despair!',17016,1,0,0,'sindragosa SAY_PHASE_3'), +(-1631154,'Perish!',17008,1,0,0,'sindragosa SAY_SLAY_1'), +(-1631155,'A flaw of mortality...',17009,1,0,0,'sindragosa SAY_SLAY_2'), +(-1631156,'Enough! I tire of these games!',17011,1,0,0,'sindragosa SAY_BERSERK'), +(-1631157,'Free...at last...',17010,1,0,0,'sindragosa SAY_DEATH'), + +(-1631158,'So...the Light\'s vaunted justice has finally arrived. Shall I lay down Frostmourne and throw myself at your mercy, Fordring?',17349,1,0,0,'lich_king SAY_INTRO_1'), +(-1631159,'We will grant you a swift death, Arthas. More than can be said for the thousands you\'ve tortured and slain.',17390,1,0,0,'tirion SAY_INTRO_2'), +(-1631160,'You will learn of that first hand. When my work is complete, you will beg for mercy -- and I will deny you. Your anguished cries will be testament to my unbridled power.',17350,1,0,0,'lich_king SAY_INTRO_3'), +(-1631161,'So be it. Champions, attack!',17391,1,0,0,'tirion SAY_INTRO_4'), +(-1631162,'I\'ll keep you alive to witness the end, Fordring. I would not want the Light\'s greatest champion to miss seeing this wretched world remade in my image.',17351,1,0,0,'lich_king SAY_INTRO_5'), +(-1631163,'Come then champions, feed me your rage!',17352,1,0,0,'lich_king SAY_AGGRO'), +(-1631164,'I will freeze you from within until all that remains is an icy husk!',17369,1,0,0,'lich_king SAY_REMORSELESS_WINTER'), +(-1631165,'Watch as the world around you collapses!',17370,1,0,0,'lich_king SAY_SHATTER_ARENA'), +(-1631166,'Val\'kyr, your master calls!',17373,1,0,0,'lich_king SAY_SUMMON_VALKYR'), +(-1631167,'Frostmourne hungers...',17366,1,0,0,'lich_king SAY_HARVEST_SOUL'), +(-1631168,'You have come to bring Arthas to justice? To see the Lich King destroyed?',17394,1,0,0,'terenas SAY_FM_TERENAS_AID_1'), +(-1631169,'First, you must escape Frostmourne\'s hold, or be damned as I am; trapped within this cursed blade for all eternity.',17395,1,0,0,'terenas SAY_FM_TERENAS_AID_2'), +(-1631170,'Aid me in destroying these tortured souls! Together we will loosen Frostmourne\'s hold and weaken the Lich King from within!',17396,1,0,0,'terenas SAY_FM_TERENAS_AID_3'), +(-1631171,'Argh... Frostmourne, obey me!',17367,1,0,0,'lich_king SAY_FM_PLAYER_ESCAPE'), +(-1631172,'Frostmourne feeds on the soul of your fallen ally!',17368,1,0,0,'lich_king SAY_FM_PLAYER_DEATH'), +(-1631173,'Apocalypse!',17371,1,0,0,'lich_king SAY_SPECIAL_1'), +(-1631174,'Bow down before your lord and master!',17372,1,0,0,'lich_king SAY_SPECIAL_2'), +(-1631175,'You gnats actually hurt me! Perhaps I\'ve toyed with you long enough, now taste the vengeance of the grave!',17359,1,0,0,'lich_king SAY_LAST_PHASE'), +(-1631176,'Hope wanes!',17363,1,0,0,'lich_king SAY_SLAY_1'), +(-1631177,'The end has come!',17364,1,0,0,'lich_king SAY_SLAY_2'), +(-1631178,'Face now your tragic end!',17365,1,0,0,'lich_king SAY_ENRAGE'), +(-1631179,'No question remains unanswered. No doubts linger. You are Azeroth\'s greatest champions! You overcame every challenge I laid before you. My mightiest servants have fallen before your relentless onslaught, your unbridled fury...',17353,1,0,0,'lich_king SAY_OUTRO_1'), +(-1631180,'Is it truly righteousness that drives you? I wonder',17354,1,0,0,'lich_king SAY_OUTRO_2'), +(-1631181,'You trained them well, Fordring. You delivered the greatest fighting force this world has ever known... right into my hands -- exactly as I intended. You shall be rewarded for your unwitting sacrifice.',17355,1,0,0,'lich_king SAY_OUTRO_3'), +(-1631182,'Watch now as I raise them from the dead to become masters of the Scourge. They will shroud this world in chaos and destruction. Azeroth\'s fall will come at their hands -- and you will be the first to die.',17356,1,0,0,'lich_king SAY_OUTRO_4'), +(-1631183,'I delight in the irony.',17357,1,0,0,'lich_king SAY_OUTRO_5'), +(-1631184,'LIGHT, GRANT ME ONE FINAL BLESSING. GIVE ME THE STRENGTH... TO SHATTER THESE BONDS!',17392,1,0,0,'tirion SAY_OUTRO_6'), +(-1631185,'Impossible...',17358,1,0,0,'lich_king SAY_OUTRO_7'), +(-1631186,'No more, Arthas! No more lives will be consumed by your hatred!',17393,1,0,0,'tirion SAY_OUTRO_8'), +(-1631187,'Free at last! It is over, my son. This is the moment of reckoning.',17397,1,0,0,'terenas SAY_OUTRO_9'), +(-1631188,'Rise up, champions of the Light!',17398,1,0,0,'terenas SAY_OUTRO_10'), +(-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 + +(-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 @@ -3132,7 +4564,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen -- -1 649 000 TRIAL OF THE CRUSADER INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1649000,'Welcome champions, you have heard the call of the argent crusade and you have boldly answered. It is here in the crusaders coliseum that you will face your greatest challenges. Those of you who survive the rigors of the coliseum will join the Argent Crusade on it''s marsh to ice crown citadel.',16036,1,0,0,'tirion SAY_TIRION_RAID_INTRO_LONG'), +(-1649000,'Welcome champions, you have heard the call of the argent crusade and you have boldly answered. It is here in the crusaders coliseum that you will face your greatest challenges. Those of you who survive the rigors of the coliseum will join the Argent Crusade on it\'s marsh to ice crown citadel.',16036,1,0,0,'tirion SAY_TIRION_RAID_INTRO_LONG'), (-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'), @@ -3144,38 +4576,38 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-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'), +(-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'), (-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'), +(-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'), -(-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'), +(-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_A_INTRO_2'), -(-1649025,'Show them no mercy, Horde champions! LOK''TAR OGAR!',16022,1,0,0,'garrosh SAY_GARROSH_PVP_H_INTRO_2'), -(-1649026,'Glory to the alliance.',16067,1,0,0,'varian SAY_VARIAN_PVP_A_WIN'), +(-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'), (-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'), +(-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,0,'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'), (-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'), +(-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 arrived, just as the master promised.',16235,1,0,0,'anubarak SAY_ANUB_ANUB_INTRO_1'), +(-1649038,'Ahhh, our guests have arrived, just as the master promised.',16235,1,0,0,'anubarak SAY_ANUB_ANUB_INTRO_1'), (-1649039,'%s glares at $N and lets out a bellowing roar!',0,3,0,0,'icehowl EMOTE_MASSIVE_CRASH'), @@ -3191,7 +4623,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-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'), +(-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'), @@ -3212,7 +4644,14 @@ 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'); -- -1 650 000 TRIAL OF THE CHAMPION @@ -3224,11 +4663,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'), @@ -3238,7 +4677,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'), @@ -3255,25 +4694,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'), @@ -3284,18 +4723,64 @@ 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 -- -1 724 000 RUBY SANCTUM - +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1724000,'Help! I am trapped within this tree! I require aid!',17490,6,0,0,'xerestraza SAY_HELP'), +(-1724001,'Your power wanes, ancient one! Soon, you will join your friends!',17525,6,0,0,'baltharus SAY_INTRO'), +(-1724002,'Thank you! I could have not held out for much longer. A terrible thing has happened here.',17491,1,0,0,'xerestraza SAY_THANKS'), +(-1724003,'We believed that the Sanctum was well fortified, but we were not prepareted for the nature of this assault.',17492,0,0,0,'xerestraza SAY_OUTRO_1'), +(-1724004,'The Black Dragonkin materialized from thin air, and set upon us before we could react.',17493,0,0,0,'xerestraza SAY_OUTRO_2'), +(-1724005,'We did not stand a chance. As my brethren perished around me, I managed to retreat hear and bar the entrance.',17494,0,0,0,'xerestraza SAY_OUTRO_3'), +(-1724006,'They slaughtered us with cold efficiency, but the true focus of their interest seemed to be the eggs kept here in the sanctum.',17495,0,0,0,'xerestraza SAY_OUTRO_4'), +(-1724007,'The commander of the forces on the ground here is a cruel brute named Zarithrian. But I fear there are greater powers at work.',17496,0,0,0,'xerestraza SAY_OUTRO_5'), +(-1724008,'In their initial assault I caught a glimpse of their true leader, a fearsome full-grown Twilight Dragon.',17497,0,0,0,'xerestraza SAY_OUTRO_6'), +(-1724009,'I know not the extent of their plans heroes, but I know this: they cannot be allowed to succeed!',17498,0,0,0,'xerestraza SAY_OUTRO_7'), + +(-1724010,'Ah, the entertainment has arrived.',17520,1,0,0,'baltharus SAY_AGGRO'), +(-1724011,'Baltharus leaves no survivors!',17521,1,0,0,'baltharus SAY_SLAY_1'), +(-1724012,'This world has enough heroes.',17522,1,0,0,'baltharus SAY_SLAY_2'), +(-1724013,'I... Didn\'t see that coming...',17523,1,0,0,'baltharus SAY_DEATH'), +(-1724014,'Twice the pain and half the fun.',17524,1,0,0,'baltharus SAY_SPLIT'), + +(-1724015,'You will suffer for this intrusion!',17528,1,0,0,'saviana SAY_AGGRO'), +(-1724016,'As it should be...',17529,1,0,0,'saviana SAY_SLAY_1'), +(-1724017,'Halion will be pleased.',17530,1,0,0,'saviana SAY_SLAY_2'), +(-1724018,'Burn in the master\'s flame!',17532,1,0,0,'saviana SAY_SPECIAL'), + +(-1724019,'Alexstrasza has chosen capable allies... A pity that I must END YOU!',17512,1,0,0,'zarithrian SAY_AGGRO'), +(-1724020,'You thought you stood a chance?',17513,1,0,0,'zarithrian SAY_SLAY_1'), +(-1724021,'It\'s for the best.',17514,1,0,0,'zarithrian SAY_SLAY_2'), +(-1724022,'HALION! I...',17515,1,0,0,'zarithrian SAY_DEATH'), +(-1724023,'Turn them to ash, minions!',17516,1,0,0,'zarithrian SAY_SUMMON'), + +(-1724024,'Meddlesome insects! You\'re too late: The Ruby Sanctum\'s lost.',17499,6,0,0,'halion SAY_SPAWN'), +(-1724025,'Your world teeters on the brink of annihilation. You will ALL bear witness to the coming of a new age of DESTRUCTION!',17500,1,0,0,'halion SAY_AGGRO'), +(-1724026,'Another hero falls.',17501,1,0,0,'halion SAY_SLAY'), +(-1724027,'Relish this victory, mortals, for it will be your last! This world will burn with the master\'s return!',17503,1,0,0,'halion SAY_DEATH'), +(-1724028,'Not good enough.',17504,1,0,0,'halion SAY_BERSERK'), +(-1724029,'The heavens burn!',17505,1,0,0,'halion SAY_FIREBALL'), +(-1724030,'Beware the shadow!',17506,1,0,0,'halion SAY_SPHERES'), +(-1724031,'You will find only suffering within the realm of twilight! Enter if you dare!',17507,1,0,0,'halion SAY_PHASE_2'), +(-1724032,'I am the light and the darkness! Cower, mortals, before the herald of Deathwing!',17508,1,0,0,'halion SAY_PHASE_3'), +(-1724033,'The orbining spheres pulse with dark energy!',0,3,0,0,'halion EMOTE_SPHERES'), +(-1724034,'Your efforts force %s further out of the twillight realm!',0,3,0,0,'halion EMOTE_OUT_OF_TWILLIGHT'), +(-1724035,'Your efforts force %s further out of the physical realm!',0,3,0,0,'halion EMOTE_OUT_OF_PHYSICAL'), +(-1724036,'Your companions\' efforts force Halion further into the twillight realm!',0,3,0,0,'halion EMOTE_INTO_TWILLIGHT'), +(-1724037,'Your companions\' efforts force Halion further into the physical realm!',0,3,0,0,'halion EMOTE_INTO_PHYSICAL'), +(-1724038,'Without pressure in both realms %s begins to regenerate.',0,3,0,0,'halion EMOTE_REGENERATE'); -- -1 999 900 EXAMPLE TEXT INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3347,24 +4832,111 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES -- -3 000 100 GENERAL MAPS (not instance maps) INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3000101,'Taruk send me to collect what you owe.','silvermoon harry GOSSIP_ITEM_GAMBLING_DEBT'), -(-3000102,'Here\'s the money.','silvermoon harry GOSSIP_ITEM_PAYING'), +(-3000102,'Pay up, Harry!','silvermoon harry GOSSIP_ITEM_PAYING'), (-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'); +(-3000105,'Ezekiel said that you might have a certain book...','dirty larry GOSSIP_ITEM_BOOK'), +(-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 +(-3033000,'Please unlock the courtyard door.','deathstalker adamant/ sorcerer ashcrombe - GOSSIP_ITEM_DOOR'); + +-- -3 043 000 WAILING CAVERNS +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3043000,'Let the event begin!','Disciple of Naralex - GOSSIP_ITEM_BEGIN'); -- -3 090 000 GNOMEREGAN 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'), +(-3409001,'What else do you have to say?','majordomo_executus GOSSIP_ITEM_SUMMON_2'), +(-3409002,'You challenged us and we have come. Where is this master you speak of?','majordomo_executus GOSSIP_ITEM_SUMMON_3'); + +-- -3 469 000 BLACKWING LAIR +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3469000,'I\'ve made no mistakes.','victor_nefarius GOSSIP_ITEM_NEFARIUS_1'), +(-3469001,'You have lost your mind, Nefarius. You speak in riddles.','victor_nefarius GOSSIP_ITEM_NEFARIUS_2'), +(-3469002,'Please do.','victor_nefarius GOSSIP_ITEM_NEFARIUS_3'), + +(-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,'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 @@ -3373,7 +4945,14 @@ 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.$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'); + +-- -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 @@ -3385,16 +4964,41 @@ 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 -(-3649000,'Yes. We are prepared for the challenges ahead of us.','barrett GOSSIP_ITEM_START_EVENT1'); +(-3649000,'Yes. We are prepared for the challenges ahead of us.','barrett GOSSIP_ITEM_BEAST_INIT'), +(-3649001,'Bring forth the first challenge!','barrett GOSSIP_ITEM_BEAST_START'), +(-3649002,'We want another shot at those beasts!','barrett GOSSIP_ITEM_BEAST_WIPE_INIT'), +(-3649003,'What new challenge awaits us?','barrett GOSSIP_ITEM_JARAXXUS_INIT'), +(-3649004,'We\'re ready to fight the sorceror again.','barrett GOSSIP_ITEM_JARAXXUS_WIPE_INIT'), +(-3649005,'Of course!','barrett GOSSIP_ITEM_PVP_INIT'), +(-3649006,'Give the signal! We\'re ready to go!','barrett GOSSIP_ITEM_PVP_START'), +(-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'); + -- -- Below just for beautiful view in table, run at own desire @@ -4442,7 +6046,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, ''), @@ -4450,107 +6054,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 @@ -4581,6 +6197,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, ''), @@ -4604,18 +6243,6 @@ INSERT INTO script_waypoint VALUES (18210, 18, -1324.803589, 8510.688477, 13.050, 0, ''), (18210, 19, -1312.075439, 8492.709961, 14.235, 0, ''); -DELETE FROM script_waypoint WHERE entry=18731; -INSERT INTO script_waypoint VALUES -(18731, 0, -157.366, 2.177, 8.073, 0, ''), -(18731, 1, -172.266, -18.280, 8.073, 0, ''), -(18731, 2, -171.051, -38.748, 8.073, 0, ''), -(18731, 3, -170.718, -59.436, 8.073, 0, ''), -(18731, 4, -156.659, -72.118, 8.073, 0, ''), -(18731, 5, -142.292, -59.423, 8.073, 0, ''), -(18731, 6, -141.779, -38.972, 8.073, 0, ''), -(18731, 7, -142.922, -18.950, 8.073, 0, ''), -(18731, 8, -157.366, 2.177, 8.073, 0, ''); - DELETE FROM script_waypoint WHERE entry=18887; INSERT INTO script_waypoint VALUES (18887, 0, 2650.06, 665.473, 61.9305, 0, ''), @@ -4625,7 +6252,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, ''), @@ -4780,7 +6407,7 @@ INSERT INTO script_waypoint VALUES (20129, 25, -8375.42,-4250.41, -205.14,5000, ''); DELETE FROM script_waypoint WHERE entry=20415; -INSERT INTO script_waypoint VALUES +INSERT INTO script_waypoint VALUES (20415, 0, 2488.77, 2184.89, 104.64, 0, ""), (20415, 1, 2478.72, 2184.77, 98.58, 0, ""), (20415, 2, 2473.52, 2184.71, 99.00, 0, ""), @@ -5091,6 +6718,31 @@ INSERT INTO script_waypoint VALUES (28217,23, 5638.541504, 4594.924805, -137.495117, 0, 'summon'), (28217,24, 5638.061523, 4579.945801, -138.029465, 0, ''); +DELETE FROM script_waypoint WHERE entry=28787; +INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, waittime, point_comment) VALUES +(28787, 1, 5913.516113, 5379.034668, -98.896118, 0, ''), +(28787, 2, 5917.750977, 5374.519043, -98.869781, 0, 'SAY_HELICE_EXPLOSIVES_1'), +(28787, 3, 5926.428711, 5372.145020, -98.884453, 0, ''), +(28787, 4, 5929.214844, 5377.803223, -99.020065, 0, ''), +(28787, 5, 5927.621582, 5378.564941, -99.047890, 0, ''), +(28787, 6, 5917.622070, 5383.494629, -106.310204, 0, ''), +(28787, 7, 5908.991211, 5387.655762, -106.310204, 0, ''), +(28787, 8, 5906.287109, 5390.496582, -106.041801, 0, ''), +(28787, 9, 5902.415039, 5399.741211, -99.306595, 0, ''), +(28787, 10, 5901.444336, 5404.593262, -96.759636, 0, ''), +(28787, 11, 5897.860352, 5406.656250, -96.029709, 0, ''), +(28787, 12, 5892.254395, 5401.291504, -95.848808, 0, ''), +(28787, 13, 5887.421875, 5386.701172, -95.400146, 0, 'SAY_HELICE_EXPLOSIVES_2'), +(28787, 14, 5883.308105, 5385.057617, -94.423698, 0, ''), +(28787, 15, 5879.180664, 5375.897461, -95.088066, 0, ''), +(28787, 16, 5872.613281, 5363.473633, -97.703575, 0, ''), +(28787, 17, 5857.971191, 5354.929688, -98.586090, 0, ''), +(28787, 18, 5848.729004, 5345.326660, -99.428978, 0, ''), +(28787, 19, 5842.330566, 5335.018555, -100.421455, 0, ''), +(28787, 20, 5832.164551, 5323.145020, -98.703285, 0, ''), +(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'), @@ -5109,9 +6761,10 @@ 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 @@ -5226,28 +6879,1631 @@ INSERT INTO script_waypoint VALUES (25208,24,4254.66,6205.16,-0.170,0,''), (25208,25,4270.07,6188.42,0.059,15000,'Lurgglbr - final point'); --- uncomment when it is implemented --- DELETE FROM script_waypoint WHERE entry=7998; --- INSERT INTO script_waypoint VALUES --- (7998, 01, -510.1305, -132.6899, -152.5, 0, ''), --- (7998, 02, -511.0994, -129.74, -153.8453, 0, ''), --- (7998, 03, -511.7897, -127.4764, -155.5505, 0, ''), --- (7998, 04, -512.9688, -124.926, -156.1146, 5000, ''), --- (7998, 05, -513.9719, -120.2358, -156.1161, 0, ''), --- (7998, 06, -514.3875, -115.1896, -156.1165, 0, ''), --- (7998, 07, -514.3039, -111.4777, -155.5205, 0, ''), --- (7998, 08, -514.8401, -107.6633, -154.8925, 0, ''), --- (7998, 09, -518.9943, -101.4161, -154.6482, 27000, ''), --- (7998, 10, -526.9984, -98.14884, -155.6253, 0, ''), --- (7998, 11, -534.5686, -105.4101, -155.989, 30000, ''), --- (7998, 12, -535.5336, -104.6947, -155.9713, 0, ''), --- (7998, 13, -541.6304, -98.6583, -155.8584, 25000, ''), --- (7998, 14, -535.0923, -99.91748, -155.9742, 0, ''), --- (7998, 15, -519.0099, -101.5097, -154.6766, 3000, ''), --- (7998, 16, -504.4659, -97.84802, -150.9554, 30000, ''), --- (7998, 17, -506.9069, -89.14736, -151.083, 23000, ''), --- (7998, 18, -512.7576, -101.9025, -153.198, 0, ''), --- (7998, 19, -519.9883, -124.8479, -156.128, 86400000, 'this npc should not reset on wp end'); +DELETE FROM script_waypoint WHERE entry=7998; +INSERT INTO script_waypoint VALUES +(7998, 01, -510.1305, -132.6899, -152.5, 0, ''), +(7998, 02, -511.0994, -129.74, -153.8453, 0, ''), +(7998, 03, -511.7897, -127.4764, -155.5505, 0, ''), +(7998, 04, -512.9688, -124.926, -156.1146, 5000, ''), +(7998, 05, -513.9719, -120.2358, -156.1161, 0, ''), +(7998, 06, -514.3875, -115.1896, -156.1165, 0, ''), +(7998, 07, -514.3039, -111.4777, -155.5205, 0, ''), +(7998, 08, -514.8401, -107.6633, -154.8925, 0, ''), +(7998, 09, -518.9943, -101.4161, -154.6482, 27000, ''), +(7998, 10, -526.9984, -98.14884, -155.6253, 0, ''), +(7998, 11, -534.5686, -105.4101, -155.989, 30000, ''), +(7998, 12, -535.5336, -104.6947, -155.9713, 0, ''), +(7998, 13, -541.6304, -98.6583, -155.8584, 25000, ''), +(7998, 14, -535.0923, -99.91748, -155.9742, 0, ''), +(7998, 15, -519.0099, -101.5097, -154.6766, 3000, ''), +(7998, 16, -504.4659, -97.84802, -150.9554, 30000, ''), +(7998, 17, -506.9069, -89.14736, -151.083, 23000, ''), +(7998, 18, -512.7576, -101.9025, -153.198, 0, ''), +(7998, 19, -519.9883, -124.8479, -156.128, 86400000, 'this npc should not reset on wp end'); + +DELETE FROM script_waypoint WHERE entry = 18760; +INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, waittime, point_comment) VALUES +(18760, 01, -2267.07, 3091.46, 13.8271, 0, ''), +(18760, 02, -2270.92, 3094.19, 13.8271, 0, ''), +(18760, 03, -2279.08, 3100.04, 13.8271, 0, ''), +(18760, 04, -2290.05, 3105.07, 13.8271, 0, ''), +(18760, 05, -2297.64, 3112.32, 13.8271, 0, ''), +(18760, 06, -2303.89, 3118.22, 13.8231, 10000, 'building exit'), +(18760, 07, -2307.77, 3123.47, 13.7257, 0, ''), +(18760, 08, -2310.67, 3126.2, 12.5841, 0, ''), +(18760, 09, -2311.48, 3126.98, 12.2769, 0, ''), +(18760, 10, -2316.91, 3132.13, 11.9261, 0, ''), +(18760, 11, -2320.43, 3135.54, 11.7436, 0, ''), +(18760, 12, -2327.38, 3139.36, 10.9431, 0, ''), +(18760, 13, -2332.02, 3142.05, 9.81277, 0, ''), +(18760, 14, -2338.21, 3145.32, 9.31001, 0, ''), +(18760, 15, -2343.1, 3148.91, 8.84879, 0, ''), +(18760, 16, -2347.76, 3153.15, 7.71049, 0, ''), +(18760, 17, -2351.04, 3156.12, 6.66476, 0, ''), +(18760, 18, -2355.15, 3163.18, 5.11997, 0, ''), +(18760, 19, -2359.01, 3169.83, 3.64343, 0, ''), +(18760, 20, -2364.85, 3176.81, 2.32802, 0, ''), +(18760, 21, -2368.77, 3181.69, 1.53285, 0, ''), +(18760, 22, -2371.76, 3185.11, 0.979932, 0, ''), +(18760, 23, -2371.85, 3191.89, -0.293048, 0, ''), +(18760, 24, -2370.99, 3199.6, -1.10504, 0, 'turn left 1'), +(18760, 25, -2376.24, 3205.54, -1.04152, 0, ''), +(18760, 26, -2380.99, 3211.61, -1.16891, 0, ''), +(18760, 27, -2384.04, 3218.4, -1.15279, 0, ''), +(18760, 28, -2385.41, 3226.22, -1.23403, 0, ''), +(18760, 29, -2386.02, 3233.89, -1.31723, 0, ''), +(18760, 30, -2384.7, 3239.82, -1.51903, 0, ''), +(18760, 31, -2382.98, 3247.94, -1.39163, 0, ''), +(18760, 32, -2379.68, 3254.22, -1.25927, 0, ''), +(18760, 33, -2375.27, 3259.69, -1.22925, 0, ''), +(18760, 34, -2369.62, 3264.55, -1.1879, 0, ''), +(18760, 35, -2364.01, 3268.32, -1.48348, 0, ''), +(18760, 36, -2356.61, 3272.31, -1.5505, 0, ''), +(18760, 37, -2352.3, 3274.63, -1.35693, 0, ''), +(18760, 38, -2348.54, 3278.04, -1.04161, 0, 'turn left 2'), +(18760, 39, -2347.56, 3282.41, -0.75979, 0, ''), +(18760, 40, -2348.29, 3288.91, -0.63215, 0, ''), +(18760, 41, -2349.68, 3298.84, -1.07864, 0, ''), +(18760, 42, -2351.15, 3308.52, -1.38864, 0, ''), +(18760, 43, -2352.2, 3317.14, -1.59873, 0, ''), +(18760, 44, -2351.59, 3325.51, -1.92624, 0, ''), +(18760, 45, -2350.88, 3333.38, -2.32506, 0, ''), +(18760, 46, -2350.05, 3342.68, -2.51886, 0, ''), +(18760, 47, -2350.12, 3347.32, -2.57528, 0, ''), +(18760, 48, -2348.72, 3353.7, -2.72689, 0, ''), +(18760, 49, -2346.53, 3360.85, -2.9756, 0, ''), +(18760, 50, -2344.83, 3365.46, -3.3311, 0, ''), +(18760, 51, -2342.68, 3368.91, -3.74526, 0, ''), +(18760, 52, -2340.25, 3371.44, -4.10499, 0, ''), +(18760, 53, -2337.4, 3373.47, -4.44362, 0, ''), +(18760, 54, -2332.68, 3376.02, -5.19648, 0, ''), +(18760, 55, -2326.69, 3379.64, -6.24757, 0, ''), +(18760, 56, -2321.2, 3383.98, -7.28247, 0, ''), +(18760, 57, -2317.81, 3387.78, -8.40093, 0, ''), +(18760, 58, -2315.3, 3392.47, -9.63431, 0, ''), +(18760, 59, -2314.69, 3396.6, -10.2031, 0, ''), +(18760, 60, -2315.48, 3402.35, -10.8211, 0, 'gate'), +(18760, 61, -2317.55, 3409.27, -11.3309, 5000, 'Firewing point exit'), +(18760, 62, -2320.69, 3412.99, -11.5207, 0, ''), +(18760, 63, -2326.88, 3417.89, -11.6105, 0, ''), +(18760, 64, -2332.73, 3421.74, -11.5659, 0, ''), +(18760, 65, -2337.23, 3424.89, -11.496, 0, ''), +(18760, 66, -2339.57, 3429.17, -11.3782, 0, ''), +(18760, 67, -2341.66, 3435.86, -11.3746, 5000, 'Wave and transform'), +(18760, 68, -2342.15, 3443.94, -11.2562, 2000, 'final destination'); + +DELETE FROM script_waypoint WHERE entry=3678; +INSERT INTO script_waypoint VALUES +(3678, 0, -134.925, 125.468, -78.16, 0, ''), +(3678, 1, -125.684, 132.937, -78.42, 0, ''), +(3678, 2, -113.812, 139.295, -80.98, 0, ''), +(3678, 3, -109.854, 157.538, -80.20, 0, ''), +(3678, 4, -108.640, 175.207, -79.74, 0, ''), +(3678, 5, -108.668, 195.457, -80.64, 0, ''), +(3678, 6, -111.007, 219.007, -86.58, 0, ''), +(3678, 7, -102.408, 232.821, -91.52, 0, 'first corner SAY_FIRST_CORNER'), +(3678, 8, -92.434, 227.742, -90.75, 0, ''), +(3678, 9, -82.456, 224.853, -93.57, 0, ''), +(3678, 10, -67.789, 208.073, -93.34, 0, ''), +(3678, 11, -43.343, 205.295, -96.37, 0, ''), +(3678, 12, -34.676, 221.394, -95.82, 0, ''), +(3678, 13, -32.582, 238.573, -93.51, 0, ''), +(3678, 14, -42.149, 258.672, -92.88, 0, ''), +(3678, 15, -55.257, 274.696, -92.83, 0, 'circle of flames SAY_CIRCLE_BANISH'), +(3678, 16, -48.604, 287.584, -92.46, 0, ''), +(3678, 17, -47.236, 296.093, -90.88, 0, ''), +(3678, 18, -35.618, 309.067, -89.73, 0, ''), +(3678, 19, -23.573, 311.376, -88.60, 0, ''), +(3678, 20, -8.692, 302.389, -87.43, 0, ''), +(3678, 21, -1.237, 293.268, -85.55, 0, ''), +(3678, 22, 10.398, 279.294, -85.86, 0, ''), +(3678, 23, 23.108, 264.693, -86.69, 0, ''), +(3678, 24, 31.996, 251.436, -87.62, 0, ''), +(3678, 25, 43.374, 233.073, -87.61, 0, ''), +(3678, 26, 54.438, 212.048, -89.50, 3000, 'chamber entrance SAY_NARALEX_CHAMBER'), +(3678, 27, 78.794, 208.895, -92.84, 0, ''), +(3678, 28, 88.392, 225.231, -94.46, 0, ''), +(3678, 29, 98.758, 233.938, -95.84, 0, ''), +(3678, 30, 107.248, 233.054, -95.98, 0, ''), +(3678, 31, 112.825, 233.907, -96.39, 0, ''), +(3678, 32, 114.634, 236.969, -96.04, 1000, 'naralex SAY_BEGIN_RITUAL'), +(3678, 33, 127.385, 252.279, -90.07, 0, ''), +(3678, 34, 121.595, 264.488, -91.55, 0, ''), +(3678, 35, 115.472, 264.253, -91.50, 0, ''), +(3678, 36, 99.988, 252.790, -91.51, 0, ''), +(3678, 37, 96.347, 245.038, -90.34, 0, ''), +(3678, 38, 82.201, 216.273, -86.10, 0, ''), +(3678, 39, 75.112, 206.494, -84.80, 0, ''), +(3678, 40, 27.174, 201.064, -72.31, 0, ''), +(3678, 41, -41.114, 204.149, -78.94, 0, ''); + +DELETE FROM script_waypoint WHERE entry=5644; +INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, waittime, point_comment) VALUES +(5644, 1, -339.679, 1752.04, 139.482, 0, ''), +(5644, 2, -328.957, 1734.95, 139.327, 0, ''), +(5644, 3, -338.29, 1731.36, 139.327, 0, ''), +(5644, 4, -350.747, 1731.12, 139.338, 0, ''), +(5644, 5, -365.064, 1739.04, 139.376, 0, ''), +(5644, 6, -371.105, 1746.03, 139.374, 0, ''), +(5644, 7, -383.141, 1738.62, 138.93, 0, ''), +(5644, 8, -390.445, 1733.98, 136.353, 0, ''), +(5644, 9, -401.368, 1726.77, 131.071, 0, ''), +(5644, 10, -416.016, 1721.19, 129.807, 0, ''), +(5644, 11, -437.139, 1709.82, 126.342, 0, ''), +(5644, 12, -455.83, 1695.61, 119.305, 0, ''), +(5644, 13, -459.862, 1687.92, 116.059, 0, ''), +(5644, 14, -463.565, 1679.1, 111.653, 0, ''), +(5644, 15, -461.485, 1670.94, 109.033, 0, ''), +(5644, 16, -471.786, 1647.34, 102.862, 0, ''), +(5644, 17, -477.146, 1625.69, 98.342, 0, ''), +(5644, 18, -475.815, 1615.815, 97.07, 0, ''), +(5644, 19, -474.329, 1590.01, 94.4982, 0, ''); + +DELETE FROM script_waypoint WHERE entry=4508; +INSERT INTO script_waypoint VALUES +(4508, 0, 2194.38, 1791.65, 65.48, 5000, ''), +(4508, 1, 2188.56, 1805.87, 64.45, 0, ''), +(4508, 2, 2186.2, 1836.278, 59.859, 5000, 'SAY_WILLIX_1'), +(4508, 3, 2163.27, 1851.67, 56.73, 0, ''), +(4508, 4, 2140.22, 1845.02, 48.32, 0, ''), +(4508, 5, 2131.5, 1804.29, 46.85, 0, ''), +(4508, 6, 2096.18, 1789.03, 51.13, 3000, 'SAY_WILLIX_2'), +(4508, 7, 2074.46, 1780.09, 55.64, 0, ''), +(4508, 8, 2055.12, 1768.67, 58.46, 0, ''), +(4508, 9, 2037.83, 1748.62, 60.27, 5000, 'SAY_WILLIX_3'), +(4508, 10, 2037.51, 1728.94, 60.85, 0, ''), +(4508, 11, 2044.7, 1711.71, 59.71, 0, ''), +(4508, 12, 2067.66, 1701.84, 57.77, 0, ''), +(4508, 13, 2078.91, 1704.54, 56.77, 0, ''), +(4508, 14, 2097.65, 1715.24, 54.74, 3000, 'SAY_WILLIX_4'), +(4508, 15, 2106.44, 1720.98, 54.41, 0, ''), +(4508, 16, 2123.96, 1732.56, 52.27, 0, ''), +(4508, 17, 2153.82, 1728.73, 51.92, 0, ''), +(4508, 18, 2163.49, 1706.33, 54.42, 0, ''), +(4508, 19, 2158.75, 1695.98, 55.70, 0, ''), +(4508, 20, 2142.6, 1680.72, 58.24, 0, ''), +(4508, 21, 2118.31, 1671.54, 59.21, 0, ''), +(4508, 22, 2086.02, 1672.04, 61.24, 0, ''), +(4508, 23, 2068.81, 1658.93, 61.24, 0, ''), +(4508, 24, 2062.82, 1633.31, 64.35, 0, ''), +(4508, 25, 2060.92, 1600.11, 62.41, 3000, 'SAY_WILLIX_5'), +(4508, 26, 2063.05, 1589.16, 63.26, 0, ''), +(4508, 27, 2063.67, 1577.22, 65.89, 0, ''), +(4508, 28, 2057.94, 1560.68, 68.40, 0, ''), +(4508, 29, 2052.56, 1548.05, 73.35, 0, ''), +(4508, 30, 2045.22, 1543.4, 76.65, 0, ''), +(4508, 31, 2034.35, 1543.01, 79.70, 0, ''), +(4508, 32, 2029.95, 1542.94, 80.79, 0, ''), +(4508, 33, 2021.34, 1538.67, 80.8, 0, 'SAY_WILLIX_6'), +(4508, 34, 2012.45, 1549.48, 79.93, 0, ''), +(4508, 35, 2008.05, 1554.92, 80.44, 0, ''), +(4508, 36, 2006.54, 1562.72, 81.11, 0, ''), +(4508, 37, 2003.8, 1576.43, 81.57, 0, ''), +(4508, 38, 2000.57, 1590.06, 80.62, 0, ''), +(4508, 39, 1998.96, 1596.87, 80.22, 0, ''), +(4508, 40, 1991.19, 1600.82, 79.39, 0, ''), +(4508, 41, 1980.71, 1601.44, 79.77, 0, ''), +(4508, 42, 1967.22, 1600.18, 80.62, 0, ''), +(4508, 43, 1956.43, 1596.97, 81.75, 0, ''), +(4508, 44, 1954.87, 1592.02, 82.18, 3000, 'SAY_WILLIX_7'), +(4508, 45, 1948.35, 1571.35, 80.96, 30000, 'SAY_WILLIX_END'), +(4508, 46, 1947.02, 1566.42, 81.80, 30000, ''); + +DELETE FROM script_waypoint WHERE entry = 8516; +INSERT INTO script_waypoint VALUES +(8516, 1,2603.18, 725.259, 54.6927, 0, ''), +(8516, 2,2587.13, 734.392, 55.231, 0, ''), +(8516, 3,2570.69, 753.572, 54.5855, 0, ''), +(8516, 4,2558.51, 747.66, 54.4482, 0, ''), +(8516, 5,2544.23, 772.924, 47.9255, 0, ''), +(8516, 6,2530.08, 797.475, 45.97, 0, ''), +(8516, 7,2521.83, 799.127, 44.3061, 0, ''), +(8516, 8,2502.61, 789.222, 39.5074, 0, ''), +(8516, 9,2495.25, 789.406, 39.499, 0, ''), +(8516, 10,2488.07, 802.455, 42.9834, 0, ''), +(8516, 11,2486.64, 826.649, 43.6363, 0, ''), +(8516, 12,2492.64, 835.166, 45.1427, 0, ''), +(8516, 13,2505.02, 847.564, 47.6487, 0, ''), +(8516, 14,2538.96, 877.362, 47.6781, 0, ''), +(8516, 15,2546.07, 885.672, 47.6789, 0, ''), +(8516, 16,2548.02, 897.584, 47.7277, 0, ''), +(8516, 17,2544.29, 909.116, 46.2506, 0, ''), +(8516, 18,2523.60, 920.306, 45.8717, 0, ''), +(8516, 19,2522.69, 933.546, 47.5769, 0, ''), +(8516, 20,2531.63, 959.893, 49.4111, 0, ''), +(8516, 21,2540.23, 973.338, 50.1241, 0, ''), +(8516, 22,2547.21, 977.489, 49.9759, 0, ''), +(8516, 23,2558.75, 969.243, 50.7353, 0, ''), +(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'), +(11832, 1, 7848.385645, -2216.356670, 470.888333, 5000, 'SAY_REMULOS_INTRO_2'), +(11832, 2, 7829.785645, -2244.836670, 463.853333, 0, ''), +(11832, 3, 7819.010742, -2304.344238, 455.956726, 0, ''), +(11832, 4, 7931.099121, -2314.350830, 473.054047, 0, ''), +(11832, 5, 7943.553223, -2324.688721, 477.676819, 0, ''), +(11832, 6, 7952.017578, -2351.135010, 485.234924, 0, ''), +(11832, 7, 7963.672852, -2412.990967, 488.953369, 0, ''), +(11832, 8, 7975.178223, -2551.602051, 490.079926, 0, ''), +(11832, 9, 7948.046875, -2570.828613, 489.750732, 0, ''), +(11832, 10, 7947.161133, -2583.396729, 490.066284, 0, ''), +(11832, 11, 7951.086426, -2596.215088, 489.831268, 0, ''), +(11832, 12, 7948.267090, -2610.062988, 492.340424, 0, ''), +(11832, 13, 7928.521973, -2625.954346, 492.447540, 0, 'escort paused - SAY_REMULOS_INTRO_3'), +(11832, 14, 7948.267090, -2610.062988, 492.340424, 0, ''), +(11832, 15, 7952.318848, -2594.118408, 490.070374, 0, ''), +(11832, 16, 7913.988770, -2567.002686, 488.330566, 0, ''), +(11832, 17, 7835.454102, -2571.099121, 489.289246, 0, 'escort paused - SAY_REMULOS_DEFEND_2'), +(11832, 18, 7897.283691, -2560.652344, 487.461304, 0, 'escort paused'); + +DELETE FROM script_waypoint WHERE entry=10300; +INSERT INTO script_waypoint VALUES +(10300, 1, 5728.81, -4801.15, 778.18, 0, ''), +(10300, 2, 5730.22, -4818.34, 777.11, 0, ''), +(10300, 3, 5728.12, -4835.76, 778.15, 1000, 'SAY_ENTER_OWL_THICKET'), +(10300, 4, 5718.85, -4865.62, 787.56, 0, ''), +(10300, 5, 5697.13, -4909.12, 801.53, 0, ''), +(10300, 6, 5684.20, -4913.75, 801.60, 0, ''), +(10300, 7, 5674.67, -4915.78, 802.13, 0, ''), +(10300, 8, 5665.61, -4919.22, 804.85, 0, ''), +(10300, 9, 5638.22, -4897.58, 804.97, 0, ''), +(10300, 10, 5632.67, -4892.05, 805.44, 0, 'Cavern 1 - EMOTE_CHANT_SPELL'), +(10300, 11, 5664.58, -4921.84, 804.91, 0, ''), +(10300, 12, 5684.21, -4943.81, 802.80, 0, ''), +(10300, 13, 5724.92, -4983.69, 808.25, 0, ''), +(10300, 14, 5753.39, -4990.73, 809.84, 0, ''), +(10300, 15, 5765.62, -4994.89, 809.42, 0, 'Cavern 2 - EMOTE_CHANT_SPELL'), +(10300, 16, 5724.94, -4983.58, 808.29, 0, ''), +(10300, 17, 5699.61, -4989.82, 808.03, 0, ''), +(10300, 18, 5686.80, -5012.17, 807.27, 0, ''), +(10300, 19, 5691.43, -5037.43, 807.73, 0, ''), +(10300, 20, 5694.24, -5054.64, 808.85, 0, 'Cavern 3 - EMOTE_CHANT_SPELL'), +(10300, 21, 5686.88, -5012.18, 807.23, 0, ''), +(10300, 22, 5664.94, -5001.12, 807.78, 0, ''), +(10300, 23, 5647.12, -5002.84, 807.54, 0, ''), +(10300, 24, 5629.23, -5014.88, 807.94, 0, ''), +(10300, 25, 5611.26, -5025.62, 808.36, 0, 'Cavern 4 - EMOTE_CHANT_SPELL'), +(10300, 26, 5647.13, -5002.85, 807.57, 0, ''), +(10300, 27, 5641.12, -4973.22, 809.39, 0, ''), +(10300, 28, 5622.97, -4953.58, 811.12, 0, ''), +(10300, 29, 5601.52, -4939.49, 820.77, 0, ''), +(10300, 30, 5571.87, -4936.22, 831.35, 0, ''), +(10300, 31, 5543.23, -4933.67, 838.33, 0, ''), +(10300, 32, 5520.86, -4942.05, 843.02, 0, ''), +(10300, 33, 5509.15, -4946.31, 849.36, 0, ''), +(10300, 34, 5498.45, -4950.08, 849.98, 0, ''), +(10300, 35, 5485.78, -4963.40, 850.43, 0, ''), +(10300, 36, 5467.92, -4980.67, 851.89, 0, 'Cavern 5 - EMOTE_CHANT_SPELL'), +(10300, 37, 5498.68, -4950.45, 849.96, 0, ''), +(10300, 38, 5518.68, -4921.94, 844.65, 0, ''), +(10300, 39, 5517.66, -4920.82, 845.12, 0, 'SAY_REACH_ALTAR_1'), +(10300, 40, 5518.38, -4913.47, 845.57, 0, ''), +(10300, 41, 5511.31, -4913.82, 847.17, 5000, 'light the spotlights'), +(10300, 42, 5511.31, -4913.82, 847.17, 0, 'start altar cinematic - SAY_RANSHALLA_ALTAR_2'), +(10300, 43, 5510.36, -4921.17, 846.33, 0, ''), +(10300, 44, 5517.66, -4920.82, 845.12, 0, 'escort paused'); + +DELETE FROM script_waypoint WHERE entry=4484; +INSERT INTO script_waypoint VALUES +(4484, 0, 3178.57, 188.52, 4.27, 0, 'SAY_QUEST_START'), +(4484, 1, 3189.82, 198.56, 5.62, 0, ''), +(4484, 2, 3215.21, 185.78, 6.43, 0, ''), +(4484, 3, 3224.05, 183.08, 6.74, 0, ''), +(4484, 4, 3228.11, 194.97, 7.51, 0, ''), +(4484, 5, 3225.33, 201.78, 7.25, 0, ''), +(4484, 6, 3233.33, 226.88, 10.18, 0, ''), +(4484, 7, 3274.12, 225.83, 10.72, 0, ''), +(4484, 8, 3321.63, 209.82, 12.36, 0, ''), +(4484, 9, 3369.66, 226.21, 11.69, 0, ''), +(4484, 10, 3402.35, 227.20, 9.48, 0, ''), +(4484, 11, 3441.92, 224.75, 10.85, 0, ''), +(4484, 12, 3453.87, 220.31, 12.52, 0, ''), +(4484, 13, 3472.51, 213.68, 13.26, 0, ''), +(4484, 14, 3515.49, 212.96, 9.76, 5000, 'SAY_FIRST_AMBUSH_START'), +(4484, 15, 3516.21, 212.84, 9.52, 20000, 'SAY_FIRST_AMBUSH_END'), +(4484, 16, 3548.22, 217.12, 7.34, 0, ''), +(4484, 17, 3567.57, 219.43, 5.22, 0, ''), +(4484, 18, 3659.85, 209.68, 2.27, 0, ''), +(4484, 19, 3734.90, 177.64, 6.75, 0, ''), +(4484, 20, 3760.24, 162.51, 7.49, 5000, 'SAY_SECOND_AMBUSH_START'), +(4484, 21, 3761.58, 161.14, 7.37, 20000, 'SAY_SECOND_AMBUSH_END'), +(4484, 22, 3801.17, 129.87, 9.38, 0, ''), +(4484, 23, 3815.53, 118.53, 10.14, 0, ''), +(4484, 24, 3894.58, 44.88, 15.49, 0, ''), +(4484, 25, 3972.83, 0.42, 17.34, 0, ''), +(4484, 26, 4026.41, -7.63, 16.77, 0, ''), +(4484, 27, 4086.24, 12.32, 16.12, 0, ''), +(4484, 28, 4158.79, 50.67, 25.86, 0, ''), +(4484, 29, 4223.48, 99.52, 35.47, 5000, 'SAY_FINAL_AMBUSH_START'), +(4484, 30, 4224.28, 100.02, 35.49, 10000, 'SAY_QUEST_END'), +(4484, 31, 4243.45, 117.44, 38.83, 0, ''), +(4484, 32, 4264.18, 134.22, 42.96, 0, ''); + +DELETE FROM script_waypoint WHERE entry=12277; +INSERT INTO script_waypoint VALUES +(12277, 1, -1154.87, 2708.16, 111.123, 1000, 'SAY_MELIZZA_START'), +(12277, 2, -1162.62, 2712.86, 111.549, 0, ''), +(12277, 3, -1183.37, 2709.45, 111.601, 0, ''), +(12277, 4, -1245.09, 2676.43, 111.572, 0, ''), +(12277, 5, -1260.54, 2672.48, 111.55, 0, ''), +(12277, 6, -1272.71, 2666.38, 111.555, 0, ''), +(12277, 7, -1342.95, 2580.82, 111.557, 0, ''), +(12277, 8, -1362.24, 2561.74, 110.848, 0, ''), +(12277, 9, -1376.56, 2514.06, 95.6146, 0, ''), +(12277, 10, -1379.06, 2510.88, 93.3256, 0, ''), +(12277, 11, -1383.14, 2489.17, 89.009, 0, ''), +(12277, 12, -1395.34, 2426.15, 88.6607, 0, 'SAY_MELIZZA_FINISH'), +(12277, 13, -1366.23, 2317.17, 91.8086, 0, ''), +(12277, 14, -1353.81, 2213.52, 90.726, 0, ''), +(12277, 15, -1354.19, 2208.28, 88.7386, 0, ''), +(12277, 16, -1354.59, 2193.77, 77.6702, 0, ''), +(12277, 17, -1367.62, 2160.64, 67.1482, 0, ''), +(12277, 18, -1379.44, 2132.77, 64.1326, 0, ''), +(12277, 19, -1404.81, 2088.68, 61.8162, 0, 'SAY_MELIZZA_1'), +(12277, 20, -1417.15, 2082.65, 62.4112, 0, ''), +(12277, 21, -1423.28, 2074.19, 62.2046, 0, ''), +(12277, 22, -1432.99, 2070.56, 61.7811, 0, ''), +(12277, 23, -1469.27, 2078.68, 63.1141, 0, ''), +(12277, 24, -1507.21, 2115.12, 62.3578, 0, ''); + +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'); + +DELETE FROM script_waypoint WHERE entry=22424; +INSERT INTO script_waypoint VALUES +(22424, 1, -3620.54, 4164.57, 1.81, 0, 'SKYWING_START'), +(22424, 2, -3624.78, 4149.65, 7.44, 0, ''), +(22424, 3, -3630.30, 4124.84, 21.28, 0, ''), +(22424, 4, -3629.14, 4093.65, 44.35, 0, ''), +(22424, 5, -3626.34, 4080.29, 52.39, 0, ''), +(22424, 6, -3619.35, 4063.86, 60.86, 3000, 'SAY_SKYWING_TREE_DOWN'), +(22424, 7, -3615.09, 4054.17, 62.46, 0, ''), +(22424, 8, -3611.39, 4046.60, 65.07, 0, ''), +(22424, 9, -3606.68, 4040.50, 66.00, 0, ''), +(22424, 10, -3600.88, 4038.69, 67.14, 0, ''), +(22424, 11, -3597.88, 4033.84, 68.53, 0, ''), +(22424, 12, -3602.19, 4027.89, 69.36, 0, ''), +(22424, 13, -3609.85, 4028.37, 70.78, 0, ''), +(22424, 14, -3613.01, 4031.10, 72.14, 0, ''), +(22424, 15, -3613.18, 4035.63, 73.52, 0, ''), +(22424, 16, -3609.84, 4039.73, 75.25, 0, ''), +(22424, 17, -3604.55, 4040.12, 77.01, 0, ''), +(22424, 18, -3600.61, 4036.03, 78.84, 0, ''), +(22424, 19, -3602.63, 4029.99, 81.01, 0, ''), +(22424, 20, -3608.87, 4028.64, 83.27, 0, ''), +(22424, 21, -3612.53, 4032.74, 85.24, 0, ''), +(22424, 22, -3611.08, 4038.13, 87.31, 0, ''), +(22424, 23, -3605.09, 4039.35, 89.55, 0, ''), +(22424, 24, -3601.87, 4035.44, 91.64, 0, ''), +(22424, 25, -3603.08, 4030.58, 93.66, 0, ''), +(22424, 26, -3608.47, 4029.23, 95.91, 0, ''), +(22424, 27, -3611.68, 4033.35, 98.09, 0, ''), +(22424, 28, -3609.51, 4038.25, 100.45, 0, ''), +(22424, 29, -3604.54, 4038.01, 102.72, 0, ''), +(22424, 30, -3602.40, 4033.48, 105.12, 0, ''), +(22424, 31, -3606.17, 4029.69, 107.63, 0, ''), +(22424, 32, -3609.93, 4031.26, 109.53, 0, ''), +(22424, 33, -3609.38, 4035.86, 110.67, 0, ''), +(22424, 34, -3603.58, 4043.03, 112.89, 0, ''), +(22424, 35, -3600.99, 4046.49, 111.81, 0, ''), +(22424, 36, -3602.32, 4051.77, 111.81, 3000, 'SAY_SKYWING_TREE_UP'), +(22424, 37, -3609.55, 4055.95, 112.00, 0, ''), +(22424, 38, -3620.93, 4043.77, 111.99, 0, ''), +(22424, 39, -3622.44, 4038.95, 111.99, 0, ''), +(22424, 40, -3621.64, 4025.39, 111.99, 0, ''), +(22424, 41, -3609.62, 4015.20, 111.99, 0, ''), +(22424, 42, -3598.37, 4017.72, 111.99, 0, ''), +(22424, 43, -3590.21, 4026.62, 111.99, 0, ''), +(22424, 44, -3586.55, 4034.13, 112.00, 0, ''), +(22424, 45, -3580.39, 4033.46, 112.00, 0, ''), +(22424, 46, -3568.83, 4032.53, 107.16, 0, ''), +(22424, 47, -3554.81, 4031.23, 105.31, 0, ''), +(22424, 48, -3544.39, 4030.10, 106.58, 0, ''), +(22424, 49, -3531.91, 4029.25, 111.70, 0, ''), +(22424, 50, -3523.50, 4030.24, 112.47, 0, ''), +(22424, 51, -3517.48, 4037.42, 112.66, 0, ''), +(22424, 52, -3510.40, 4040.77, 112.92, 0, ''), +(22424, 53, -3503.83, 4041.35, 113.17, 0, ''), +(22424, 54, -3498.31, 4040.65, 113.11, 0, ''), +(22424, 55, -3494.05, 4031.67, 113.11, 0, ''), +(22424, 56, -3487.71, 4025.58, 113.12, 0, ''), +(22424, 57, -3500.42, 4012.93, 113.11, 0, ''), +(22424, 58, -3510.86, 4010.15, 113.10, 0, ''), +(22424, 59, -3518.07, 4008.62, 112.97, 0, ''), +(22424, 60, -3524.74, 4014.55, 112.41, 2000, 'SAY_SKYWING_JUMP'), +(22424, 61, -3537.81, 4008.59, 92.53, 0, ''), +(22424, 62, -3546.25, 4008.81, 92.79, 0, ''), +(22424, 63, -3552.07, 4006.48, 92.84, 0, ''), +(22424, 64, -3556.29, 4000.14, 92.92, 0, ''), +(22424, 65, -3556.16, 3991.24, 92.92, 0, ''), +(22424, 66, -3551.48, 3984.28, 92.91, 0, ''), +(22424, 67, -3542.90, 3981.64, 92.91, 0, ''), +(22424, 68, -3534.82, 3983.98, 92.92, 0, ''), +(22424, 69, -3530.58, 3989.91, 92.85, 0, ''), +(22424, 70, -3529.85, 3998.77, 92.59, 0, ''), +(22424, 71, -3534.15, 4008.45, 92.34, 0, ''), +(22424, 72, -3532.87, 4012.97, 91.64, 0, ''), +(22424, 73, -3530.57, 4023.42, 86.82, 0, ''), +(22424, 74, -3528.24, 4033.91, 85.69, 0, ''), +(22424, 75, -3526.22, 4043.75, 87.26, 0, ''), +(22424, 76, -3523.84, 4054.29, 92.42, 0, ''), +(22424, 77, -3522.44, 4059.06, 92.92, 0, ''), +(22424, 78, -3514.26, 4060.72, 92.92, 0, ''), +(22424, 79, -3507.76, 4065.21, 92.92, 0, ''), +(22424, 80, -3503.24, 4076.63, 92.92, 0, 'SAY_SKYWING_SUMMON'), +(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'); -- EOF - diff --git a/sql/Updates/0.0.1/09_BraveWindfeather.sql b/sql/updates/0.0.1/09_BraveWindfeather.sql similarity index 100% rename from sql/Updates/0.0.1/09_BraveWindfeather.sql rename to sql/updates/0.0.1/09_BraveWindfeather.sql diff --git a/sql/Updates/0.0.1/11_SilvaFilnaveth.sql b/sql/updates/0.0.1/11_SilvaFilnaveth.sql similarity index 100% rename from sql/Updates/0.0.1/11_SilvaFilnaveth.sql rename to sql/updates/0.0.1/11_SilvaFilnaveth.sql diff --git a/sql/Updates/0.0.1/27_Vaelastraz.sql b/sql/updates/0.0.1/27_Vaelastraz.sql similarity index 100% rename from sql/Updates/0.0.1/27_Vaelastraz.sql rename to sql/updates/0.0.1/27_Vaelastraz.sql diff --git a/sql/Updates/0.0.2/r104.sql b/sql/updates/0.0.2/r104.sql similarity index 100% rename from sql/Updates/0.0.2/r104.sql rename to sql/updates/0.0.2/r104.sql diff --git a/sql/Updates/0.0.2/r108.sql b/sql/updates/0.0.2/r108.sql similarity index 100% rename from sql/Updates/0.0.2/r108.sql rename to sql/updates/0.0.2/r108.sql diff --git a/sql/Updates/0.0.2/r110.sql b/sql/updates/0.0.2/r110.sql similarity index 100% rename from sql/Updates/0.0.2/r110.sql rename to sql/updates/0.0.2/r110.sql diff --git a/sql/Updates/0.0.2/r121.sql b/sql/updates/0.0.2/r121.sql similarity index 100% rename from sql/Updates/0.0.2/r121.sql rename to sql/updates/0.0.2/r121.sql diff --git a/sql/Updates/0.0.2/r123.sql b/sql/updates/0.0.2/r123.sql similarity index 100% rename from sql/Updates/0.0.2/r123.sql rename to sql/updates/0.0.2/r123.sql diff --git a/sql/Updates/0.0.2/r124.sql b/sql/updates/0.0.2/r124.sql similarity index 100% rename from sql/Updates/0.0.2/r124.sql rename to sql/updates/0.0.2/r124.sql diff --git a/sql/Updates/0.0.2/r125.sql b/sql/updates/0.0.2/r125.sql similarity index 100% rename from sql/Updates/0.0.2/r125.sql rename to sql/updates/0.0.2/r125.sql diff --git a/sql/Updates/0.0.2/r128.sql b/sql/updates/0.0.2/r128.sql similarity index 100% rename from sql/Updates/0.0.2/r128.sql rename to sql/updates/0.0.2/r128.sql diff --git a/sql/Updates/0.0.2/r131.sql b/sql/updates/0.0.2/r131.sql similarity index 100% rename from sql/Updates/0.0.2/r131.sql rename to sql/updates/0.0.2/r131.sql diff --git a/sql/Updates/0.0.2/r134.sql b/sql/updates/0.0.2/r134.sql similarity index 100% rename from sql/Updates/0.0.2/r134.sql rename to sql/updates/0.0.2/r134.sql diff --git a/sql/Updates/0.0.2/r136.sql b/sql/updates/0.0.2/r136.sql similarity index 100% rename from sql/Updates/0.0.2/r136.sql rename to sql/updates/0.0.2/r136.sql diff --git a/sql/Updates/0.0.2/r139.sql b/sql/updates/0.0.2/r139.sql similarity index 100% rename from sql/Updates/0.0.2/r139.sql rename to sql/updates/0.0.2/r139.sql diff --git a/sql/Updates/0.0.2/r142.sql b/sql/updates/0.0.2/r142.sql similarity index 100% rename from sql/Updates/0.0.2/r142.sql rename to sql/updates/0.0.2/r142.sql diff --git a/sql/Updates/0.0.2/r144.sql b/sql/updates/0.0.2/r144.sql similarity index 100% rename from sql/Updates/0.0.2/r144.sql rename to sql/updates/0.0.2/r144.sql diff --git a/sql/Updates/0.0.2/r145.sql b/sql/updates/0.0.2/r145.sql similarity index 100% rename from sql/Updates/0.0.2/r145.sql rename to sql/updates/0.0.2/r145.sql diff --git a/sql/Updates/0.0.2/r149.sql b/sql/updates/0.0.2/r149.sql similarity index 100% rename from sql/Updates/0.0.2/r149.sql rename to sql/updates/0.0.2/r149.sql diff --git a/sql/Updates/0.0.2/r150.sql b/sql/updates/0.0.2/r150.sql similarity index 100% rename from sql/Updates/0.0.2/r150.sql rename to sql/updates/0.0.2/r150.sql diff --git a/sql/Updates/0.0.2/r152.sql b/sql/updates/0.0.2/r152.sql similarity index 100% rename from sql/Updates/0.0.2/r152.sql rename to sql/updates/0.0.2/r152.sql diff --git a/sql/Updates/0.0.2/r153.sql b/sql/updates/0.0.2/r153.sql similarity index 100% rename from sql/Updates/0.0.2/r153.sql rename to sql/updates/0.0.2/r153.sql diff --git a/sql/Updates/0.0.2/r157.sql b/sql/updates/0.0.2/r157.sql similarity index 100% rename from sql/Updates/0.0.2/r157.sql rename to sql/updates/0.0.2/r157.sql diff --git a/sql/Updates/0.0.2/r161.sql b/sql/updates/0.0.2/r161.sql similarity index 100% rename from sql/Updates/0.0.2/r161.sql rename to sql/updates/0.0.2/r161.sql diff --git a/sql/Updates/0.0.2/r163.sql b/sql/updates/0.0.2/r163.sql similarity index 100% rename from sql/Updates/0.0.2/r163.sql rename to sql/updates/0.0.2/r163.sql diff --git a/sql/Updates/0.0.2/r164.sql b/sql/updates/0.0.2/r164.sql similarity index 100% rename from sql/Updates/0.0.2/r164.sql rename to sql/updates/0.0.2/r164.sql diff --git a/sql/Updates/0.0.2/r165.sql b/sql/updates/0.0.2/r165.sql similarity index 100% rename from sql/Updates/0.0.2/r165.sql rename to sql/updates/0.0.2/r165.sql diff --git a/sql/Updates/0.0.2/r169.sql b/sql/updates/0.0.2/r169.sql similarity index 100% rename from sql/Updates/0.0.2/r169.sql rename to sql/updates/0.0.2/r169.sql diff --git a/sql/Updates/0.0.2/r170.sql b/sql/updates/0.0.2/r170.sql similarity index 100% rename from sql/Updates/0.0.2/r170.sql rename to sql/updates/0.0.2/r170.sql diff --git a/sql/Updates/0.0.2/r171.sql b/sql/updates/0.0.2/r171.sql similarity index 100% rename from sql/Updates/0.0.2/r171.sql rename to sql/updates/0.0.2/r171.sql diff --git a/sql/Updates/0.0.2/r172.sql b/sql/updates/0.0.2/r172.sql similarity index 100% rename from sql/Updates/0.0.2/r172.sql rename to sql/updates/0.0.2/r172.sql diff --git a/sql/Updates/0.0.2/r174.sql b/sql/updates/0.0.2/r174.sql similarity index 100% rename from sql/Updates/0.0.2/r174.sql rename to sql/updates/0.0.2/r174.sql diff --git a/sql/Updates/0.0.2/r176.sql b/sql/updates/0.0.2/r176.sql similarity index 100% rename from sql/Updates/0.0.2/r176.sql rename to sql/updates/0.0.2/r176.sql diff --git a/sql/Updates/0.0.2/r177.sql b/sql/updates/0.0.2/r177.sql similarity index 100% rename from sql/Updates/0.0.2/r177.sql rename to sql/updates/0.0.2/r177.sql diff --git a/sql/Updates/0.0.2/r178.sql b/sql/updates/0.0.2/r178.sql similarity index 100% rename from sql/Updates/0.0.2/r178.sql rename to sql/updates/0.0.2/r178.sql diff --git a/sql/Updates/0.0.2/r181.sql b/sql/updates/0.0.2/r181.sql similarity index 100% rename from sql/Updates/0.0.2/r181.sql rename to sql/updates/0.0.2/r181.sql diff --git a/sql/Updates/0.0.2/r182.sql b/sql/updates/0.0.2/r182.sql similarity index 100% rename from sql/Updates/0.0.2/r182.sql rename to sql/updates/0.0.2/r182.sql diff --git a/sql/Updates/0.0.2/r183.sql b/sql/updates/0.0.2/r183.sql similarity index 100% rename from sql/Updates/0.0.2/r183.sql rename to sql/updates/0.0.2/r183.sql diff --git a/sql/Updates/0.0.2/r184.sql b/sql/updates/0.0.2/r184.sql similarity index 100% rename from sql/Updates/0.0.2/r184.sql rename to sql/updates/0.0.2/r184.sql diff --git a/sql/Updates/0.0.2/r186.sql b/sql/updates/0.0.2/r186.sql similarity index 100% rename from sql/Updates/0.0.2/r186.sql rename to sql/updates/0.0.2/r186.sql diff --git a/sql/Updates/0.0.2/r187.sql b/sql/updates/0.0.2/r187.sql similarity index 100% rename from sql/Updates/0.0.2/r187.sql rename to sql/updates/0.0.2/r187.sql diff --git a/sql/Updates/0.0.2/r189.sql b/sql/updates/0.0.2/r189.sql similarity index 100% rename from sql/Updates/0.0.2/r189.sql rename to sql/updates/0.0.2/r189.sql diff --git a/sql/Updates/0.0.2/r191.sql b/sql/updates/0.0.2/r191.sql similarity index 100% rename from sql/Updates/0.0.2/r191.sql rename to sql/updates/0.0.2/r191.sql diff --git a/sql/Updates/0.0.2/r192.sql b/sql/updates/0.0.2/r192.sql similarity index 100% rename from sql/Updates/0.0.2/r192.sql rename to sql/updates/0.0.2/r192.sql diff --git a/sql/Updates/0.0.2/r197.sql b/sql/updates/0.0.2/r197.sql similarity index 100% rename from sql/Updates/0.0.2/r197.sql rename to sql/updates/0.0.2/r197.sql diff --git a/sql/Updates/0.0.2/r204.sql b/sql/updates/0.0.2/r204.sql similarity index 100% rename from sql/Updates/0.0.2/r204.sql rename to sql/updates/0.0.2/r204.sql diff --git a/sql/Updates/0.0.2/r206.sql b/sql/updates/0.0.2/r206.sql similarity index 100% rename from sql/Updates/0.0.2/r206.sql rename to sql/updates/0.0.2/r206.sql diff --git a/sql/Updates/0.0.2/r211.sql b/sql/updates/0.0.2/r211.sql similarity index 100% rename from sql/Updates/0.0.2/r211.sql rename to sql/updates/0.0.2/r211.sql diff --git a/sql/Updates/0.0.2/r213.sql b/sql/updates/0.0.2/r213.sql similarity index 100% rename from sql/Updates/0.0.2/r213.sql rename to sql/updates/0.0.2/r213.sql diff --git a/sql/Updates/0.0.2/r214.sql b/sql/updates/0.0.2/r214.sql similarity index 100% rename from sql/Updates/0.0.2/r214.sql rename to sql/updates/0.0.2/r214.sql diff --git a/sql/Updates/0.0.2/r215.sql b/sql/updates/0.0.2/r215.sql similarity index 100% rename from sql/Updates/0.0.2/r215.sql rename to sql/updates/0.0.2/r215.sql diff --git a/sql/Updates/0.0.2/r218.sql b/sql/updates/0.0.2/r218.sql similarity index 100% rename from sql/Updates/0.0.2/r218.sql rename to sql/updates/0.0.2/r218.sql diff --git a/sql/Updates/0.0.2/r219.sql b/sql/updates/0.0.2/r219.sql similarity index 100% rename from sql/Updates/0.0.2/r219.sql rename to sql/updates/0.0.2/r219.sql diff --git a/sql/Updates/0.0.2/r221_scriptdev2.sql b/sql/updates/0.0.2/r221_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r221_scriptdev2.sql rename to sql/updates/0.0.2/r221_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r227_scriptdev2.sql b/sql/updates/0.0.2/r227_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r227_scriptdev2.sql rename to sql/updates/0.0.2/r227_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r230_mangos.sql b/sql/updates/0.0.2/r230_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r230_mangos.sql rename to sql/updates/0.0.2/r230_mangos.sql diff --git a/sql/Updates/0.0.2/r234_mangos.sql b/sql/updates/0.0.2/r234_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r234_mangos.sql rename to sql/updates/0.0.2/r234_mangos.sql diff --git a/sql/Updates/0.0.2/r237_mangos.sql b/sql/updates/0.0.2/r237_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r237_mangos.sql rename to sql/updates/0.0.2/r237_mangos.sql diff --git a/sql/Updates/0.0.2/r238_mangos.sql b/sql/updates/0.0.2/r238_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r238_mangos.sql rename to sql/updates/0.0.2/r238_mangos.sql diff --git a/sql/Updates/0.0.2/r239_mangos.sql b/sql/updates/0.0.2/r239_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r239_mangos.sql rename to sql/updates/0.0.2/r239_mangos.sql diff --git a/sql/Updates/0.0.2/r240_scriptdev2.sql b/sql/updates/0.0.2/r240_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r240_scriptdev2.sql rename to sql/updates/0.0.2/r240_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r241_mangos.sql b/sql/updates/0.0.2/r241_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r241_mangos.sql rename to sql/updates/0.0.2/r241_mangos.sql diff --git a/sql/Updates/0.0.2/r242_mangos.sql b/sql/updates/0.0.2/r242_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r242_mangos.sql rename to sql/updates/0.0.2/r242_mangos.sql diff --git a/sql/Updates/0.0.2/r243_mangos.sql b/sql/updates/0.0.2/r243_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r243_mangos.sql rename to sql/updates/0.0.2/r243_mangos.sql diff --git a/sql/Updates/0.0.2/r249_mangos.sql b/sql/updates/0.0.2/r249_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r249_mangos.sql rename to sql/updates/0.0.2/r249_mangos.sql diff --git a/sql/Updates/0.0.2/r250_mangos.sql b/sql/updates/0.0.2/r250_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r250_mangos.sql rename to sql/updates/0.0.2/r250_mangos.sql diff --git a/sql/Updates/0.0.2/r253_mangos.sql b/sql/updates/0.0.2/r253_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r253_mangos.sql rename to sql/updates/0.0.2/r253_mangos.sql diff --git a/sql/Updates/0.0.2/r255_mangos.sql b/sql/updates/0.0.2/r255_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r255_mangos.sql rename to sql/updates/0.0.2/r255_mangos.sql diff --git a/sql/Updates/0.0.2/r256_mangos.sql b/sql/updates/0.0.2/r256_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r256_mangos.sql rename to sql/updates/0.0.2/r256_mangos.sql diff --git a/sql/Updates/0.0.2/r257_mangos.sql b/sql/updates/0.0.2/r257_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r257_mangos.sql rename to sql/updates/0.0.2/r257_mangos.sql diff --git a/sql/Updates/0.0.2/r258_mangos.sql b/sql/updates/0.0.2/r258_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r258_mangos.sql rename to sql/updates/0.0.2/r258_mangos.sql diff --git a/sql/Updates/0.0.2/r260_mangos.sql b/sql/updates/0.0.2/r260_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r260_mangos.sql rename to sql/updates/0.0.2/r260_mangos.sql diff --git a/sql/Updates/0.0.2/r261_mangos.sql b/sql/updates/0.0.2/r261_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r261_mangos.sql rename to sql/updates/0.0.2/r261_mangos.sql diff --git a/sql/Updates/0.0.2/r262_mangos.sql b/sql/updates/0.0.2/r262_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r262_mangos.sql rename to sql/updates/0.0.2/r262_mangos.sql diff --git a/sql/Updates/0.0.2/r263_mangos.sql b/sql/updates/0.0.2/r263_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r263_mangos.sql rename to sql/updates/0.0.2/r263_mangos.sql diff --git a/sql/Updates/0.0.2/r264_mangos.sql b/sql/updates/0.0.2/r264_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r264_mangos.sql rename to sql/updates/0.0.2/r264_mangos.sql diff --git a/sql/Updates/0.0.2/r265_mangos.sql b/sql/updates/0.0.2/r265_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r265_mangos.sql rename to sql/updates/0.0.2/r265_mangos.sql diff --git a/sql/Updates/0.0.2/r269_mangos.sql b/sql/updates/0.0.2/r269_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r269_mangos.sql rename to sql/updates/0.0.2/r269_mangos.sql diff --git a/sql/Updates/0.0.2/r270_mangos.sql b/sql/updates/0.0.2/r270_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r270_mangos.sql rename to sql/updates/0.0.2/r270_mangos.sql diff --git a/sql/Updates/0.0.2/r271_mangos.sql b/sql/updates/0.0.2/r271_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r271_mangos.sql rename to sql/updates/0.0.2/r271_mangos.sql diff --git a/sql/Updates/0.0.2/r272_mangos.sql b/sql/updates/0.0.2/r272_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r272_mangos.sql rename to sql/updates/0.0.2/r272_mangos.sql diff --git a/sql/Updates/0.0.2/r273_mangos.sql b/sql/updates/0.0.2/r273_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r273_mangos.sql rename to sql/updates/0.0.2/r273_mangos.sql diff --git a/sql/Updates/0.0.2/r274_mangos.sql b/sql/updates/0.0.2/r274_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r274_mangos.sql rename to sql/updates/0.0.2/r274_mangos.sql diff --git a/sql/Updates/0.0.2/r275_mangos.sql b/sql/updates/0.0.2/r275_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r275_mangos.sql rename to sql/updates/0.0.2/r275_mangos.sql diff --git a/sql/Updates/0.0.2/r281_scriptdev2.sql b/sql/updates/0.0.2/r281_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r281_scriptdev2.sql rename to sql/updates/0.0.2/r281_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r282_mangos.sql b/sql/updates/0.0.2/r282_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r282_mangos.sql rename to sql/updates/0.0.2/r282_mangos.sql diff --git a/sql/Updates/0.0.2/r286_mangos.sql b/sql/updates/0.0.2/r286_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r286_mangos.sql rename to sql/updates/0.0.2/r286_mangos.sql diff --git a/sql/Updates/0.0.2/r289_mangos.sql b/sql/updates/0.0.2/r289_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r289_mangos.sql rename to sql/updates/0.0.2/r289_mangos.sql diff --git a/sql/Updates/0.0.2/r291_mangos.sql b/sql/updates/0.0.2/r291_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r291_mangos.sql rename to sql/updates/0.0.2/r291_mangos.sql diff --git a/sql/Updates/0.0.2/r295_mangos.sql b/sql/updates/0.0.2/r295_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r295_mangos.sql rename to sql/updates/0.0.2/r295_mangos.sql diff --git a/sql/Updates/0.0.2/r297_mangos.sql b/sql/updates/0.0.2/r297_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r297_mangos.sql rename to sql/updates/0.0.2/r297_mangos.sql diff --git a/sql/Updates/0.0.2/r298_scriptdev2.sql b/sql/updates/0.0.2/r298_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r298_scriptdev2.sql rename to sql/updates/0.0.2/r298_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r299_scriptdev2.sql b/sql/updates/0.0.2/r299_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r299_scriptdev2.sql rename to sql/updates/0.0.2/r299_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r304_mangos.sql b/sql/updates/0.0.2/r304_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r304_mangos.sql rename to sql/updates/0.0.2/r304_mangos.sql diff --git a/sql/Updates/0.0.2/r306_scriptdev2.sql b/sql/updates/0.0.2/r306_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r306_scriptdev2.sql rename to sql/updates/0.0.2/r306_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r307_mangos.sql b/sql/updates/0.0.2/r307_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r307_mangos.sql rename to sql/updates/0.0.2/r307_mangos.sql diff --git a/sql/Updates/0.0.2/r308_mangos.sql b/sql/updates/0.0.2/r308_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r308_mangos.sql rename to sql/updates/0.0.2/r308_mangos.sql diff --git a/sql/Updates/0.0.2/r309_mangos.sql b/sql/updates/0.0.2/r309_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r309_mangos.sql rename to sql/updates/0.0.2/r309_mangos.sql diff --git a/sql/Updates/0.0.2/r311_mangos.sql b/sql/updates/0.0.2/r311_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r311_mangos.sql rename to sql/updates/0.0.2/r311_mangos.sql diff --git a/sql/Updates/0.0.2/r312_mangos.sql b/sql/updates/0.0.2/r312_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r312_mangos.sql rename to sql/updates/0.0.2/r312_mangos.sql diff --git a/sql/Updates/0.0.2/r318_mangos.sql b/sql/updates/0.0.2/r318_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r318_mangos.sql rename to sql/updates/0.0.2/r318_mangos.sql diff --git a/sql/Updates/0.0.2/r324_mangos.sql b/sql/updates/0.0.2/r324_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r324_mangos.sql rename to sql/updates/0.0.2/r324_mangos.sql diff --git a/sql/Updates/0.0.2/r327_mangos.sql b/sql/updates/0.0.2/r327_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r327_mangos.sql rename to sql/updates/0.0.2/r327_mangos.sql diff --git a/sql/Updates/0.0.2/r332_scriptdev2.sql b/sql/updates/0.0.2/r332_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r332_scriptdev2.sql rename to sql/updates/0.0.2/r332_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r333_mangos.sql b/sql/updates/0.0.2/r333_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r333_mangos.sql rename to sql/updates/0.0.2/r333_mangos.sql diff --git a/sql/Updates/0.0.2/r334_mangos.sql b/sql/updates/0.0.2/r334_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r334_mangos.sql rename to sql/updates/0.0.2/r334_mangos.sql diff --git a/sql/Updates/0.0.2/r336_mangos.sql b/sql/updates/0.0.2/r336_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r336_mangos.sql rename to sql/updates/0.0.2/r336_mangos.sql diff --git a/sql/Updates/0.0.2/r352_mangos.sql b/sql/updates/0.0.2/r352_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r352_mangos.sql rename to sql/updates/0.0.2/r352_mangos.sql diff --git a/sql/Updates/0.0.2/r355_mangos.sql b/sql/updates/0.0.2/r355_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r355_mangos.sql rename to sql/updates/0.0.2/r355_mangos.sql diff --git a/sql/Updates/0.0.2/r358_mangos.sql b/sql/updates/0.0.2/r358_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r358_mangos.sql rename to sql/updates/0.0.2/r358_mangos.sql diff --git a/sql/Updates/0.0.2/r364_mangos.sql b/sql/updates/0.0.2/r364_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r364_mangos.sql rename to sql/updates/0.0.2/r364_mangos.sql diff --git a/sql/Updates/0.0.2/r367_mangos.sql b/sql/updates/0.0.2/r367_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r367_mangos.sql rename to sql/updates/0.0.2/r367_mangos.sql diff --git a/sql/Updates/0.0.2/r368_mangos.sql b/sql/updates/0.0.2/r368_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r368_mangos.sql rename to sql/updates/0.0.2/r368_mangos.sql diff --git a/sql/Updates/0.0.2/r369_mangos.sql b/sql/updates/0.0.2/r369_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r369_mangos.sql rename to sql/updates/0.0.2/r369_mangos.sql diff --git a/sql/Updates/0.0.2/r374_mangos.sql b/sql/updates/0.0.2/r374_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r374_mangos.sql rename to sql/updates/0.0.2/r374_mangos.sql diff --git a/sql/Updates/0.0.2/r386_mangos.sql b/sql/updates/0.0.2/r386_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r386_mangos.sql rename to sql/updates/0.0.2/r386_mangos.sql diff --git a/sql/Updates/0.0.2/r417_mangos.sql b/sql/updates/0.0.2/r417_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r417_mangos.sql rename to sql/updates/0.0.2/r417_mangos.sql diff --git a/sql/Updates/0.0.2/r428_mangos.sql b/sql/updates/0.0.2/r428_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r428_mangos.sql rename to sql/updates/0.0.2/r428_mangos.sql diff --git a/sql/Updates/0.0.2/r431_mangos.sql b/sql/updates/0.0.2/r431_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r431_mangos.sql rename to sql/updates/0.0.2/r431_mangos.sql diff --git a/sql/Updates/0.0.2/r444_mangos.sql b/sql/updates/0.0.2/r444_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r444_mangos.sql rename to sql/updates/0.0.2/r444_mangos.sql diff --git a/sql/Updates/0.0.2/r445_mangos.sql b/sql/updates/0.0.2/r445_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r445_mangos.sql rename to sql/updates/0.0.2/r445_mangos.sql diff --git a/sql/Updates/0.0.2/r446_mangos.sql b/sql/updates/0.0.2/r446_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r446_mangos.sql rename to sql/updates/0.0.2/r446_mangos.sql diff --git a/sql/Updates/0.0.2/r448_scriptdev2.sql b/sql/updates/0.0.2/r448_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r448_scriptdev2.sql rename to sql/updates/0.0.2/r448_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r462_mangos.sql b/sql/updates/0.0.2/r462_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r462_mangos.sql rename to sql/updates/0.0.2/r462_mangos.sql diff --git a/sql/Updates/0.0.2/r465_mangos.sql b/sql/updates/0.0.2/r465_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r465_mangos.sql rename to sql/updates/0.0.2/r465_mangos.sql diff --git a/sql/Updates/0.0.2/r467_mangos.sql b/sql/updates/0.0.2/r467_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r467_mangos.sql rename to sql/updates/0.0.2/r467_mangos.sql diff --git a/sql/Updates/0.0.2/r473_mangos.sql b/sql/updates/0.0.2/r473_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r473_mangos.sql rename to sql/updates/0.0.2/r473_mangos.sql diff --git a/sql/Updates/0.0.2/r476_mangos.sql b/sql/updates/0.0.2/r476_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r476_mangos.sql rename to sql/updates/0.0.2/r476_mangos.sql diff --git a/sql/Updates/0.0.2/r477_mangos.sql b/sql/updates/0.0.2/r477_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r477_mangos.sql rename to sql/updates/0.0.2/r477_mangos.sql diff --git a/sql/Updates/0.0.2/r479_mangos.sql b/sql/updates/0.0.2/r479_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r479_mangos.sql rename to sql/updates/0.0.2/r479_mangos.sql diff --git a/sql/Updates/0.0.2/r482_mangos.sql b/sql/updates/0.0.2/r482_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r482_mangos.sql rename to sql/updates/0.0.2/r482_mangos.sql diff --git a/sql/Updates/0.0.2/r484_mangos.sql b/sql/updates/0.0.2/r484_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r484_mangos.sql rename to sql/updates/0.0.2/r484_mangos.sql diff --git a/sql/Updates/0.0.2/r486_mangos.sql b/sql/updates/0.0.2/r486_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r486_mangos.sql rename to sql/updates/0.0.2/r486_mangos.sql diff --git a/sql/Updates/0.0.2/r487_mangos.sql b/sql/updates/0.0.2/r487_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r487_mangos.sql rename to sql/updates/0.0.2/r487_mangos.sql diff --git a/sql/Updates/0.0.2/r494_mangos.sql b/sql/updates/0.0.2/r494_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r494_mangos.sql rename to sql/updates/0.0.2/r494_mangos.sql diff --git a/sql/Updates/0.0.2/r501_mangos.sql b/sql/updates/0.0.2/r501_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r501_mangos.sql rename to sql/updates/0.0.2/r501_mangos.sql diff --git a/sql/Updates/0.0.2/r513_mangos.sql b/sql/updates/0.0.2/r513_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r513_mangos.sql rename to sql/updates/0.0.2/r513_mangos.sql diff --git a/sql/Updates/0.0.2/r514_mangos.sql b/sql/updates/0.0.2/r514_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r514_mangos.sql rename to sql/updates/0.0.2/r514_mangos.sql diff --git a/sql/Updates/0.0.2/r515_mangos.sql b/sql/updates/0.0.2/r515_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r515_mangos.sql rename to sql/updates/0.0.2/r515_mangos.sql diff --git a/sql/Updates/0.0.2/r516_mangos.sql b/sql/updates/0.0.2/r516_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r516_mangos.sql rename to sql/updates/0.0.2/r516_mangos.sql diff --git a/sql/Updates/0.0.2/r517_mangos.sql b/sql/updates/0.0.2/r517_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r517_mangos.sql rename to sql/updates/0.0.2/r517_mangos.sql diff --git a/sql/Updates/0.0.2/r518_mangos.sql b/sql/updates/0.0.2/r518_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r518_mangos.sql rename to sql/updates/0.0.2/r518_mangos.sql diff --git a/sql/Updates/0.0.2/r519_mangos.sql b/sql/updates/0.0.2/r519_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r519_mangos.sql rename to sql/updates/0.0.2/r519_mangos.sql diff --git a/sql/Updates/0.0.2/r520_mangos.sql b/sql/updates/0.0.2/r520_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r520_mangos.sql rename to sql/updates/0.0.2/r520_mangos.sql diff --git a/sql/Updates/0.0.2/r521_mangos.sql b/sql/updates/0.0.2/r521_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r521_mangos.sql rename to sql/updates/0.0.2/r521_mangos.sql diff --git a/sql/Updates/0.0.2/r522_mangos.sql b/sql/updates/0.0.2/r522_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r522_mangos.sql rename to sql/updates/0.0.2/r522_mangos.sql diff --git a/sql/Updates/0.0.2/r526_mangos.sql b/sql/updates/0.0.2/r526_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r526_mangos.sql rename to sql/updates/0.0.2/r526_mangos.sql diff --git a/sql/Updates/0.0.2/r528_mangos.sql b/sql/updates/0.0.2/r528_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r528_mangos.sql rename to sql/updates/0.0.2/r528_mangos.sql diff --git a/sql/Updates/0.0.2/r533_mangos.sql b/sql/updates/0.0.2/r533_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r533_mangos.sql rename to sql/updates/0.0.2/r533_mangos.sql diff --git a/sql/Updates/0.0.2/r538_scriptdev2.sql b/sql/updates/0.0.2/r538_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r538_scriptdev2.sql rename to sql/updates/0.0.2/r538_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r547_mangos.sql b/sql/updates/0.0.2/r547_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r547_mangos.sql rename to sql/updates/0.0.2/r547_mangos.sql diff --git a/sql/Updates/0.0.2/r554_mangos.sql b/sql/updates/0.0.2/r554_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r554_mangos.sql rename to sql/updates/0.0.2/r554_mangos.sql diff --git a/sql/Updates/0.0.2/r555_mangos.sql b/sql/updates/0.0.2/r555_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r555_mangos.sql rename to sql/updates/0.0.2/r555_mangos.sql diff --git a/sql/Updates/0.0.2/r56.sql b/sql/updates/0.0.2/r56.sql similarity index 100% rename from sql/Updates/0.0.2/r56.sql rename to sql/updates/0.0.2/r56.sql diff --git a/sql/Updates/0.0.2/r575_mangos.sql b/sql/updates/0.0.2/r575_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r575_mangos.sql rename to sql/updates/0.0.2/r575_mangos.sql diff --git a/sql/Updates/0.0.2/r576_mangos.sql b/sql/updates/0.0.2/r576_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r576_mangos.sql rename to sql/updates/0.0.2/r576_mangos.sql diff --git a/sql/Updates/0.0.2/r578_mangos.sql b/sql/updates/0.0.2/r578_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r578_mangos.sql rename to sql/updates/0.0.2/r578_mangos.sql diff --git a/sql/Updates/0.0.2/r584_mangos.sql b/sql/updates/0.0.2/r584_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r584_mangos.sql rename to sql/updates/0.0.2/r584_mangos.sql diff --git a/sql/Updates/0.0.2/r59.sql b/sql/updates/0.0.2/r59.sql similarity index 100% rename from sql/Updates/0.0.2/r59.sql rename to sql/updates/0.0.2/r59.sql diff --git a/sql/Updates/0.0.2/r590_mangos.sql b/sql/updates/0.0.2/r590_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r590_mangos.sql rename to sql/updates/0.0.2/r590_mangos.sql diff --git a/sql/Updates/0.0.2/r591_mangos.sql b/sql/updates/0.0.2/r591_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r591_mangos.sql rename to sql/updates/0.0.2/r591_mangos.sql diff --git a/sql/Updates/0.0.2/r593_mangos.sql b/sql/updates/0.0.2/r593_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r593_mangos.sql rename to sql/updates/0.0.2/r593_mangos.sql diff --git a/sql/Updates/0.0.2/r594_mangos.sql b/sql/updates/0.0.2/r594_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r594_mangos.sql rename to sql/updates/0.0.2/r594_mangos.sql diff --git a/sql/Updates/0.0.2/r596_mangos.sql b/sql/updates/0.0.2/r596_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r596_mangos.sql rename to sql/updates/0.0.2/r596_mangos.sql diff --git a/sql/Updates/0.0.2/r610_mangos.sql b/sql/updates/0.0.2/r610_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r610_mangos.sql rename to sql/updates/0.0.2/r610_mangos.sql diff --git a/sql/Updates/0.0.2/r615_scriptdev2.sql b/sql/updates/0.0.2/r615_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r615_scriptdev2.sql rename to sql/updates/0.0.2/r615_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r617_mangos.sql b/sql/updates/0.0.2/r617_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r617_mangos.sql rename to sql/updates/0.0.2/r617_mangos.sql diff --git a/sql/Updates/0.0.2/r621_mangos.sql b/sql/updates/0.0.2/r621_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r621_mangos.sql rename to sql/updates/0.0.2/r621_mangos.sql diff --git a/sql/Updates/0.0.2/r628_mangos.sql b/sql/updates/0.0.2/r628_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r628_mangos.sql rename to sql/updates/0.0.2/r628_mangos.sql diff --git a/sql/Updates/0.0.2/r63.sql b/sql/updates/0.0.2/r63.sql similarity index 100% rename from sql/Updates/0.0.2/r63.sql rename to sql/updates/0.0.2/r63.sql diff --git a/sql/Updates/0.0.2/r632_mangos.sql b/sql/updates/0.0.2/r632_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r632_mangos.sql rename to sql/updates/0.0.2/r632_mangos.sql diff --git a/sql/Updates/0.0.2/r633_mangos.sql b/sql/updates/0.0.2/r633_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r633_mangos.sql rename to sql/updates/0.0.2/r633_mangos.sql diff --git a/sql/Updates/0.0.2/r634_scriptdev2.sql b/sql/updates/0.0.2/r634_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r634_scriptdev2.sql rename to sql/updates/0.0.2/r634_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r636_mangos.sql b/sql/updates/0.0.2/r636_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r636_mangos.sql rename to sql/updates/0.0.2/r636_mangos.sql diff --git a/sql/Updates/0.0.2/r637_mangos.sql b/sql/updates/0.0.2/r637_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r637_mangos.sql rename to sql/updates/0.0.2/r637_mangos.sql diff --git a/sql/Updates/0.0.2/r638_mangos.sql b/sql/updates/0.0.2/r638_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r638_mangos.sql rename to sql/updates/0.0.2/r638_mangos.sql diff --git a/sql/Updates/0.0.2/r639_mangos.sql b/sql/updates/0.0.2/r639_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r639_mangos.sql rename to sql/updates/0.0.2/r639_mangos.sql diff --git a/sql/Updates/0.0.2/r642_mangos.sql b/sql/updates/0.0.2/r642_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r642_mangos.sql rename to sql/updates/0.0.2/r642_mangos.sql diff --git a/sql/Updates/0.0.2/r643_mangos.sql b/sql/updates/0.0.2/r643_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r643_mangos.sql rename to sql/updates/0.0.2/r643_mangos.sql diff --git a/sql/Updates/0.0.2/r646_mangos.sql b/sql/updates/0.0.2/r646_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r646_mangos.sql rename to sql/updates/0.0.2/r646_mangos.sql diff --git a/sql/Updates/0.0.2/r647_scriptdev2.sql b/sql/updates/0.0.2/r647_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r647_scriptdev2.sql rename to sql/updates/0.0.2/r647_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r65.sql b/sql/updates/0.0.2/r65.sql similarity index 100% rename from sql/Updates/0.0.2/r65.sql rename to sql/updates/0.0.2/r65.sql diff --git a/sql/Updates/0.0.2/r656_scriptdev2.sql b/sql/updates/0.0.2/r656_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r656_scriptdev2.sql rename to sql/updates/0.0.2/r656_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r658_mangos.sql b/sql/updates/0.0.2/r658_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r658_mangos.sql rename to sql/updates/0.0.2/r658_mangos.sql diff --git a/sql/Updates/0.0.2/r659_mangos.sql b/sql/updates/0.0.2/r659_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r659_mangos.sql rename to sql/updates/0.0.2/r659_mangos.sql diff --git a/sql/Updates/0.0.2/r681_scriptdev2.sql b/sql/updates/0.0.2/r681_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r681_scriptdev2.sql rename to sql/updates/0.0.2/r681_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r695_scriptdev2.sql b/sql/updates/0.0.2/r695_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.2/r695_scriptdev2.sql rename to sql/updates/0.0.2/r695_scriptdev2.sql diff --git a/sql/Updates/0.0.2/r699_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r699_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r699_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r699_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r700_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r700_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r700_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r700_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r701_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r701_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r701_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r701_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r702_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r702_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r702_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r702_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r703_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r703_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r703_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r703_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r704_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r704_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r704_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r704_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r705_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r705_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r705_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r705_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r706_mangos.sql b/sql/updates/0.0.2/r706_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r706_mangos.sql rename to sql/updates/0.0.2/r706_mangos.sql diff --git a/sql/Updates/0.0.2/r707_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r707_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r707_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r707_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r709_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r709_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r709_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r709_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r710_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r710_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r710_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r710_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r713_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r713_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r713_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r713_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r715_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r715_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r715_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r715_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r72.sql b/sql/updates/0.0.2/r72.sql similarity index 100% rename from sql/Updates/0.0.2/r72.sql rename to sql/updates/0.0.2/r72.sql diff --git a/sql/Updates/0.0.2/r725_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r725_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r725_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r725_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r726_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r726_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r726_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r726_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r727_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r727_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r727_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r727_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r728_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r728_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r728_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r728_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r729_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r729_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r729_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r729_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r730_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r730_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r730_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r730_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r732_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r732_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r732_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r732_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r735_mangos.sql b/sql/updates/0.0.2/r735_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r735_mangos.sql rename to sql/updates/0.0.2/r735_mangos.sql diff --git a/sql/Updates/0.0.2/r735_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r735_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r735_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r735_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r740_mangos.sql b/sql/updates/0.0.2/r740_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r740_mangos.sql rename to sql/updates/0.0.2/r740_mangos.sql diff --git a/sql/Updates/0.0.2/r740_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r740_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r740_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r740_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r743_mangos.sql b/sql/updates/0.0.2/r743_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r743_mangos.sql rename to sql/updates/0.0.2/r743_mangos.sql diff --git a/sql/Updates/0.0.2/r743_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r743_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r743_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r743_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r745_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r745_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r745_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r745_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r747_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r747_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r747_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r747_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r751_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r751_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r751_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r751_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r755_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r755_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r755_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r755_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r757_mangos.sql b/sql/updates/0.0.2/r757_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r757_mangos.sql rename to sql/updates/0.0.2/r757_mangos.sql diff --git a/sql/Updates/0.0.2/r757_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r757_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r757_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r757_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r764_mangos.sql b/sql/updates/0.0.2/r764_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r764_mangos.sql rename to sql/updates/0.0.2/r764_mangos.sql diff --git a/sql/Updates/0.0.2/r764_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r764_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r764_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r764_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r766_mangos.sql b/sql/updates/0.0.2/r766_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r766_mangos.sql rename to sql/updates/0.0.2/r766_mangos.sql diff --git a/sql/Updates/0.0.2/r766_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r766_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r766_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r766_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r767_mangos.sql b/sql/updates/0.0.2/r767_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r767_mangos.sql rename to sql/updates/0.0.2/r767_mangos.sql diff --git a/sql/Updates/0.0.2/r768_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r768_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r768_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r768_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r769_mangos.sql b/sql/updates/0.0.2/r769_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r769_mangos.sql rename to sql/updates/0.0.2/r769_mangos.sql diff --git a/sql/Updates/0.0.2/r771_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r771_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r771_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r771_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r772_mangos.sql b/sql/updates/0.0.2/r772_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r772_mangos.sql rename to sql/updates/0.0.2/r772_mangos.sql diff --git a/sql/Updates/0.0.2/r777_mangos.sql b/sql/updates/0.0.2/r777_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r777_mangos.sql rename to sql/updates/0.0.2/r777_mangos.sql diff --git a/sql/Updates/0.0.2/r778_mangos.sql b/sql/updates/0.0.2/r778_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r778_mangos.sql rename to sql/updates/0.0.2/r778_mangos.sql diff --git a/sql/Updates/0.0.2/r779_mangos.sql b/sql/updates/0.0.2/r779_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r779_mangos.sql rename to sql/updates/0.0.2/r779_mangos.sql diff --git a/sql/Updates/0.0.2/r779_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r779_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r779_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r779_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r78.sql b/sql/updates/0.0.2/r78.sql similarity index 100% rename from sql/Updates/0.0.2/r78.sql rename to sql/updates/0.0.2/r78.sql diff --git a/sql/Updates/0.0.2/r782_mangos.sql b/sql/updates/0.0.2/r782_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r782_mangos.sql rename to sql/updates/0.0.2/r782_mangos.sql diff --git a/sql/Updates/0.0.2/r783_mangos.sql b/sql/updates/0.0.2/r783_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r783_mangos.sql rename to sql/updates/0.0.2/r783_mangos.sql diff --git a/sql/Updates/0.0.2/r783_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r783_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r783_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r783_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r790_mangos.sql b/sql/updates/0.0.2/r790_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r790_mangos.sql rename to sql/updates/0.0.2/r790_mangos.sql diff --git a/sql/Updates/0.0.2/r794_mangos.sql b/sql/updates/0.0.2/r794_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r794_mangos.sql rename to sql/updates/0.0.2/r794_mangos.sql diff --git a/sql/Updates/0.0.2/r796_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r796_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r796_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r796_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r802_mangos.sql b/sql/updates/0.0.2/r802_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r802_mangos.sql rename to sql/updates/0.0.2/r802_mangos.sql diff --git a/sql/Updates/0.0.2/r804_mangos.sql b/sql/updates/0.0.2/r804_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r804_mangos.sql rename to sql/updates/0.0.2/r804_mangos.sql diff --git a/sql/Updates/0.0.2/r804_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r804_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r804_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r804_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r809_mangos.sql b/sql/updates/0.0.2/r809_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r809_mangos.sql rename to sql/updates/0.0.2/r809_mangos.sql diff --git a/sql/Updates/0.0.2/r809_scriptdev2_script_texts.sql b/sql/updates/0.0.2/r809_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.2/r809_scriptdev2_script_texts.sql rename to sql/updates/0.0.2/r809_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.2/r81.sql b/sql/updates/0.0.2/r81.sql similarity index 100% rename from sql/Updates/0.0.2/r81.sql rename to sql/updates/0.0.2/r81.sql diff --git a/sql/Updates/0.0.2/r810_mangos.sql b/sql/updates/0.0.2/r810_mangos.sql similarity index 100% rename from sql/Updates/0.0.2/r810_mangos.sql rename to sql/updates/0.0.2/r810_mangos.sql diff --git a/sql/Updates/0.0.2/r91.sql b/sql/updates/0.0.2/r91.sql similarity index 100% rename from sql/Updates/0.0.2/r91.sql rename to sql/updates/0.0.2/r91.sql diff --git a/sql/Updates/0.0.2/r92.sql b/sql/updates/0.0.2/r92.sql similarity index 100% rename from sql/Updates/0.0.2/r92.sql rename to sql/updates/0.0.2/r92.sql diff --git a/sql/Updates/0.0.2/r97.sql b/sql/updates/0.0.2/r97.sql similarity index 100% rename from sql/Updates/0.0.2/r97.sql rename to sql/updates/0.0.2/r97.sql diff --git a/sql/Updates/0.0.3/r1002_scriptdev2.sql b/sql/updates/0.0.3/r1002_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1002_scriptdev2.sql rename to sql/updates/0.0.3/r1002_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1006_scriptdev2.sql b/sql/updates/0.0.3/r1006_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1006_scriptdev2.sql rename to sql/updates/0.0.3/r1006_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1008_mangos.sql b/sql/updates/0.0.3/r1008_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1008_mangos.sql rename to sql/updates/0.0.3/r1008_mangos.sql diff --git a/sql/Updates/0.0.3/r1008_scriptdev2.sql b/sql/updates/0.0.3/r1008_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1008_scriptdev2.sql rename to sql/updates/0.0.3/r1008_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1009_scriptdev2.sql b/sql/updates/0.0.3/r1009_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1009_scriptdev2.sql rename to sql/updates/0.0.3/r1009_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1010_mangos.sql b/sql/updates/0.0.3/r1010_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1010_mangos.sql rename to sql/updates/0.0.3/r1010_mangos.sql diff --git a/sql/Updates/0.0.3/r1010_scriptdev2.sql b/sql/updates/0.0.3/r1010_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1010_scriptdev2.sql rename to sql/updates/0.0.3/r1010_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1012_mangos.sql b/sql/updates/0.0.3/r1012_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1012_mangos.sql rename to sql/updates/0.0.3/r1012_mangos.sql diff --git a/sql/Updates/0.0.3/r1012_scriptdev2.sql b/sql/updates/0.0.3/r1012_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1012_scriptdev2.sql rename to sql/updates/0.0.3/r1012_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1014_mangos.sql b/sql/updates/0.0.3/r1014_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1014_mangos.sql rename to sql/updates/0.0.3/r1014_mangos.sql diff --git a/sql/Updates/0.0.3/r1014_scriptdev2.sql b/sql/updates/0.0.3/r1014_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1014_scriptdev2.sql rename to sql/updates/0.0.3/r1014_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1016_scriptdev2.sql b/sql/updates/0.0.3/r1016_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1016_scriptdev2.sql rename to sql/updates/0.0.3/r1016_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1023_scriptdev2.sql b/sql/updates/0.0.3/r1023_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1023_scriptdev2.sql rename to sql/updates/0.0.3/r1023_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1025_mangos.sql b/sql/updates/0.0.3/r1025_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1025_mangos.sql rename to sql/updates/0.0.3/r1025_mangos.sql diff --git a/sql/Updates/0.0.3/r1030_scriptdev2.sql b/sql/updates/0.0.3/r1030_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1030_scriptdev2.sql rename to sql/updates/0.0.3/r1030_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1032_mangos.sql b/sql/updates/0.0.3/r1032_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1032_mangos.sql rename to sql/updates/0.0.3/r1032_mangos.sql diff --git a/sql/Updates/0.0.3/r1032_scriptdev2.sql b/sql/updates/0.0.3/r1032_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1032_scriptdev2.sql rename to sql/updates/0.0.3/r1032_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1039_mangos.sql b/sql/updates/0.0.3/r1039_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1039_mangos.sql rename to sql/updates/0.0.3/r1039_mangos.sql diff --git a/sql/Updates/0.0.3/r1056_scriptdev2.sql b/sql/updates/0.0.3/r1056_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1056_scriptdev2.sql rename to sql/updates/0.0.3/r1056_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1058_mangos.sql b/sql/updates/0.0.3/r1058_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1058_mangos.sql rename to sql/updates/0.0.3/r1058_mangos.sql diff --git a/sql/Updates/0.0.3/r1058_scriptdev2.sql b/sql/updates/0.0.3/r1058_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1058_scriptdev2.sql rename to sql/updates/0.0.3/r1058_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1062_mangos.sql b/sql/updates/0.0.3/r1062_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1062_mangos.sql rename to sql/updates/0.0.3/r1062_mangos.sql diff --git a/sql/Updates/0.0.3/r1067_mangos.sql b/sql/updates/0.0.3/r1067_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1067_mangos.sql rename to sql/updates/0.0.3/r1067_mangos.sql diff --git a/sql/Updates/0.0.3/r1068_mangos.sql b/sql/updates/0.0.3/r1068_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1068_mangos.sql rename to sql/updates/0.0.3/r1068_mangos.sql diff --git a/sql/Updates/0.0.3/r1068_scriptdev2.sql b/sql/updates/0.0.3/r1068_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1068_scriptdev2.sql rename to sql/updates/0.0.3/r1068_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1069_mangos.sql b/sql/updates/0.0.3/r1069_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1069_mangos.sql rename to sql/updates/0.0.3/r1069_mangos.sql diff --git a/sql/Updates/0.0.3/r1073_mangos.sql b/sql/updates/0.0.3/r1073_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1073_mangos.sql rename to sql/updates/0.0.3/r1073_mangos.sql diff --git a/sql/Updates/0.0.3/r1074_scriptdev2.sql b/sql/updates/0.0.3/r1074_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1074_scriptdev2.sql rename to sql/updates/0.0.3/r1074_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1075_mangos.sql b/sql/updates/0.0.3/r1075_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1075_mangos.sql rename to sql/updates/0.0.3/r1075_mangos.sql diff --git a/sql/Updates/0.0.3/r1080_scriptdev2.sql b/sql/updates/0.0.3/r1080_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1080_scriptdev2.sql rename to sql/updates/0.0.3/r1080_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1082_mangos.sql b/sql/updates/0.0.3/r1082_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1082_mangos.sql rename to sql/updates/0.0.3/r1082_mangos.sql diff --git a/sql/Updates/0.0.3/r1098_scriptdev2.sql b/sql/updates/0.0.3/r1098_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1098_scriptdev2.sql rename to sql/updates/0.0.3/r1098_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1099_mangos.sql b/sql/updates/0.0.3/r1099_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1099_mangos.sql rename to sql/updates/0.0.3/r1099_mangos.sql diff --git a/sql/Updates/0.0.3/r1100_mangos.sql b/sql/updates/0.0.3/r1100_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1100_mangos.sql rename to sql/updates/0.0.3/r1100_mangos.sql diff --git a/sql/Updates/0.0.3/r1103_mangos.sql b/sql/updates/0.0.3/r1103_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1103_mangos.sql rename to sql/updates/0.0.3/r1103_mangos.sql diff --git a/sql/Updates/0.0.3/r1104_scriptdev2.sql b/sql/updates/0.0.3/r1104_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1104_scriptdev2.sql rename to sql/updates/0.0.3/r1104_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1106_mangos.sql b/sql/updates/0.0.3/r1106_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1106_mangos.sql rename to sql/updates/0.0.3/r1106_mangos.sql diff --git a/sql/Updates/0.0.3/r1112_mangos.sql b/sql/updates/0.0.3/r1112_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1112_mangos.sql rename to sql/updates/0.0.3/r1112_mangos.sql diff --git a/sql/Updates/0.0.3/r1116_mangos.sql b/sql/updates/0.0.3/r1116_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1116_mangos.sql rename to sql/updates/0.0.3/r1116_mangos.sql diff --git a/sql/Updates/0.0.3/r1119_mangos.sql b/sql/updates/0.0.3/r1119_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1119_mangos.sql rename to sql/updates/0.0.3/r1119_mangos.sql diff --git a/sql/Updates/0.0.3/r1119_scriptdev2.sql b/sql/updates/0.0.3/r1119_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1119_scriptdev2.sql rename to sql/updates/0.0.3/r1119_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1120_scriptdev2.sql b/sql/updates/0.0.3/r1120_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1120_scriptdev2.sql rename to sql/updates/0.0.3/r1120_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1121_mangos.sql b/sql/updates/0.0.3/r1121_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1121_mangos.sql rename to sql/updates/0.0.3/r1121_mangos.sql diff --git a/sql/Updates/0.0.3/r1121_scriptdev2.sql b/sql/updates/0.0.3/r1121_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1121_scriptdev2.sql rename to sql/updates/0.0.3/r1121_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1123_scriptdev2.sql b/sql/updates/0.0.3/r1123_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1123_scriptdev2.sql rename to sql/updates/0.0.3/r1123_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1128_mangos.sql b/sql/updates/0.0.3/r1128_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1128_mangos.sql rename to sql/updates/0.0.3/r1128_mangos.sql diff --git a/sql/Updates/0.0.3/r1129_mangos.sql b/sql/updates/0.0.3/r1129_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1129_mangos.sql rename to sql/updates/0.0.3/r1129_mangos.sql diff --git a/sql/Updates/0.0.3/r1129_scriptdev2.sql b/sql/updates/0.0.3/r1129_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1129_scriptdev2.sql rename to sql/updates/0.0.3/r1129_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1131_mangos.sql b/sql/updates/0.0.3/r1131_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1131_mangos.sql rename to sql/updates/0.0.3/r1131_mangos.sql diff --git a/sql/Updates/0.0.3/r1136_mangos.sql b/sql/updates/0.0.3/r1136_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1136_mangos.sql rename to sql/updates/0.0.3/r1136_mangos.sql diff --git a/sql/Updates/0.0.3/r1136_scriptdev2.sql b/sql/updates/0.0.3/r1136_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1136_scriptdev2.sql rename to sql/updates/0.0.3/r1136_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1140_scriptdev2.sql b/sql/updates/0.0.3/r1140_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1140_scriptdev2.sql rename to sql/updates/0.0.3/r1140_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1141_mangos.sql b/sql/updates/0.0.3/r1141_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1141_mangos.sql rename to sql/updates/0.0.3/r1141_mangos.sql diff --git a/sql/Updates/0.0.3/r1145_scriptdev2.sql b/sql/updates/0.0.3/r1145_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1145_scriptdev2.sql rename to sql/updates/0.0.3/r1145_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1146_scriptdev2.sql b/sql/updates/0.0.3/r1146_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1146_scriptdev2.sql rename to sql/updates/0.0.3/r1146_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1149_scriptdev2.sql b/sql/updates/0.0.3/r1149_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1149_scriptdev2.sql rename to sql/updates/0.0.3/r1149_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1152_scriptdev2.sql b/sql/updates/0.0.3/r1152_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1152_scriptdev2.sql rename to sql/updates/0.0.3/r1152_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1154_mangos.sql b/sql/updates/0.0.3/r1154_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1154_mangos.sql rename to sql/updates/0.0.3/r1154_mangos.sql diff --git a/sql/Updates/0.0.3/r1155_mangos.sql b/sql/updates/0.0.3/r1155_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1155_mangos.sql rename to sql/updates/0.0.3/r1155_mangos.sql diff --git a/sql/Updates/0.0.3/r1169_mangos.sql b/sql/updates/0.0.3/r1169_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1169_mangos.sql rename to sql/updates/0.0.3/r1169_mangos.sql diff --git a/sql/Updates/0.0.3/r1169_scriptdev2.sql b/sql/updates/0.0.3/r1169_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1169_scriptdev2.sql rename to sql/updates/0.0.3/r1169_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1171_scriptdev2.sql b/sql/updates/0.0.3/r1171_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1171_scriptdev2.sql rename to sql/updates/0.0.3/r1171_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1173_scriptdev2.sql b/sql/updates/0.0.3/r1173_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1173_scriptdev2.sql rename to sql/updates/0.0.3/r1173_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1180_mangos.sql b/sql/updates/0.0.3/r1180_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1180_mangos.sql rename to sql/updates/0.0.3/r1180_mangos.sql diff --git a/sql/Updates/0.0.3/r1184_mangos.sql b/sql/updates/0.0.3/r1184_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1184_mangos.sql rename to sql/updates/0.0.3/r1184_mangos.sql diff --git a/sql/Updates/0.0.3/r1197_mangos.sql b/sql/updates/0.0.3/r1197_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1197_mangos.sql rename to sql/updates/0.0.3/r1197_mangos.sql diff --git a/sql/Updates/0.0.3/r1199_mangos.sql b/sql/updates/0.0.3/r1199_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1199_mangos.sql rename to sql/updates/0.0.3/r1199_mangos.sql diff --git a/sql/Updates/0.0.3/r1202_mangos.sql b/sql/updates/0.0.3/r1202_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1202_mangos.sql rename to sql/updates/0.0.3/r1202_mangos.sql diff --git a/sql/Updates/0.0.3/r1202_scriptdev2.sql b/sql/updates/0.0.3/r1202_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1202_scriptdev2.sql rename to sql/updates/0.0.3/r1202_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1207_mangos.sql b/sql/updates/0.0.3/r1207_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1207_mangos.sql rename to sql/updates/0.0.3/r1207_mangos.sql diff --git a/sql/Updates/0.0.3/r1207_scriptdev2.sql b/sql/updates/0.0.3/r1207_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1207_scriptdev2.sql rename to sql/updates/0.0.3/r1207_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1210_mangos.sql b/sql/updates/0.0.3/r1210_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1210_mangos.sql rename to sql/updates/0.0.3/r1210_mangos.sql diff --git a/sql/Updates/0.0.3/r1212_mangos.sql b/sql/updates/0.0.3/r1212_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1212_mangos.sql rename to sql/updates/0.0.3/r1212_mangos.sql diff --git a/sql/Updates/0.0.3/r1212_scriptdev2.sql b/sql/updates/0.0.3/r1212_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1212_scriptdev2.sql rename to sql/updates/0.0.3/r1212_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1215_mangos.sql b/sql/updates/0.0.3/r1215_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1215_mangos.sql rename to sql/updates/0.0.3/r1215_mangos.sql diff --git a/sql/Updates/0.0.3/r1215_scriptdev2.sql b/sql/updates/0.0.3/r1215_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1215_scriptdev2.sql rename to sql/updates/0.0.3/r1215_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1218_scriptdev2.sql b/sql/updates/0.0.3/r1218_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1218_scriptdev2.sql rename to sql/updates/0.0.3/r1218_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1221_mangos.sql b/sql/updates/0.0.3/r1221_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1221_mangos.sql rename to sql/updates/0.0.3/r1221_mangos.sql diff --git a/sql/Updates/0.0.3/r1221_scriptdev2.sql b/sql/updates/0.0.3/r1221_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1221_scriptdev2.sql rename to sql/updates/0.0.3/r1221_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1222_scriptdev2.sql b/sql/updates/0.0.3/r1222_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1222_scriptdev2.sql rename to sql/updates/0.0.3/r1222_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1234_mangos.sql b/sql/updates/0.0.3/r1234_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1234_mangos.sql rename to sql/updates/0.0.3/r1234_mangos.sql diff --git a/sql/Updates/0.0.3/r1241_scriptdev2.sql b/sql/updates/0.0.3/r1241_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1241_scriptdev2.sql rename to sql/updates/0.0.3/r1241_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1242_mangos.sql b/sql/updates/0.0.3/r1242_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1242_mangos.sql rename to sql/updates/0.0.3/r1242_mangos.sql diff --git a/sql/Updates/0.0.3/r1242_scriptdev2.sql b/sql/updates/0.0.3/r1242_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1242_scriptdev2.sql rename to sql/updates/0.0.3/r1242_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1243_mangos.sql b/sql/updates/0.0.3/r1243_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1243_mangos.sql rename to sql/updates/0.0.3/r1243_mangos.sql diff --git a/sql/Updates/0.0.3/r1243_scriptdev2.sql b/sql/updates/0.0.3/r1243_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1243_scriptdev2.sql rename to sql/updates/0.0.3/r1243_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1249_mangos.sql b/sql/updates/0.0.3/r1249_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1249_mangos.sql rename to sql/updates/0.0.3/r1249_mangos.sql diff --git a/sql/Updates/0.0.3/r1249_scriptdev2.sql b/sql/updates/0.0.3/r1249_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1249_scriptdev2.sql rename to sql/updates/0.0.3/r1249_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1250_mangos.sql b/sql/updates/0.0.3/r1250_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1250_mangos.sql rename to sql/updates/0.0.3/r1250_mangos.sql diff --git a/sql/Updates/0.0.3/r1250_scriptdev2.sql b/sql/updates/0.0.3/r1250_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1250_scriptdev2.sql rename to sql/updates/0.0.3/r1250_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1251_scriptdev2.sql b/sql/updates/0.0.3/r1251_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1251_scriptdev2.sql rename to sql/updates/0.0.3/r1251_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1257_scriptdev2.sql b/sql/updates/0.0.3/r1257_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1257_scriptdev2.sql rename to sql/updates/0.0.3/r1257_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1258_mangos.sql b/sql/updates/0.0.3/r1258_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1258_mangos.sql rename to sql/updates/0.0.3/r1258_mangos.sql diff --git a/sql/Updates/0.0.3/r1258_scriptdev2.sql b/sql/updates/0.0.3/r1258_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1258_scriptdev2.sql rename to sql/updates/0.0.3/r1258_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1260_scriptdev2.sql b/sql/updates/0.0.3/r1260_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1260_scriptdev2.sql rename to sql/updates/0.0.3/r1260_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1261_mangos.sql b/sql/updates/0.0.3/r1261_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1261_mangos.sql rename to sql/updates/0.0.3/r1261_mangos.sql diff --git a/sql/Updates/0.0.3/r1263_mangos.sql b/sql/updates/0.0.3/r1263_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1263_mangos.sql rename to sql/updates/0.0.3/r1263_mangos.sql diff --git a/sql/Updates/0.0.3/r1265_mangos.sql b/sql/updates/0.0.3/r1265_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1265_mangos.sql rename to sql/updates/0.0.3/r1265_mangos.sql diff --git a/sql/Updates/0.0.3/r1265_scriptdev2.sql b/sql/updates/0.0.3/r1265_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1265_scriptdev2.sql rename to sql/updates/0.0.3/r1265_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1266_mangos.sql b/sql/updates/0.0.3/r1266_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1266_mangos.sql rename to sql/updates/0.0.3/r1266_mangos.sql diff --git a/sql/Updates/0.0.3/r1266_scriptdev2.sql b/sql/updates/0.0.3/r1266_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1266_scriptdev2.sql rename to sql/updates/0.0.3/r1266_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1280_mangos.sql b/sql/updates/0.0.3/r1280_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1280_mangos.sql rename to sql/updates/0.0.3/r1280_mangos.sql diff --git a/sql/Updates/0.0.3/r1280_scriptdev2.sql b/sql/updates/0.0.3/r1280_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1280_scriptdev2.sql rename to sql/updates/0.0.3/r1280_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1281_mangos.sql b/sql/updates/0.0.3/r1281_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1281_mangos.sql rename to sql/updates/0.0.3/r1281_mangos.sql diff --git a/sql/Updates/0.0.3/r1282_mangos.sql b/sql/updates/0.0.3/r1282_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1282_mangos.sql rename to sql/updates/0.0.3/r1282_mangos.sql diff --git a/sql/Updates/0.0.3/r1283_mangos.sql b/sql/updates/0.0.3/r1283_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1283_mangos.sql rename to sql/updates/0.0.3/r1283_mangos.sql diff --git a/sql/Updates/0.0.3/r1299_scriptdev2.sql b/sql/updates/0.0.3/r1299_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1299_scriptdev2.sql rename to sql/updates/0.0.3/r1299_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1300_mangos.sql b/sql/updates/0.0.3/r1300_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1300_mangos.sql rename to sql/updates/0.0.3/r1300_mangos.sql diff --git a/sql/Updates/0.0.3/r1307_mangos.sql b/sql/updates/0.0.3/r1307_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1307_mangos.sql rename to sql/updates/0.0.3/r1307_mangos.sql diff --git a/sql/Updates/0.0.3/r1317_mangos.sql b/sql/updates/0.0.3/r1317_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1317_mangos.sql rename to sql/updates/0.0.3/r1317_mangos.sql diff --git a/sql/Updates/0.0.3/r1317_scriptdev2.sql b/sql/updates/0.0.3/r1317_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1317_scriptdev2.sql rename to sql/updates/0.0.3/r1317_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1321_mangos.sql b/sql/updates/0.0.3/r1321_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1321_mangos.sql rename to sql/updates/0.0.3/r1321_mangos.sql diff --git a/sql/Updates/0.0.3/r1321_scriptdev2.sql b/sql/updates/0.0.3/r1321_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1321_scriptdev2.sql rename to sql/updates/0.0.3/r1321_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1322_scriptdev2.sql b/sql/updates/0.0.3/r1322_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1322_scriptdev2.sql rename to sql/updates/0.0.3/r1322_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1326_scriptdev2.sql b/sql/updates/0.0.3/r1326_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1326_scriptdev2.sql rename to sql/updates/0.0.3/r1326_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1333_mangos.sql b/sql/updates/0.0.3/r1333_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1333_mangos.sql rename to sql/updates/0.0.3/r1333_mangos.sql diff --git a/sql/Updates/0.0.3/r1334_mangos.sql b/sql/updates/0.0.3/r1334_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1334_mangos.sql rename to sql/updates/0.0.3/r1334_mangos.sql diff --git a/sql/Updates/0.0.3/r1335_scriptdev2.sql b/sql/updates/0.0.3/r1335_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1335_scriptdev2.sql rename to sql/updates/0.0.3/r1335_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1336_mangos.sql b/sql/updates/0.0.3/r1336_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1336_mangos.sql rename to sql/updates/0.0.3/r1336_mangos.sql diff --git a/sql/Updates/0.0.3/r1336_scriptdev2.sql b/sql/updates/0.0.3/r1336_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1336_scriptdev2.sql rename to sql/updates/0.0.3/r1336_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1341_scriptdev2.sql b/sql/updates/0.0.3/r1341_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1341_scriptdev2.sql rename to sql/updates/0.0.3/r1341_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1351_mangos.sql b/sql/updates/0.0.3/r1351_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1351_mangos.sql rename to sql/updates/0.0.3/r1351_mangos.sql diff --git a/sql/Updates/0.0.3/r1351_scriptdev2.sql b/sql/updates/0.0.3/r1351_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1351_scriptdev2.sql rename to sql/updates/0.0.3/r1351_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1352_mangos.sql b/sql/updates/0.0.3/r1352_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1352_mangos.sql rename to sql/updates/0.0.3/r1352_mangos.sql diff --git a/sql/Updates/0.0.3/r1352_scriptdev2.sql b/sql/updates/0.0.3/r1352_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1352_scriptdev2.sql rename to sql/updates/0.0.3/r1352_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1354_scriptdev2.sql b/sql/updates/0.0.3/r1354_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1354_scriptdev2.sql rename to sql/updates/0.0.3/r1354_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1358_mangos.sql b/sql/updates/0.0.3/r1358_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1358_mangos.sql rename to sql/updates/0.0.3/r1358_mangos.sql diff --git a/sql/Updates/0.0.3/r1359_mangos.sql b/sql/updates/0.0.3/r1359_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1359_mangos.sql rename to sql/updates/0.0.3/r1359_mangos.sql diff --git a/sql/Updates/0.0.3/r1359_scriptdev2.sql b/sql/updates/0.0.3/r1359_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1359_scriptdev2.sql rename to sql/updates/0.0.3/r1359_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1367_mangos.sql b/sql/updates/0.0.3/r1367_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1367_mangos.sql rename to sql/updates/0.0.3/r1367_mangos.sql diff --git a/sql/Updates/0.0.3/r1368_mangos.sql b/sql/updates/0.0.3/r1368_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1368_mangos.sql rename to sql/updates/0.0.3/r1368_mangos.sql diff --git a/sql/Updates/0.0.3/r1369_mangos.sql b/sql/updates/0.0.3/r1369_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1369_mangos.sql rename to sql/updates/0.0.3/r1369_mangos.sql diff --git a/sql/Updates/0.0.3/r1370_mangos.sql b/sql/updates/0.0.3/r1370_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1370_mangos.sql rename to sql/updates/0.0.3/r1370_mangos.sql diff --git a/sql/Updates/0.0.3/r1371_scriptdev2.sql b/sql/updates/0.0.3/r1371_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1371_scriptdev2.sql rename to sql/updates/0.0.3/r1371_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1374_mangos.sql b/sql/updates/0.0.3/r1374_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1374_mangos.sql rename to sql/updates/0.0.3/r1374_mangos.sql diff --git a/sql/Updates/0.0.3/r1374_scriptdev2.sql b/sql/updates/0.0.3/r1374_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1374_scriptdev2.sql rename to sql/updates/0.0.3/r1374_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1378_mangos.sql b/sql/updates/0.0.3/r1378_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1378_mangos.sql rename to sql/updates/0.0.3/r1378_mangos.sql diff --git a/sql/Updates/0.0.3/r1378_scriptdev2.sql b/sql/updates/0.0.3/r1378_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1378_scriptdev2.sql rename to sql/updates/0.0.3/r1378_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1379_mangos.sql b/sql/updates/0.0.3/r1379_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1379_mangos.sql rename to sql/updates/0.0.3/r1379_mangos.sql diff --git a/sql/Updates/0.0.3/r1379_scriptdev2.sql b/sql/updates/0.0.3/r1379_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1379_scriptdev2.sql rename to sql/updates/0.0.3/r1379_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1380_mangos.sql b/sql/updates/0.0.3/r1380_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1380_mangos.sql rename to sql/updates/0.0.3/r1380_mangos.sql diff --git a/sql/Updates/0.0.3/r1380_scriptdev2.sql b/sql/updates/0.0.3/r1380_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1380_scriptdev2.sql rename to sql/updates/0.0.3/r1380_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1382_mangos.sql b/sql/updates/0.0.3/r1382_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1382_mangos.sql rename to sql/updates/0.0.3/r1382_mangos.sql diff --git a/sql/Updates/0.0.3/r1383_scriptdev2.sql b/sql/updates/0.0.3/r1383_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1383_scriptdev2.sql rename to sql/updates/0.0.3/r1383_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1384_scriptdev2.sql b/sql/updates/0.0.3/r1384_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1384_scriptdev2.sql rename to sql/updates/0.0.3/r1384_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1385_mangos.sql b/sql/updates/0.0.3/r1385_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1385_mangos.sql rename to sql/updates/0.0.3/r1385_mangos.sql diff --git a/sql/Updates/0.0.3/r1385_scriptdev2.sql b/sql/updates/0.0.3/r1385_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1385_scriptdev2.sql rename to sql/updates/0.0.3/r1385_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1386_mangos.sql b/sql/updates/0.0.3/r1386_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1386_mangos.sql rename to sql/updates/0.0.3/r1386_mangos.sql diff --git a/sql/Updates/0.0.3/r1386_scriptdev2.sql b/sql/updates/0.0.3/r1386_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1386_scriptdev2.sql rename to sql/updates/0.0.3/r1386_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1388_mangos.sql b/sql/updates/0.0.3/r1388_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1388_mangos.sql rename to sql/updates/0.0.3/r1388_mangos.sql diff --git a/sql/Updates/0.0.3/r1388_scriptdev2.sql b/sql/updates/0.0.3/r1388_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1388_scriptdev2.sql rename to sql/updates/0.0.3/r1388_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1391_mangos.sql b/sql/updates/0.0.3/r1391_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1391_mangos.sql rename to sql/updates/0.0.3/r1391_mangos.sql diff --git a/sql/Updates/0.0.3/r1391_scriptdev2.sql b/sql/updates/0.0.3/r1391_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1391_scriptdev2.sql rename to sql/updates/0.0.3/r1391_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1392_mangos.sql b/sql/updates/0.0.3/r1392_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1392_mangos.sql rename to sql/updates/0.0.3/r1392_mangos.sql diff --git a/sql/Updates/0.0.3/r1392_scriptdev2.sql b/sql/updates/0.0.3/r1392_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1392_scriptdev2.sql rename to sql/updates/0.0.3/r1392_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1394_mangos.sql b/sql/updates/0.0.3/r1394_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1394_mangos.sql rename to sql/updates/0.0.3/r1394_mangos.sql diff --git a/sql/Updates/0.0.3/r1394_scriptdev2.sql b/sql/updates/0.0.3/r1394_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1394_scriptdev2.sql rename to sql/updates/0.0.3/r1394_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1405_mangos.sql b/sql/updates/0.0.3/r1405_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1405_mangos.sql rename to sql/updates/0.0.3/r1405_mangos.sql diff --git a/sql/Updates/0.0.3/r1405_scriptdev2.sql b/sql/updates/0.0.3/r1405_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1405_scriptdev2.sql rename to sql/updates/0.0.3/r1405_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1406_mangos.sql b/sql/updates/0.0.3/r1406_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1406_mangos.sql rename to sql/updates/0.0.3/r1406_mangos.sql diff --git a/sql/Updates/0.0.3/r1408_mangos.sql b/sql/updates/0.0.3/r1408_mangos.sql similarity index 72% rename from sql/Updates/0.0.3/r1408_mangos.sql rename to sql/updates/0.0.3/r1408_mangos.sql index e19d63878d..0365a3654a 100644 --- a/sql/Updates/0.0.3/r1408_mangos.sql +++ b/sql/updates/0.0.3/r1408_mangos.sql @@ -1,4 +1,4 @@ -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_galdarah' WHERE entry=29306; UPDATE creature_template SET ScriptName='boss_moorabi' WHERE entry=29305; UPDATE creature_template SET ScriptName='boss_sladran' WHERE entry=29304; diff --git a/sql/Updates/0.0.3/r1408_scriptdev2.sql b/sql/updates/0.0.3/r1408_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1408_scriptdev2.sql rename to sql/updates/0.0.3/r1408_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1409_mangos.sql b/sql/updates/0.0.3/r1409_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1409_mangos.sql rename to sql/updates/0.0.3/r1409_mangos.sql diff --git a/sql/Updates/0.0.3/r1409_scriptdev2.sql b/sql/updates/0.0.3/r1409_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1409_scriptdev2.sql rename to sql/updates/0.0.3/r1409_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1410_mangos.sql b/sql/updates/0.0.3/r1410_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1410_mangos.sql rename to sql/updates/0.0.3/r1410_mangos.sql diff --git a/sql/Updates/0.0.3/r1410_scriptdev2.sql b/sql/updates/0.0.3/r1410_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1410_scriptdev2.sql rename to sql/updates/0.0.3/r1410_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1411_mangos.sql b/sql/updates/0.0.3/r1411_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1411_mangos.sql rename to sql/updates/0.0.3/r1411_mangos.sql diff --git a/sql/Updates/0.0.3/r1411_scriptdev2.sql b/sql/updates/0.0.3/r1411_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1411_scriptdev2.sql rename to sql/updates/0.0.3/r1411_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1412_mangos.sql b/sql/updates/0.0.3/r1412_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1412_mangos.sql rename to sql/updates/0.0.3/r1412_mangos.sql diff --git a/sql/Updates/0.0.3/r1412_scriptdev2.sql b/sql/updates/0.0.3/r1412_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1412_scriptdev2.sql rename to sql/updates/0.0.3/r1412_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1413_mangos.sql b/sql/updates/0.0.3/r1413_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1413_mangos.sql rename to sql/updates/0.0.3/r1413_mangos.sql diff --git a/sql/Updates/0.0.3/r1413_scriptdev2.sql b/sql/updates/0.0.3/r1413_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1413_scriptdev2.sql rename to sql/updates/0.0.3/r1413_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1414_mangos.sql b/sql/updates/0.0.3/r1414_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1414_mangos.sql rename to sql/updates/0.0.3/r1414_mangos.sql diff --git a/sql/Updates/0.0.3/r1414_scriptdev2.sql b/sql/updates/0.0.3/r1414_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1414_scriptdev2.sql rename to sql/updates/0.0.3/r1414_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1415_mangos.sql b/sql/updates/0.0.3/r1415_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1415_mangos.sql rename to sql/updates/0.0.3/r1415_mangos.sql diff --git a/sql/Updates/0.0.3/r1417_mangos.sql b/sql/updates/0.0.3/r1417_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1417_mangos.sql rename to sql/updates/0.0.3/r1417_mangos.sql diff --git a/sql/Updates/0.0.3/r1418_scriptdev2.sql b/sql/updates/0.0.3/r1418_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1418_scriptdev2.sql rename to sql/updates/0.0.3/r1418_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1419_mangos.sql b/sql/updates/0.0.3/r1419_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1419_mangos.sql rename to sql/updates/0.0.3/r1419_mangos.sql diff --git a/sql/Updates/0.0.3/r1421_scriptdev2.sql b/sql/updates/0.0.3/r1421_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1421_scriptdev2.sql rename to sql/updates/0.0.3/r1421_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1422_mangos.sql b/sql/updates/0.0.3/r1422_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1422_mangos.sql rename to sql/updates/0.0.3/r1422_mangos.sql diff --git a/sql/Updates/0.0.3/r1422_scriptdev2.sql b/sql/updates/0.0.3/r1422_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1422_scriptdev2.sql rename to sql/updates/0.0.3/r1422_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1428_scriptdev2.sql b/sql/updates/0.0.3/r1428_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1428_scriptdev2.sql rename to sql/updates/0.0.3/r1428_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1430_mangos.sql b/sql/updates/0.0.3/r1430_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1430_mangos.sql rename to sql/updates/0.0.3/r1430_mangos.sql diff --git a/sql/Updates/0.0.3/r1433_mangos.sql b/sql/updates/0.0.3/r1433_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1433_mangos.sql rename to sql/updates/0.0.3/r1433_mangos.sql diff --git a/sql/Updates/0.0.3/r1435_mangos.sql b/sql/updates/0.0.3/r1435_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1435_mangos.sql rename to sql/updates/0.0.3/r1435_mangos.sql diff --git a/sql/Updates/0.0.3/r1436_mangos.sql b/sql/updates/0.0.3/r1436_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1436_mangos.sql rename to sql/updates/0.0.3/r1436_mangos.sql diff --git a/sql/Updates/0.0.3/r1437_scriptdev2.sql b/sql/updates/0.0.3/r1437_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1437_scriptdev2.sql rename to sql/updates/0.0.3/r1437_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1439_scriptdev2.sql b/sql/updates/0.0.3/r1439_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r1439_scriptdev2.sql rename to sql/updates/0.0.3/r1439_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r1441_mangos.sql b/sql/updates/0.0.3/r1441_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r1441_mangos.sql rename to sql/updates/0.0.3/r1441_mangos.sql diff --git a/sql/Updates/0.0.3/r814_scriptdev2_eventai_scripts.sql b/sql/updates/0.0.3/r814_scriptdev2_eventai_scripts.sql similarity index 100% rename from sql/Updates/0.0.3/r814_scriptdev2_eventai_scripts.sql rename to sql/updates/0.0.3/r814_scriptdev2_eventai_scripts.sql diff --git a/sql/Updates/0.0.3/r820_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r820_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r820_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r820_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r822_mangos.sql b/sql/updates/0.0.3/r822_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r822_mangos.sql rename to sql/updates/0.0.3/r822_mangos.sql diff --git a/sql/Updates/0.0.3/r822_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r822_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r822_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r822_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r823_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r823_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r823_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r823_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r824_mangos.sql b/sql/updates/0.0.3/r824_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r824_mangos.sql rename to sql/updates/0.0.3/r824_mangos.sql diff --git a/sql/Updates/0.0.3/r824_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r824_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r824_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r824_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r825_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r825_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r825_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r825_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r826_scriptdev2.sql b/sql/updates/0.0.3/r826_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r826_scriptdev2.sql rename to sql/updates/0.0.3/r826_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r827_mangos.sql b/sql/updates/0.0.3/r827_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r827_mangos.sql rename to sql/updates/0.0.3/r827_mangos.sql diff --git a/sql/Updates/0.0.3/r828_mangos.sql b/sql/updates/0.0.3/r828_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r828_mangos.sql rename to sql/updates/0.0.3/r828_mangos.sql diff --git a/sql/Updates/0.0.3/r834_mangos.sql b/sql/updates/0.0.3/r834_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r834_mangos.sql rename to sql/updates/0.0.3/r834_mangos.sql diff --git a/sql/Updates/0.0.3/r834_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r834_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r834_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r834_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r835_mangos.sql b/sql/updates/0.0.3/r835_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r835_mangos.sql rename to sql/updates/0.0.3/r835_mangos.sql diff --git a/sql/Updates/0.0.3/r845_mangos.sql b/sql/updates/0.0.3/r845_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r845_mangos.sql rename to sql/updates/0.0.3/r845_mangos.sql diff --git a/sql/Updates/0.0.3/r846_scriptdev2.sql b/sql/updates/0.0.3/r846_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r846_scriptdev2.sql rename to sql/updates/0.0.3/r846_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r847_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r847_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r847_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r847_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r848_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r848_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r848_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r848_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r849_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r849_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r849_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r849_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r850_mangos.sql b/sql/updates/0.0.3/r850_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r850_mangos.sql rename to sql/updates/0.0.3/r850_mangos.sql diff --git a/sql/Updates/0.0.3/r851_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r851_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r851_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r851_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r852_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r852_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r852_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r852_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r854_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r854_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r854_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r854_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r855_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r855_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r855_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r855_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r856_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r856_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r856_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r856_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r860_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r860_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r860_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r860_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r862_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r862_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r862_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r862_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r863_mangos.sql b/sql/updates/0.0.3/r863_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r863_mangos.sql rename to sql/updates/0.0.3/r863_mangos.sql diff --git a/sql/Updates/0.0.3/r872_mangos.sql b/sql/updates/0.0.3/r872_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r872_mangos.sql rename to sql/updates/0.0.3/r872_mangos.sql diff --git a/sql/Updates/0.0.3/r883_mangos.sql b/sql/updates/0.0.3/r883_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r883_mangos.sql rename to sql/updates/0.0.3/r883_mangos.sql diff --git a/sql/Updates/0.0.3/r895_mangos.sql b/sql/updates/0.0.3/r895_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r895_mangos.sql rename to sql/updates/0.0.3/r895_mangos.sql diff --git a/sql/Updates/0.0.3/r900_mangos.sql b/sql/updates/0.0.3/r900_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r900_mangos.sql rename to sql/updates/0.0.3/r900_mangos.sql diff --git a/sql/Updates/0.0.3/r903_mangos.sql b/sql/updates/0.0.3/r903_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r903_mangos.sql rename to sql/updates/0.0.3/r903_mangos.sql diff --git a/sql/Updates/0.0.3/r903_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r903_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r903_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r903_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r907_mangos.sql b/sql/updates/0.0.3/r907_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r907_mangos.sql rename to sql/updates/0.0.3/r907_mangos.sql diff --git a/sql/Updates/0.0.3/r907_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r907_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r907_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r907_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r909_mangos.sql b/sql/updates/0.0.3/r909_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r909_mangos.sql rename to sql/updates/0.0.3/r909_mangos.sql diff --git a/sql/Updates/0.0.3/r910_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r910_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r910_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r910_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r912_mangos.sql b/sql/updates/0.0.3/r912_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r912_mangos.sql rename to sql/updates/0.0.3/r912_mangos.sql diff --git a/sql/Updates/0.0.3/r912_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r912_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r912_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r912_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r916_mangos.sql b/sql/updates/0.0.3/r916_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r916_mangos.sql rename to sql/updates/0.0.3/r916_mangos.sql diff --git a/sql/Updates/0.0.3/r916_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r916_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r916_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r916_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r919_mangos.sql b/sql/updates/0.0.3/r919_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r919_mangos.sql rename to sql/updates/0.0.3/r919_mangos.sql diff --git a/sql/Updates/0.0.3/r922_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r922_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r922_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r922_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r924_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r924_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r924_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r924_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r936_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r936_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r936_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r936_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r937_mangos.sql b/sql/updates/0.0.3/r937_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r937_mangos.sql rename to sql/updates/0.0.3/r937_mangos.sql diff --git a/sql/Updates/0.0.3/r937_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r937_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r937_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r937_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r937_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r937_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r937_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r937_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r939_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r939_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r939_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r939_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r940_mangos.sql b/sql/updates/0.0.3/r940_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r940_mangos.sql rename to sql/updates/0.0.3/r940_mangos.sql diff --git a/sql/Updates/0.0.3/r941_mangos.sql b/sql/updates/0.0.3/r941_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r941_mangos.sql rename to sql/updates/0.0.3/r941_mangos.sql diff --git a/sql/Updates/0.0.3/r945_mangos.sql b/sql/updates/0.0.3/r945_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r945_mangos.sql rename to sql/updates/0.0.3/r945_mangos.sql diff --git a/sql/Updates/0.0.3/r945_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r945_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r945_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r945_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r945_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r945_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r945_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r945_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r947_mangos.sql b/sql/updates/0.0.3/r947_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r947_mangos.sql rename to sql/updates/0.0.3/r947_mangos.sql diff --git a/sql/Updates/0.0.3/r949_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r949_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r949_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r949_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r951_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r951_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r951_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r951_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r953_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r953_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r953_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r953_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r956_scriptdev2.sql b/sql/updates/0.0.3/r956_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r956_scriptdev2.sql rename to sql/updates/0.0.3/r956_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r963_mangos.sql b/sql/updates/0.0.3/r963_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r963_mangos.sql rename to sql/updates/0.0.3/r963_mangos.sql diff --git a/sql/Updates/0.0.3/r964_mangos.sql b/sql/updates/0.0.3/r964_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r964_mangos.sql rename to sql/updates/0.0.3/r964_mangos.sql diff --git a/sql/Updates/0.0.3/r965_mangos.sql b/sql/updates/0.0.3/r965_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r965_mangos.sql rename to sql/updates/0.0.3/r965_mangos.sql diff --git a/sql/Updates/0.0.3/r965_scriptdev2.sql b/sql/updates/0.0.3/r965_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r965_scriptdev2.sql rename to sql/updates/0.0.3/r965_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r972_mangos.sql b/sql/updates/0.0.3/r972_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r972_mangos.sql rename to sql/updates/0.0.3/r972_mangos.sql diff --git a/sql/Updates/0.0.3/r972_scriptdev2.sql b/sql/updates/0.0.3/r972_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r972_scriptdev2.sql rename to sql/updates/0.0.3/r972_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r973_mangos.sql b/sql/updates/0.0.3/r973_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r973_mangos.sql rename to sql/updates/0.0.3/r973_mangos.sql diff --git a/sql/Updates/0.0.3/r973_scriptdev2_script_waypoint.sql b/sql/updates/0.0.3/r973_scriptdev2_script_waypoint.sql similarity index 100% rename from sql/Updates/0.0.3/r973_scriptdev2_script_waypoint.sql rename to sql/updates/0.0.3/r973_scriptdev2_script_waypoint.sql diff --git a/sql/Updates/0.0.3/r975_mangos.sql b/sql/updates/0.0.3/r975_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r975_mangos.sql rename to sql/updates/0.0.3/r975_mangos.sql diff --git a/sql/Updates/0.0.3/r975_scriptdev2.sql b/sql/updates/0.0.3/r975_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r975_scriptdev2.sql rename to sql/updates/0.0.3/r975_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r976_mangos.sql b/sql/updates/0.0.3/r976_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r976_mangos.sql rename to sql/updates/0.0.3/r976_mangos.sql diff --git a/sql/Updates/0.0.3/r976_scriptdev2.sql b/sql/updates/0.0.3/r976_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r976_scriptdev2.sql rename to sql/updates/0.0.3/r976_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r978_mangos.sql b/sql/updates/0.0.3/r978_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r978_mangos.sql rename to sql/updates/0.0.3/r978_mangos.sql diff --git a/sql/Updates/0.0.3/r979_mangos.sql b/sql/updates/0.0.3/r979_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r979_mangos.sql rename to sql/updates/0.0.3/r979_mangos.sql diff --git a/sql/Updates/0.0.3/r979_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r979_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r979_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r979_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r980_mangos.sql b/sql/updates/0.0.3/r980_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r980_mangos.sql rename to sql/updates/0.0.3/r980_mangos.sql diff --git a/sql/Updates/0.0.3/r982_mangos.sql b/sql/updates/0.0.3/r982_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r982_mangos.sql rename to sql/updates/0.0.3/r982_mangos.sql diff --git a/sql/Updates/0.0.3/r982_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r982_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r982_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r982_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r989_mangos.sql b/sql/updates/0.0.3/r989_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r989_mangos.sql rename to sql/updates/0.0.3/r989_mangos.sql diff --git a/sql/Updates/0.0.3/r990_mangos.sql b/sql/updates/0.0.3/r990_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r990_mangos.sql rename to sql/updates/0.0.3/r990_mangos.sql diff --git a/sql/Updates/0.0.3/r991_scriptdev2.sql b/sql/updates/0.0.3/r991_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r991_scriptdev2.sql rename to sql/updates/0.0.3/r991_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r992_mangos.sql b/sql/updates/0.0.3/r992_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r992_mangos.sql rename to sql/updates/0.0.3/r992_mangos.sql diff --git a/sql/Updates/0.0.3/r993_mangos.sql b/sql/updates/0.0.3/r993_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r993_mangos.sql rename to sql/updates/0.0.3/r993_mangos.sql diff --git a/sql/Updates/0.0.3/r993_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r993_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r993_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r993_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.3/r995_mangos.sql b/sql/updates/0.0.3/r995_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r995_mangos.sql rename to sql/updates/0.0.3/r995_mangos.sql diff --git a/sql/Updates/0.0.3/r995_scriptdev2.sql b/sql/updates/0.0.3/r995_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.3/r995_scriptdev2.sql rename to sql/updates/0.0.3/r995_scriptdev2.sql diff --git a/sql/Updates/0.0.3/r997_mangos.sql b/sql/updates/0.0.3/r997_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r997_mangos.sql rename to sql/updates/0.0.3/r997_mangos.sql diff --git a/sql/Updates/0.0.3/r998_mangos.sql b/sql/updates/0.0.3/r998_mangos.sql similarity index 100% rename from sql/Updates/0.0.3/r998_mangos.sql rename to sql/updates/0.0.3/r998_mangos.sql diff --git a/sql/Updates/0.0.3/r998_scriptdev2_script_texts.sql b/sql/updates/0.0.3/r998_scriptdev2_script_texts.sql similarity index 100% rename from sql/Updates/0.0.3/r998_scriptdev2_script_texts.sql rename to sql/updates/0.0.3/r998_scriptdev2_script_texts.sql diff --git a/sql/Updates/0.0.4/r1453_scriptdev2.sql b/sql/updates/0.0.4/r1453_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1453_scriptdev2.sql rename to sql/updates/0.0.4/r1453_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1457_scriptdev2.sql b/sql/updates/0.0.4/r1457_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1457_scriptdev2.sql rename to sql/updates/0.0.4/r1457_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1459_mangos.sql b/sql/updates/0.0.4/r1459_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1459_mangos.sql rename to sql/updates/0.0.4/r1459_mangos.sql diff --git a/sql/Updates/0.0.4/r1460_mangos.sql b/sql/updates/0.0.4/r1460_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1460_mangos.sql rename to sql/updates/0.0.4/r1460_mangos.sql diff --git a/sql/Updates/0.0.4/r1461_mangos.sql b/sql/updates/0.0.4/r1461_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1461_mangos.sql rename to sql/updates/0.0.4/r1461_mangos.sql diff --git a/sql/Updates/0.0.4/r1461_scriptdev2.sql b/sql/updates/0.0.4/r1461_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1461_scriptdev2.sql rename to sql/updates/0.0.4/r1461_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1463_mangos.sql b/sql/updates/0.0.4/r1463_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1463_mangos.sql rename to sql/updates/0.0.4/r1463_mangos.sql diff --git a/sql/Updates/0.0.4/r1465_scriptdev2.sql b/sql/updates/0.0.4/r1465_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1465_scriptdev2.sql rename to sql/updates/0.0.4/r1465_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1466_scriptdev2.sql b/sql/updates/0.0.4/r1466_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1466_scriptdev2.sql rename to sql/updates/0.0.4/r1466_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1470_scriptdev2.sql b/sql/updates/0.0.4/r1470_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1470_scriptdev2.sql rename to sql/updates/0.0.4/r1470_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1473_scriptdev2.sql b/sql/updates/0.0.4/r1473_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1473_scriptdev2.sql rename to sql/updates/0.0.4/r1473_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1474_scriptdev2.sql b/sql/updates/0.0.4/r1474_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1474_scriptdev2.sql rename to sql/updates/0.0.4/r1474_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1476_mangos.sql b/sql/updates/0.0.4/r1476_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1476_mangos.sql rename to sql/updates/0.0.4/r1476_mangos.sql diff --git a/sql/Updates/0.0.4/r1476_scriptdev2.sql b/sql/updates/0.0.4/r1476_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1476_scriptdev2.sql rename to sql/updates/0.0.4/r1476_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1478_scriptdev2.sql b/sql/updates/0.0.4/r1478_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1478_scriptdev2.sql rename to sql/updates/0.0.4/r1478_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1481_scriptdev2.sql b/sql/updates/0.0.4/r1481_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1481_scriptdev2.sql rename to sql/updates/0.0.4/r1481_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1486_mangos.sql b/sql/updates/0.0.4/r1486_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1486_mangos.sql rename to sql/updates/0.0.4/r1486_mangos.sql diff --git a/sql/Updates/0.0.4/r1490_scriptdev2.sql b/sql/updates/0.0.4/r1490_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1490_scriptdev2.sql rename to sql/updates/0.0.4/r1490_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1492_mangos.sql b/sql/updates/0.0.4/r1492_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1492_mangos.sql rename to sql/updates/0.0.4/r1492_mangos.sql diff --git a/sql/Updates/0.0.4/r1493_scriptdev2.sql b/sql/updates/0.0.4/r1493_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1493_scriptdev2.sql rename to sql/updates/0.0.4/r1493_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1494_mangos.sql b/sql/updates/0.0.4/r1494_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1494_mangos.sql rename to sql/updates/0.0.4/r1494_mangos.sql diff --git a/sql/Updates/0.0.4/r1496_mangos.sql b/sql/updates/0.0.4/r1496_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1496_mangos.sql rename to sql/updates/0.0.4/r1496_mangos.sql diff --git a/sql/Updates/0.0.4/r1498_mangos.sql b/sql/updates/0.0.4/r1498_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1498_mangos.sql rename to sql/updates/0.0.4/r1498_mangos.sql diff --git a/sql/Updates/0.0.4/r1500_mangos.sql b/sql/updates/0.0.4/r1500_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1500_mangos.sql rename to sql/updates/0.0.4/r1500_mangos.sql diff --git a/sql/Updates/0.0.4/r1502_mangos.sql b/sql/updates/0.0.4/r1502_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1502_mangos.sql rename to sql/updates/0.0.4/r1502_mangos.sql diff --git a/sql/Updates/0.0.4/r1503_scriptdev2.sql b/sql/updates/0.0.4/r1503_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1503_scriptdev2.sql rename to sql/updates/0.0.4/r1503_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1504_scriptdev2.sql b/sql/updates/0.0.4/r1504_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1504_scriptdev2.sql rename to sql/updates/0.0.4/r1504_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1506_scriptdev2.sql b/sql/updates/0.0.4/r1506_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1506_scriptdev2.sql rename to sql/updates/0.0.4/r1506_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1508_mangos.sql b/sql/updates/0.0.4/r1508_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1508_mangos.sql rename to sql/updates/0.0.4/r1508_mangos.sql diff --git a/sql/Updates/0.0.4/r1513_scriptdev2.sql b/sql/updates/0.0.4/r1513_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1513_scriptdev2.sql rename to sql/updates/0.0.4/r1513_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1516_mangos.sql b/sql/updates/0.0.4/r1516_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1516_mangos.sql rename to sql/updates/0.0.4/r1516_mangos.sql diff --git a/sql/Updates/0.0.4/r1516_scriptdev2.sql b/sql/updates/0.0.4/r1516_scriptdev2.sql similarity index 98% rename from sql/Updates/0.0.4/r1516_scriptdev2.sql rename to sql/updates/0.0.4/r1516_scriptdev2.sql index 9ec1cf2abc..400b693040 100644 --- a/sql/Updates/0.0.4/r1516_scriptdev2.sql +++ b/sql/updates/0.0.4/r1516_scriptdev2.sql @@ -1,2 +1 @@ UPDATE script_texts SET comment='sladran SAY_SUMMON_CONSTRICTOR' WHERE entry=-1604002; - \ No newline at end of file diff --git a/sql/Updates/0.0.4/r1517_scriptdev2.sql b/sql/updates/0.0.4/r1517_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1517_scriptdev2.sql rename to sql/updates/0.0.4/r1517_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1519_mangos.sql b/sql/updates/0.0.4/r1519_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1519_mangos.sql rename to sql/updates/0.0.4/r1519_mangos.sql diff --git a/sql/Updates/0.0.4/r1523_mangos.sql b/sql/updates/0.0.4/r1523_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1523_mangos.sql rename to sql/updates/0.0.4/r1523_mangos.sql diff --git a/sql/Updates/0.0.4/r1524_scriptdev2.sql b/sql/updates/0.0.4/r1524_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1524_scriptdev2.sql rename to sql/updates/0.0.4/r1524_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1525_mangos.sql b/sql/updates/0.0.4/r1525_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1525_mangos.sql rename to sql/updates/0.0.4/r1525_mangos.sql diff --git a/sql/Updates/0.0.4/r1525_scriptdev2.sql b/sql/updates/0.0.4/r1525_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1525_scriptdev2.sql rename to sql/updates/0.0.4/r1525_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1531_mangos.sql b/sql/updates/0.0.4/r1531_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1531_mangos.sql rename to sql/updates/0.0.4/r1531_mangos.sql diff --git a/sql/Updates/0.0.4/r1536_mangos.sql b/sql/updates/0.0.4/r1536_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1536_mangos.sql rename to sql/updates/0.0.4/r1536_mangos.sql diff --git a/sql/Updates/0.0.4/r1538_mangos.sql b/sql/updates/0.0.4/r1538_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1538_mangos.sql rename to sql/updates/0.0.4/r1538_mangos.sql diff --git a/sql/Updates/0.0.4/r1540_mangos.sql b/sql/updates/0.0.4/r1540_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1540_mangos.sql rename to sql/updates/0.0.4/r1540_mangos.sql diff --git a/sql/Updates/0.0.4/r1540_scriptdev2.sql b/sql/updates/0.0.4/r1540_scriptdev2.sql similarity index 100% rename from sql/Updates/0.0.4/r1540_scriptdev2.sql rename to sql/updates/0.0.4/r1540_scriptdev2.sql diff --git a/sql/Updates/0.0.4/r1542_mangos.sql b/sql/updates/0.0.4/r1542_mangos.sql similarity index 100% rename from sql/Updates/0.0.4/r1542_mangos.sql rename to sql/updates/0.0.4/r1542_mangos.sql 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 90% rename from sql/Updates/r1632_mangos.sql rename to sql/updates/0.6/r1632_mangos.sql index 3fe6ca9650..4818b1a286 100644 --- a/sql/Updates/r1632_mangos.sql +++ b/sql/updates/0.6/r1632_mangos.sql @@ -3,7 +3,7 @@ UPDATE creature_template SET ScriptName='boss_gormok' WHERE entry=34796; UPDATE creature_template SET ScriptName='boss_acidmaw' WHERE entry=35144; UPDATE creature_template SET ScriptName='boss_dreadscale' WHERE entry=34799; UPDATE creature_template SET ScriptName='boss_icehowl' WHERE entry=34797; -UPDATE creature_template SET ScriptName='boss_jaraxxis' WHERE entry=34780; +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; 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 97% rename from sql/Updates/r1647_scriptdev2.sql rename to sql/updates/0.6/r1647_scriptdev2.sql index de5dc6b960..32164dbe7f 100644 --- a/sql/Updates/r1647_scriptdev2.sql +++ b/sql/updates/0.6/r1647_scriptdev2.sql @@ -7,7 +7,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000565,'Brave adventurer, thank you for rescuing me! I am sure Marshal Marris will reward your kind deed.',0,0,0,0,'SAY_CORPORAL_KEESHAN_5'); DELETE FROM script_waypoint WHERE entry = 349; -INSERT INTO script_waypoint VALUES +INSERT INTO script_waypoint VALUES (349, 01, -8769.591797, -2185.733643, 141.974564, 0, ''), (349, 02, -8776.540039, -2193.782959, 140.960159, 0, ''), (349, 03, -8783.289063, -2194.818604, 140.461731, 0, ''), @@ -26,7 +26,7 @@ INSERT INTO script_waypoint VALUES (349, 16, -8741.869141, -2250.997070, 154.485718, 0, ''), (349, 17, -8733.218750, -2251.010742, 154.360031, 0, ''), (349, 18, -8717.474609, -2245.044678, 154.68614, 0, ''), -(349, 19, -8712.240234, -2246.826172, 154.709473, 0, ''), +(349, 19, -8712.240234, -2246.826172, 154.709473, 0, ''), (349, 20, -8693.840820, -2240.410889, 152.909714, 0, ''), (349, 21, -8681.818359, -2245.332764, 155.517838, 0, ''), (349, 22, -8669.86, -2252.77, 154.854, 0, ''), 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 98% rename from sql/Updates/r1651_scriptdev2.sql rename to sql/updates/0.6/r1651_scriptdev2.sql index dcd8eccd81..3efb21efcf 100644 --- a/sql/Updates/r1651_scriptdev2.sql +++ b/sql/updates/0.6/r1651_scriptdev2.sql @@ -1,2 +1 @@ UPDATE script_texts SET content_default='Ah, fresh air, at last! I need a moment to rest.' WHERE entry=-1000562; - diff --git a/sql/Updates/r1652_scriptdev2.sql b/sql/updates/0.6/r1652_scriptdev2.sql similarity index 98% rename from sql/Updates/r1652_scriptdev2.sql rename to sql/updates/0.6/r1652_scriptdev2.sql index 658774eafa..2eb23cd2e6 100644 --- a/sql/Updates/r1652_scriptdev2.sql +++ b/sql/updates/0.6/r1652_scriptdev2.sql @@ -1,3 +1,2 @@ UPDATE script_texts SET content_default='%s raises more skeletons!' WHERE entry=-1533131; UPDATE script_texts SET content_default='%s teleports to the balcony above!' WHERE entry=-1533132; - 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 94% rename from sql/Updates/r1720_scriptdev2.sql rename to sql/updates/0.6/r1720_scriptdev2.sql index 77acd0c522..92dd0fe746 100644 --- a/sql/Updates/r1720_scriptdev2.sql +++ b/sql/updates/0.6/r1720_scriptdev2.sql @@ -1,5 +1,5 @@ DELETE FROM script_waypoint WHERE entry=20415; -INSERT INTO script_waypoint VALUES +INSERT INTO script_waypoint VALUES (20415, 0, 2488.77, 2184.89, 104.64, 0, ""), (20415, 1, 2478.72, 2184.77, 98.58, 0, ""), (20415, 2, 2473.52, 2184.71, 99.00, 0, ""), 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/0.6/r1843_mangos.sql b/sql/updates/0.6/r1843_mangos.sql new file mode 100644 index 0000000000..95d916b8fc --- /dev/null +++ b/sql/updates/0.6/r1843_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=32149; diff --git a/sql/updates/0.6/r1843_scriptdev2.sql b/sql/updates/0.6/r1843_scriptdev2.sql new file mode 100644 index 0000000000..a6a8876aae --- /dev/null +++ b/sql/updates/0.6/r1843_scriptdev2.sql @@ -0,0 +1,7 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000598 AND -1000594; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000594,'At last... now I can rest.',0,0,0,0,'hero spirit SAY_BLESS_1'), +(-1000595,'I\'m so tired. Just let me rest for a moment.',0,0,0,0,'hero spirit SAY_BLESS_2'), +(-1000596,'I can\'t hear the screams anymore. Is this the end?',0,0,0,0,'hero spirit SAY_BLESS_3'), +(-1000597,'My nightmare, is it finally over?',0,0,0,0,'hero spirit SAY_BLESS_4'), +(-1000598,'It was awful... I dreamt I was fighting against my friends.',0,0,0,0,'hero spirit SAY_BLESS_5'); 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/0.6/r1878_mangos.sql b/sql/updates/0.6/r1878_mangos.sql new file mode 100644 index 0000000000..0e337f24ac --- /dev/null +++ b/sql/updates/0.6/r1878_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (29330,29338,29329); 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/0.6/r1886_scriptdev2.sql b/sql/updates/0.6/r1886_scriptdev2.sql new file mode 100644 index 0000000000..20a4bba17f --- /dev/null +++ b/sql/updates/0.6/r1886_scriptdev2.sql @@ -0,0 +1,2 @@ +DELETE FROM sd2_db_version; +INSERT INTO sd2_db_version (version) VALUES ('ScriptDev2 (for MaNGOS 10761+) '); diff --git a/sql/updates/0.6/r1888_mangos.sql b/sql/updates/0.6/r1888_mangos.sql new file mode 100644 index 0000000000..ec9325985b --- /dev/null +++ b/sql/updates/0.6/r1888_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_zeppit' WHERE entry=22484; diff --git a/sql/updates/0.6/r1888_scriptdev2.sql b/sql/updates/0.6/r1888_scriptdev2.sql new file mode 100644 index 0000000000..e51dc09406 --- /dev/null +++ b/sql/updates/0.6/r1888_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1000625; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000625,'%s gathers the warp chaser\'s blood.',0,2,0,0,'zeppit EMOTE_GATHER_BLOOD'); diff --git a/sql/updates/0.6/r1889_mangos.sql b/sql/updates/0.6/r1889_mangos.sql new file mode 100644 index 0000000000..ec06a37b03 --- /dev/null +++ b/sql/updates/0.6/r1889_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_depleted_war_golem' WHERE entry=27017; diff --git a/sql/updates/0.6/r1889_scriptdev2.sql b/sql/updates/0.6/r1889_scriptdev2.sql new file mode 100644 index 0000000000..4bbccf052f --- /dev/null +++ b/sql/updates/0.6/r1889_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1000626,-1000627); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000626,'Intiating energy collection.',0,0,0,0,'depleted golem SAY_GOLEM_CHARGE'), +(-1000627,'Energy collection complete.',0,0,0,0,'depleted golem SAY_GOLEM_COMPLETE'); diff --git a/sql/updates/0.6/r1890_mangos.sql b/sql/updates/0.6/r1890_mangos.sql new file mode 100644 index 0000000000..234e7c45ac --- /dev/null +++ b/sql/updates/0.6/r1890_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_hungry_nether_ray' WHERE entry=23439; diff --git a/sql/updates/0.6/r1890_scriptdev2.sql b/sql/updates/0.6/r1890_scriptdev2.sql new file mode 100644 index 0000000000..beaab0918e --- /dev/null +++ b/sql/updates/0.6/r1890_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1000628; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000628,'%s feeds on the freshly-killed warp chaser.',0,2,0,0,'hungry ray EMOTE_FEED'); diff --git a/sql/updates/0.6/r1891_mangos.sql b/sql/updates/0.6/r1891_mangos.sql new file mode 100644 index 0000000000..64d9d08250 --- /dev/null +++ b/sql/updates/0.6/r1891_mangos.sql @@ -0,0 +1,8 @@ +UPDATE creature_template SET ScriptName='npc_totem_of_spirits' WHERE entry=21071; + +DELETE FROM scripted_event_id WHERE id IN (13513,13514,13515,13516); +INSERT INTO scripted_event_id VALUES +(13513,'event_spell_soul_captured_credit'), +(13514,'event_spell_soul_captured_credit'), +(13515,'event_spell_soul_captured_credit'), +(13516,'event_spell_soul_captured_credit'); diff --git a/sql/updates/0.6/r1899_mangos.sql b/sql/updates/0.6/r1899_mangos.sql new file mode 100644 index 0000000000..ac86c61ee9 --- /dev/null +++ b/sql/updates/0.6/r1899_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_greer_orehammer' WHERE entry=23859; diff --git a/sql/updates/0.6/r1899_scriptdev2.sql b/sql/updates/0.6/r1899_scriptdev2.sql new file mode 100644 index 0000000000..01f1e22f8a --- /dev/null +++ b/sql/updates/0.6/r1899_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM gossip_texts WHERE entry BETWEEN -3000108 AND -3000106; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-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'); diff --git a/sql/updates/0.6/r1908_scriptdev2.sql b/sql/updates/0.6/r1908_scriptdev2.sql new file mode 100644 index 0000000000..513dcf3f95 --- /dev/null +++ b/sql/updates/0.6/r1908_scriptdev2.sql @@ -0,0 +1,12 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1554005 AND -1554000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1554000,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554001,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554002,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-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'); + +DELETE FROM gossip_texts WHERE entry=-3000102; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000102,'Pay up, Harry!','silvermoon harry GOSSIP_ITEM_PAYING'); diff --git a/sql/updates/0.6/r1913_mangos.sql b/sql/updates/0.6/r1913_mangos.sql new file mode 100644 index 0000000000..2224fb8ed3 --- /dev/null +++ b/sql/updates/0.6/r1913_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_lab_work_reagents' WHERE entry IN (190462, 190473, 190478, 190459); diff --git a/sql/updates/0.6/r1914_scriptdev2.sql b/sql/updates/0.6/r1914_scriptdev2.sql new file mode 100644 index 0000000000..93ec87b2a5 --- /dev/null +++ b/sql/updates/0.6/r1914_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 10928+) '; diff --git a/sql/updates/0.6/r1918_scriptdev2.sql b/sql/updates/0.6/r1918_scriptdev2.sql new file mode 100644 index 0000000000..e91c9f2488 --- /dev/null +++ b/sql/updates/0.6/r1918_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 10938+) '; diff --git a/sql/updates/0.6/r1921_scriptdev2.sql b/sql/updates/0.6/r1921_scriptdev2.sql new file mode 100644 index 0000000000..385d496496 --- /dev/null +++ b/sql/updates/0.6/r1921_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 10950+) '; diff --git a/sql/updates/0.6/r1924_mangos.sql b/sql/updates/0.6/r1924_mangos.sql new file mode 100644 index 0000000000..a2d143f365 --- /dev/null +++ b/sql/updates/0.6/r1924_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_grobbulus' WHERE entry=15931; diff --git a/sql/updates/0.6/r1924_scriptdev2.sql b/sql/updates/0.6/r1924_scriptdev2.sql new file mode 100644 index 0000000000..36d342010d --- /dev/null +++ b/sql/updates/0.6/r1924_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1533158; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1533158,'%s injects you with a mutagen!',0,5,0,0,'grobbulus EMOTE_INJECTION'); diff --git a/sql/updates/0.6/r1936_mangos.sql b/sql/updates/0.6/r1936_mangos.sql new file mode 100644 index 0000000000..c336c9b5a1 --- /dev/null +++ b/sql/updates/0.6/r1936_mangos.sql @@ -0,0 +1 @@ +UPDATE instance_template SET ScriptName='instance_blackwing_lair' WHERE map=469; diff --git a/sql/updates/0.6/r1940_mangos.sql b/sql/updates/0.6/r1940_mangos.sql new file mode 100644 index 0000000000..e3966d4339 --- /dev/null +++ b/sql/updates/0.6/r1940_mangos.sql @@ -0,0 +1,3 @@ +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; diff --git a/sql/updates/0.6/r1946_scriptdev2.sql b/sql/updates/0.6/r1946_scriptdev2.sql new file mode 100644 index 0000000000..e7537c5f54 --- /dev/null +++ b/sql/updates/0.6/r1946_scriptdev2.sql @@ -0,0 +1,9 @@ +UPDATE script_texts SET type=6 WHERE entry=-1409004; + +DELETE FROM script_texts WHERE entry IN (-1409007, -1409019, -1409020, -1409021, -1409022); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1409007,'Impossible! Stay your attack mortals! I submitt! I submitt!',8038,1,0,0,'majordomo SAY_DEFEAT_1'), +(-1409019,'You think you\'ve won already? Perhaps you\'ll need another lesson in pain!',0,1,0,0,'majordomo SAY_LAST_ADD'), +(-1409020,'Brashly you have come to rest the secrets of the living flame. You will soon regret the recklessness of your quest.',0,1,0,0,'majordomo SAY_DEFEAT_2'), +(-1409021,'I go now to summon the lord whos house this is. Should you seek an audiance with him your paltry lives will surly be forfit. Nevertheless seek out his lair if you dare!',0,1,0,0,'majordomo SAY_DEFEAT_3'), +(-1409022,'My flame! Please don\'t take away my flame... ',8042,1,0,0,'ragnaros SAY_ARRIVAL4_MAJ'); diff --git a/sql/updates/0.6/r1949_scriptdev2.sql b/sql/updates/0.6/r1949_scriptdev2.sql new file mode 100644 index 0000000000..b6db02804f --- /dev/null +++ b/sql/updates/0.6/r1949_scriptdev2.sql @@ -0,0 +1,26 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1043019 AND -1043000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1043000,'At last! Naralex can be awakened! Come aid me, brave adventurers!',0,6,0,0,'Disciple of Naralex - SAY_INTRO'), +(-1043001,'I must make the nescessary preparations before the awakening ritual can begin. You must protect me!',0,0,0,0,'SAY_PREPARE'), +(-1043002,'These caverns were once a temple of promise for regrowth in the Barrens. Now, they are the halls of nightmares.',0,0,0,0,'Disciple of Naralex - SAY_FIRST_CORNER'), +(-1043003,'Come. We must continue. There is much to be done before we can pull Naralex from his nightmare.',0,0,0,0,'Disciple of Naralex - SAY_CONTINUE'), +(-1043004,'Within this circle of fire I must cast the spell to banish the spirits of the slain Fanglords.',0,0,0,0,'Disciple of Naralex - SAY_CIRCLE_BANISH'), +(-1043005,'The caverns have been purified. To Naralex''s chamber we go!',0,0,0,0,'Disciple of Naralex - SAY_PURIFIED'), +(-1043006,'Beyond this corridor, Naralex lies in fitful sleep. Let us go awaken him before it is too late.',0,0,0,0,'Disciple of Naralex - SAY_NARALEX_CHAMBER'), +(-1043007,'Protect me brave souls as I delve into the Emerald Dream to rescue Naralex and put an end to this corruption!',0,1,0,0,'Disciple of Naralex - SAY_BEGIN_RITUAL'), +(-1043008,'%s begins to perform the awakening ritual on Naralex.',0,2,0,0,'Disciple of Naralex - EMOTE_RITUAL_BEGIN'), +(-1043009,'%s tosses fitfully in troubled sleep.',0,2,0,0,'Naralex - EMOTE_NARALEX_AWAKE'), +(-1043010,'%s writhes in agony. The Disciple seems to be breaking through.',0,2,0,0,'Naralex - EMOTE_BREAK_THROUGH'), +(-1043011,'%s dreams up a horrendous vision. Something stirs beneath the murky waters.',0,2,0,0,'Naralex - EMOTE_VISION'), +(-1043012,'This $N is a minin from Naralex\'s nightmare no doubt!.',0,0,0,0,'Disciple of Naralex - SAY_MUTANUS'), +(-1043013,'I AM AWAKE, AT LAST!',5789,1,0,0,'Naralex - SAY_NARALEX_AWAKE'), +(-1043014,'At last! Naralex awakes from the nightmare.',0,0,0,0,'Disciple of Naralex - SAY_AWAKE'), +(-1043015,'Ah, to be pulled from the dreaded nightmare! I thank you, my loyal Disciple, along with your brave companions.',0,0,0,0,'Naralex - SAY_NARALEX_THANKYOU'), +(-1043016,'We must go and gather with the other Disciplies. There is much work to be done before I can make another attempt to restore the Barrens. Farewell, brave souls!',0,0,0,0,'Naralex - SAY_FAREWELL'), +(-1043017,'Attacked! Help get this $N off of me!',0,0,0,0,'Disciple of Naralex - SAY_AGGRO_1'), +(-1043018,'Help!',0,0,0,0,'Disciple of Naralex - SAY_AGGRO_2'), +(-1043019,'Deal with this $N! I need to prepare to awake Naralex!',0,0,0,0,'Disciple of Naralex - SAY_AGGRO_3'); + +DELETE FROM gossip_texts WHERE entry=-3043000; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3043000,'Let the event begin!','Disciple of Naralex - GOSSIP_ITEM_BEGIN'); diff --git a/sql/updates/0.6/r1951_scriptdev2.sql b/sql/updates/0.6/r1951_scriptdev2.sql new file mode 100644 index 0000000000..cff5208e0a --- /dev/null +++ b/sql/updates/0.6/r1951_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1289000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1289000,'School is in session!',0,1,0,0,'gandling SAY_GANDLING_SPAWN'); diff --git a/sql/updates/0.6/r1954_mangos.sql b/sql/updates/0.6/r1954_mangos.sql new file mode 100644 index 0000000000..e4069a0e16 --- /dev/null +++ b/sql/updates/0.6/r1954_mangos.sql @@ -0,0 +1,7 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=10504; +UPDATE creature_template SET ScriptName='' WHERE entry=10505; +UPDATE creature_template SET ScriptName='' WHERE entry=10508; +UPDATE creature_template SET ScriptName='' WHERE entry=10507; +UPDATE creature_template SET ScriptName='' WHERE entry=10502; +UPDATE creature_template SET ScriptName='' WHERE entry=11261; +UPDATE creature_template SET ScriptName='' WHERE entry=10901; diff --git a/sql/updates/0.6/r1962_mangos.sql b/sql/updates/0.6/r1962_mangos.sql new file mode 100644 index 0000000000..7f2690d22d --- /dev/null +++ b/sql/updates/0.6/r1962_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_isla_starmane' WHERE entry=18760; diff --git a/sql/updates/0.6/r1962_scriptdev2.sql b/sql/updates/0.6/r1962_scriptdev2.sql new file mode 100644 index 0000000000..f3e6968277 --- /dev/null +++ b/sql/updates/0.6/r1962_scriptdev2.sql @@ -0,0 +1,79 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000634 AND -1000629; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000629,' Damsel in distress over here!',0,0,0,0,'isla starmane - SAY_ISLA_PERIODIC_1'), +(-1000630,'Hello? Help?',0,0,0,0,'isla starmane - SAY_ISLA_PERIODIC_2'), +(-1000631,'Don''t leave me in here! Cause if you do I will find you!',0,0,0,0,'isla starmane - SAY_ISLA_PERIODIC_3'), +(-1000632,'Ok, let''s get out of here!',0,0,0,0,'isla starmane - SAY_ISLA_START'), +(-1000633,'You sure you''re ready? Take a moment.',0,0,0,0,'isla starmane - SAY_ISLA_WAITING'), +(-1000634,'Alright, let''s do this!',0,0,0,0,'isla starmane - SAY_ISLA_LEAVE_BUILDING'); + +DELETE FROM script_waypoint WHERE entry = 18760; +INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, waittime, point_comment) VALUES +(18760, 01, -2267.07, 3091.46, 13.8271, 0, ''), +(18760, 02, -2270.92, 3094.19, 13.8271, 0, ''), +(18760, 03, -2279.08, 3100.04, 13.8271, 0, ''), +(18760, 04, -2290.05, 3105.07, 13.8271, 0, ''), +(18760, 05, -2297.64, 3112.32, 13.8271, 0, ''), +(18760, 06, -2303.89, 3118.22, 13.8231, 10000, 'building exit'), +(18760, 07, -2307.77, 3123.47, 13.7257, 0, ''), +(18760, 08, -2310.67, 3126.2, 12.5841, 0, ''), +(18760, 09, -2311.48, 3126.98, 12.2769, 0, ''), +(18760, 10, -2316.91, 3132.13, 11.9261, 0, ''), +(18760, 11, -2320.43, 3135.54, 11.7436, 0, ''), +(18760, 12, -2327.38, 3139.36, 10.9431, 0, ''), +(18760, 13, -2332.02, 3142.05, 9.81277, 0, ''), +(18760, 14, -2338.21, 3145.32, 9.31001, 0, ''), +(18760, 15, -2343.1, 3148.91, 8.84879, 0, ''), +(18760, 16, -2347.76, 3153.15, 7.71049, 0, ''), +(18760, 17, -2351.04, 3156.12, 6.66476, 0, ''), +(18760, 18, -2355.15, 3163.18, 5.11997, 0, ''), +(18760, 19, -2359.01, 3169.83, 3.64343, 0, ''), +(18760, 20, -2364.85, 3176.81, 2.32802, 0, ''), +(18760, 21, -2368.77, 3181.69, 1.53285, 0, ''), +(18760, 22, -2371.76, 3185.11, 0.979932, 0, ''), +(18760, 23, -2371.85, 3191.89, -0.293048, 0, ''), +(18760, 24, -2370.99, 3199.6, -1.10504, 0, 'turn left 1'), +(18760, 25, -2376.24, 3205.54, -1.04152, 0, ''), +(18760, 26, -2380.99, 3211.61, -1.16891, 0, ''), +(18760, 27, -2384.04, 3218.4, -1.15279, 0, ''), +(18760, 28, -2385.41, 3226.22, -1.23403, 0, ''), +(18760, 29, -2386.02, 3233.89, -1.31723, 0, ''), +(18760, 30, -2384.7, 3239.82, -1.51903, 0, ''), +(18760, 31, -2382.98, 3247.94, -1.39163, 0, ''), +(18760, 32, -2379.68, 3254.22, -1.25927, 0, ''), +(18760, 33, -2375.27, 3259.69, -1.22925, 0, ''), +(18760, 34, -2369.62, 3264.55, -1.1879, 0, ''), +(18760, 35, -2364.01, 3268.32, -1.48348, 0, ''), +(18760, 36, -2356.61, 3272.31, -1.5505, 0, ''), +(18760, 37, -2352.3, 3274.63, -1.35693, 0, ''), +(18760, 38, -2348.54, 3278.04, -1.04161, 0, 'turn left 2'), +(18760, 39, -2347.56, 3282.41, -0.75979, 0, ''), +(18760, 40, -2348.29, 3288.91, -0.63215, 0, ''), +(18760, 41, -2349.68, 3298.84, -1.07864, 0, ''), +(18760, 42, -2351.15, 3308.52, -1.38864, 0, ''), +(18760, 43, -2352.2, 3317.14, -1.59873, 0, ''), +(18760, 44, -2351.59, 3325.51, -1.92624, 0, ''), +(18760, 45, -2350.88, 3333.38, -2.32506, 0, ''), +(18760, 46, -2350.05, 3342.68, -2.51886, 0, ''), +(18760, 47, -2350.12, 3347.32, -2.57528, 0, ''), +(18760, 48, -2348.72, 3353.7, -2.72689, 0, ''), +(18760, 49, -2346.53, 3360.85, -2.9756, 0, ''), +(18760, 50, -2344.83, 3365.46, -3.3311, 0, ''), +(18760, 51, -2342.68, 3368.91, -3.74526, 0, ''), +(18760, 52, -2340.25, 3371.44, -4.10499, 0, ''), +(18760, 53, -2337.4, 3373.47, -4.44362, 0, ''), +(18760, 54, -2332.68, 3376.02, -5.19648, 0, ''), +(18760, 55, -2326.69, 3379.64, -6.24757, 0, ''), +(18760, 56, -2321.2, 3383.98, -7.28247, 0, ''), +(18760, 57, -2317.81, 3387.78, -8.40093, 0, ''), +(18760, 58, -2315.3, 3392.47, -9.63431, 0, ''), +(18760, 59, -2314.69, 3396.6, -10.2031, 0, ''), +(18760, 60, -2315.48, 3402.35, -10.8211, 0, 'gate'), +(18760, 61, -2317.55, 3409.27, -11.3309, 5000, 'Firewing point exit'), +(18760, 62, -2320.69, 3412.99, -11.5207, 0, ''), +(18760, 63, -2326.88, 3417.89, -11.6105, 0, ''), +(18760, 64, -2332.73, 3421.74, -11.5659, 0, ''), +(18760, 65, -2337.23, 3424.89, -11.496, 0, ''), +(18760, 66, -2339.57, 3429.17, -11.3782, 0, ''), +(18760, 67, -2341.66, 3435.86, -11.3746, 5000, 'Wave and transform'), +(18760, 68, -2342.15, 3443.94, -11.2562, 2000, 'final destination'); diff --git a/sql/updates/0.6/r1963_scriptdev2.sql b/sql/updates/0.6/r1963_scriptdev2.sql new file mode 100644 index 0000000000..aa133cc21a --- /dev/null +++ b/sql/updates/0.6/r1963_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11105+) '; diff --git a/sql/updates/0.6/r1965_mangos.sql b/sql/updates/0.6/r1965_mangos.sql new file mode 100644 index 0000000000..747fa17599 --- /dev/null +++ b/sql/updates/0.6/r1965_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_blastmaster_emi_shortfuse' WHERE entry=7998; diff --git a/sql/updates/0.6/r1965_scriptdev2.sql b/sql/updates/0.6/r1965_scriptdev2.sql new file mode 100644 index 0000000000..43252b39c5 --- /dev/null +++ b/sql/updates/0.6/r1965_scriptdev2.sql @@ -0,0 +1,52 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1090023 AND -1090000 OR entry=-1090028; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1090000,'With your help, I can evaluate these tunnels.',0,0,0,1,'emi shortfuse SAY_START'), +(-1090001,'Let\'s see if we can find out where these Troggs are coming from.... and put a stop to the invasion!',0,0,0,1,'emi shortfuse SAY_INTRO_1'), +(-1090002,'Such devastation... what a horrible mess...',0,0,0,5,'emi shortfuse SAY_INTRO_2'), +(-1090003,'It\'s quiet here....',0,0,0,1,'emi shortfuse SAY_INTRO_3'), +(-1090004,'...too quiet.',0,0,0,1,'emi shortfuse SAY_INTRO_4'), +(-1090005,'Look! Over there at the tunnel wall!',0,0,0,25,'emi shortfuse SAY_LOOK_1'), +(-1090006,'Trogg incursion! Defend me while I blast the hole closed!',0,0,0,5,'emi shortfuse SAY_HEAR_1'), +(-1090007,'Get this, $n off of me!',0,0,0,0,'emi shortfuse SAY_AGGRO_1'), +(-1090008,'I don\'t think one charge is going to cut it. Keep fending them off!',0,0,0,0,'emi shortfuse SAY_CHARGE_1'), +(-1090009,'The charges are set. Get back before they blow!',0,0,0,5,'emi shortfuse SAY_CHARGE_2'), +(-1090010,'Incoming blast in 10 seconds!',0,1,0,5,'emi shortfuse SAY_BLOW_1_10'), +(-1090011,'Incoming blast in 5 seconds. Clear the tunnel! Stay back!',0,1,0,5,'emi shortfuse SAY_BLOW_1_5'), +(-1090012,'FIRE IN THE HOLE!',0,1,0,25,'emi shortfuse SAY_BLOW_1'), +(-1090013,'Well done! Without your help I would have never been able to thwart that wave of troggs.',0,0,0,4,'emi shortfuse SAY_FINISH_1'), +(-1090014,'Did you hear something?',0,0,0,6,'emi shortfuse SAY_LOOK_2'), +(-1090015,'I heard something over there.',0,0,0,25,'emi shortfuse SAY_HEAR_2'), +(-1090016,'More troggs! Ward them off as I prepare the explosives!',0,0,0,0,'emi shortfuse SAY_CHARGE_3'), +(-1090017,'The final charge is set. Stand back!',0,0,0,1,'emi shortfuse SAY_CHARGE_4'), +(-1090018,'10 seconds to blast! Stand back!!!',0,1,0,5,'emi shortfuse SAY_BLOW_2_10'), +(-1090019,'5 seconds until detonation!!!!!',0,1,0,5,'emi shortfuse SAY_BLOW_2_5'), +(-1090020,'Nice work! I\'ll set off the charges to prevent any more troggs from making it to the surface.',0,0,0,1,'emi shortfuse SAY_BLOW_SOON'), +(-1090021,'FIRE IN THE HOLE!',0,1,0,0,'emi shortfuse SAY_BLOW_2'), +(-1090022,'Superb! Because of your help, my people stand a chance of re-taking our beloved city. Three cheers to you!',0,0,0,0,'emi shortfuse SAY_FINISH_2'), + +(-1090023,'We come from below! You can never stop us!',0,1,0,1,'grubbis SAY_GRUBBIS_SPAWN'), + +(-1090028,'$n attacking! Help!',0,0,0,0,'emi shortfuse SAY_AGGRO_2'); + + +DELETE FROM script_waypoint WHERE entry=7998; +INSERT INTO script_waypoint VALUES +(7998, 01, -510.1305, -132.6899, -152.5, 0, ''), +(7998, 02, -511.0994, -129.74, -153.8453, 0, ''), +(7998, 03, -511.7897, -127.4764, -155.5505, 0, ''), +(7998, 04, -512.9688, -124.926, -156.1146, 5000, ''), +(7998, 05, -513.9719, -120.2358, -156.1161, 0, ''), +(7998, 06, -514.3875, -115.1896, -156.1165, 0, ''), +(7998, 07, -514.3039, -111.4777, -155.5205, 0, ''), +(7998, 08, -514.8401, -107.6633, -154.8925, 0, ''), +(7998, 09, -518.9943, -101.4161, -154.6482, 27000, ''), +(7998, 10, -526.9984, -98.14884, -155.6253, 0, ''), +(7998, 11, -534.5686, -105.4101, -155.989, 30000, ''), +(7998, 12, -535.5336, -104.6947, -155.9713, 0, ''), +(7998, 13, -541.6304, -98.6583, -155.8584, 25000, ''), +(7998, 14, -535.0923, -99.91748, -155.9742, 0, ''), +(7998, 15, -519.0099, -101.5097, -154.6766, 3000, ''), +(7998, 16, -504.4659, -97.84802, -150.9554, 30000, ''), +(7998, 17, -506.9069, -89.14736, -151.083, 23000, ''), +(7998, 18, -512.7576, -101.9025, -153.198, 0, ''), +(7998, 19, -519.9883, -124.8479, -156.128, 86400000, 'this npc should not reset on wp end'); diff --git a/sql/updates/0.6/r1968_scriptdev2.sql b/sql/updates/0.6/r1968_scriptdev2.sql new file mode 100644 index 0000000000..59d70c7db9 --- /dev/null +++ b/sql/updates/0.6/r1968_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11109+) '; diff --git a/sql/updates/0.6/r1972_scriptdev2.sql b/sql/updates/0.6/r1972_scriptdev2.sql new file mode 100644 index 0000000000..7ce51a10c9 --- /dev/null +++ b/sql/updates/0.6/r1972_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11126+) '; diff --git a/sql/updates/0.6/r1973_mangos.sql b/sql/updates/0.6/r1973_mangos.sql new file mode 100644 index 0000000000..a39c3f4f5e --- /dev/null +++ b/sql/updates/0.6/r1973_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (28465,28600); diff --git a/sql/updates/0.6/r1974_mangos.sql b/sql/updates/0.6/r1974_mangos.sql new file mode 100644 index 0000000000..dad7118872 --- /dev/null +++ b/sql/updates/0.6/r1974_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_theldren_trigger' WHERE entry=16079; diff --git a/sql/updates/0.6/r1975_scriptdev2.sql b/sql/updates/0.6/r1975_scriptdev2.sql new file mode 100644 index 0000000000..d14055b974 --- /dev/null +++ b/sql/updates/0.6/r1975_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11136+) '; diff --git a/sql/updates/0.6/r1979_scriptdev2.sql b/sql/updates/0.6/r1979_scriptdev2.sql new file mode 100644 index 0000000000..db7417883c --- /dev/null +++ b/sql/updates/0.6/r1979_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11167+) '; diff --git a/sql/updates/0.6/r1982_mangos.sql b/sql/updates/0.6/r1982_mangos.sql new file mode 100644 index 0000000000..c096be8145 --- /dev/null +++ b/sql/updates/0.6/r1982_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_ichoron' WHERE entry IN (29313,32234); +UPDATE creature_template SET ScriptName='boss_erekem' WHERE entry IN (29315,32226); diff --git a/sql/updates/0.6/r1982_scriptdev2.sql b/sql/updates/0.6/r1982_scriptdev2.sql new file mode 100644 index 0000000000..d6387b97ed --- /dev/null +++ b/sql/updates/0.6/r1982_scriptdev2.sql @@ -0,0 +1,20 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1608026 AND -1608008; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1608008,'Free to--mm--fly now. Ra-aak... Not find us--ekh-ekh! Escape!',14218,1,0,0,'erekem SAY_RELEASE_EREKEM'), +(-1608009,'I... am fury... unrestrained!',14229,1,0,0,'ichoron SAY_RELEASE_ICHORON'), +(-1608010,'Back in business! Now to execute an exit strategy.',14498,1,0,0,'xevozz SAY_RELEASE_XEVOZZ'), +(-1608011,'I am... renewed.',13995,1,0,0,'zuramat SAY_RELEASE_ZURAMAT'), + +(-1608012,'Not--caww--get in way of--rrak-rrak--flee!',14219,1,0,0,'erekem SAY_AGGRO'), +(-1608013,'My---raaak--favorite! Awk awk awk! Raa-kaa!',14220,1,0,0,'erekem SAY_ADD_DIE_1'), +(-1608014,'Nasty little...A-ak,kaw! Kill! Yes,kill you!',14221,1,0,0,'erekem SAY_ADD_DIE_2'), +(-1608018,'No--kaw,kaw--flee...',14225,1,0,0,'erekem SAY_DEATH'), + +(-1608019,'Stand aside, mortals!',14230,1,0,0,'ichoron SAY_AGGRO'), +(-1608020,'I will not be contained! Ngyah!!',14233,1,0,0,'ichoron SAY_SHATTERING'), +(-1608021,'Water can hold any form, take any shape... overcome any obstacle.',14232,1,0,0,'ichoron SAY_SHIELD'), +(-1608022,'I am a force of nature!',14234,1,0,0,'ichoron SAY_SLAY_1'), +(-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'); diff --git a/sql/updates/0.6/r1984_mangos.sql b/sql/updates/0.6/r1984_mangos.sql new file mode 100644 index 0000000000..6429496220 --- /dev/null +++ b/sql/updates/0.6/r1984_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_disciple_of_naralex' WHERE entry=3678; diff --git a/sql/updates/0.6/r1984_scriptdev2.sql b/sql/updates/0.6/r1984_scriptdev2.sql new file mode 100644 index 0000000000..000290adc1 --- /dev/null +++ b/sql/updates/0.6/r1984_scriptdev2.sql @@ -0,0 +1,48 @@ +DELETE FROM script_texts WHERE entry=-1043012; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1043012,'This $N is a minion from Naralex''s nightmare no doubt!.',0,0,0,0,'Disciple of Naralex - SAY_MUTANUS'); + +DELETE FROM script_waypoint WHERE entry=3678; +INSERT INTO script_waypoint VALUES +(3678, 0, -134.925, 125.468, -78.16, 0, ''), +(3678, 1, -125.684, 132.937, -78.42, 0, ''), +(3678, 2, -113.812, 139.295, -80.98, 0, ''), +(3678, 3, -109.854, 157.538, -80.20, 0, ''), +(3678, 4, -108.640, 175.207, -79.74, 0, ''), +(3678, 5, -108.668, 195.457, -80.64, 0, ''), +(3678, 6, -111.007, 219.007, -86.58, 0, ''), +(3678, 7, -102.408, 232.821, -91.52, 0, 'first corner SAY_FIRST_CORNER'), +(3678, 8, -92.434, 227.742, -90.75, 0, ''), +(3678, 9, -82.456, 224.853, -93.57, 0, ''), +(3678, 10, -67.789, 208.073, -93.34, 0, ''), +(3678, 11, -43.343, 205.295, -96.37, 0, ''), +(3678, 12, -34.676, 221.394, -95.82, 0, ''), +(3678, 13, -32.582, 238.573, -93.51, 0, ''), +(3678, 14, -42.149, 258.672, -92.88, 0, ''), +(3678, 15, -55.257, 274.696, -92.83, 0, 'circle of flames SAY_CIRCLE_BANISH'), +(3678, 16, -48.604, 287.584, -92.46, 0, ''), +(3678, 17, -47.236, 296.093, -90.88, 0, ''), +(3678, 18, -35.618, 309.067, -89.73, 0, ''), +(3678, 19, -23.573, 311.376, -88.60, 0, ''), +(3678, 20, -8.692, 302.389, -87.43, 0, ''), +(3678, 21, -1.237, 293.268, -85.55, 0, ''), +(3678, 22, 10.398, 279.294, -85.86, 0, ''), +(3678, 23, 23.108, 264.693, -86.69, 0, ''), +(3678, 24, 31.996, 251.436, -87.62, 0, ''), +(3678, 25, 43.374, 233.073, -87.61, 0, ''), +(3678, 26, 54.438, 212.048, -89.50, 3000, 'chamber entrance SAY_NARALEX_CHAMBER'), +(3678, 27, 78.794, 208.895, -92.84, 0, ''), +(3678, 28, 88.392, 225.231, -94.46, 0, ''), +(3678, 29, 98.758, 233.938, -95.84, 0, ''), +(3678, 30, 107.248, 233.054, -95.98, 0, ''), +(3678, 31, 112.825, 233.907, -96.39, 0, ''), +(3678, 32, 114.634, 236.969, -96.04, 1000, 'naralex SAY_BEGIN_RITUAL'), +(3678, 33, 127.385, 252.279, -90.07, 0, ''), +(3678, 34, 121.595, 264.488, -91.55, 0, ''), +(3678, 35, 115.472, 264.253, -91.50, 0, ''), +(3678, 36, 99.988, 252.790, -91.51, 0, ''), +(3678, 37, 96.347, 245.038, -90.34, 0, ''), +(3678, 38, 82.201, 216.273, -86.10, 0, ''), +(3678, 39, 75.112, 206.494, -84.80, 0, ''), +(3678, 40, 27.174, 201.064, -72.31, 0, ''), +(3678, 41, -41.114, 204.149, -78.94, 0, ''); diff --git a/sql/updates/0.6/r1987_mangos.sql b/sql/updates/0.6/r1987_mangos.sql new file mode 100644 index 0000000000..730dbf767e --- /dev/null +++ b/sql/updates/0.6/r1987_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE npcflag=npcflag|65536; diff --git a/sql/updates/0.6/r1990_mangos.sql b/sql/updates/0.6/r1990_mangos.sql new file mode 100644 index 0000000000..3207052c52 --- /dev/null +++ b/sql/updates/0.6/r1990_mangos.sql @@ -0,0 +1,4 @@ +DELETE FROM scripted_areatrigger WHERE entry=4778; +INSERT INTO scripted_areatrigger VALUES (4778,'at_ancient_male_vrykul'); + +UPDATE creature_template SET ScriptName='npc_ancient_male_vrykul' WHERE entry=24314; diff --git a/sql/updates/0.6/r1990_scriptdev2.sql b/sql/updates/0.6/r1990_scriptdev2.sql new file mode 100644 index 0000000000..bc0eaef2cd --- /dev/null +++ b/sql/updates/0.6/r1990_scriptdev2.sql @@ -0,0 +1,9 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000641 AND -1000635; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000635,'So then we too are cursed?',0,0,0,0,'ancient vrykul SAY_VRYKUL_CURSED'), +(-1000636,'%s points to the infant.',0,2,0,0,'ancient vrykul EMOTE_VRYKUL_POINT'), +(-1000637,'%s sobs.',0,2,0,0,'ancient vrykul EMOTE_VRYKUL_SOB'), +(-1000638,'The gods have forsaken us! We must dispose of it before Ymiron is notified!',0,0,0,0,'ancient vrykul SAY_VRYKUL_DISPOSE'), +(-1000639,'NO! You cannot! I beg of you! It is our child!',0,0,0,0,'ancient vrykul SAY_VRYKUL_BEG'), +(-1000640,'Then what are we to do, wife? The others cannot find out. Should they learn of this aberration, we will all be executed.',0,0,0,0,'ancient vrykul SAY_VRYKUL_WHAT'), +(-1000641,'I... I will hide it. I will hide it until I find it a home, far away from here...',0,0,0,0,'ancient vrykul SAY_VRYKUL_HIDE'); diff --git a/sql/updates/0.6/r1992_mangos.sql b/sql/updates/0.6/r1992_mangos.sql new file mode 100644 index 0000000000..5a068993e4 --- /dev/null +++ b/sql/updates/0.6/r1992_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_service_gate' WHERE entry=175368; diff --git a/sql/updates/0.6/r1992_scriptdev2.sql b/sql/updates/0.6/r1992_scriptdev2.sql new file mode 100644 index 0000000000..5a9bdfefce --- /dev/null +++ b/sql/updates/0.6/r1992_scriptdev2.sql @@ -0,0 +1,10 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1329015 AND -1329008; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1329008,'Intruders at the Service Gate! Lord Rivendare must be warned!',0,6,0,0,'barthilas SAY_WARN_BARON'), +(-1329009,'Intruders! More pawns of the Argent Dawn, no doubt. I already count one of their number among my prisoners. Withdraw from my domain before she is executed!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_START'), +(-1329010,'You\'re still here? Your foolishness is amusing! The Argent Dawn wench needn\'t suffer in vain. Leave at once and she shall be spared!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_10_MIN'), +(-1329011,'I shall take great pleasure in taking this poor wretch\'s life! It\'s not too late, she needn\'t suffer in vain. Turn back and her death shall be merciful!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_5_MIN'), +(-1329012,'May this prisoner\'s death serve as a warning. None shall defy the Scourge and live!',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RUN_FAIL'), +(-1329013,'So you see fit to toy with the Lich King\'s creations? Ramstein, be sure to give the intruders a proper greeting.',0,6,0,0,'baron rivendare SAY_ANNOUNCE_RAMSTEIN'), +(-1329014,'Time to take matters into my own hands. Come. Enter my domain and challenge the might of the Scourge!',0,6,0,0,'baron rivendare SAY_UNDEAD_DEFEAT'), +(-1329015,'You did it... you\'ve slain Baron Rivendare! The Argent Dawn shall hear of your valiant deeds!',0,0,0,0,'ysida SAY_EPILOGUE'); diff --git a/sql/updates/0.6/r1993_mangos.sql b/sql/updates/0.6/r1993_mangos.sql new file mode 100644 index 0000000000..bd6bc356e2 --- /dev/null +++ b/sql/updates/0.6/r1993_mangos.sql @@ -0,0 +1 @@ +UPDATE instance_template SET ScriptName='instance_dire_maul' WHERE map=429; diff --git a/sql/updates/0.6/r1993_scriptdev2.sql b/sql/updates/0.6/r1993_scriptdev2.sql new file mode 100644 index 0000000000..cbe8d234b5 --- /dev/null +++ b/sql/updates/0.6/r1993_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1429000, -1429001); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-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'); diff --git a/sql/updates/0.6/r2004_mangos.sql b/sql/updates/0.6/r2004_mangos.sql new file mode 100644 index 0000000000..63d094a877 --- /dev/null +++ b/sql/updates/0.6/r2004_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_forgemaster_garfrost' WHERE entry=36494; diff --git a/sql/updates/0.6/r2008_mangos.sql b/sql/updates/0.6/r2008_mangos.sql new file mode 100644 index 0000000000..b409b82531 --- /dev/null +++ b/sql/updates/0.6/r2008_mangos.sql @@ -0,0 +1,4 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (3958, 3960); +INSERT INTO scripted_areatrigger VALUES +(3958, 'at_zulgurub'), +(3960, 'at_zulgurub'); diff --git a/sql/updates/0.6/r2008_scriptdev2.sql b/sql/updates/0.6/r2008_scriptdev2.sql new file mode 100644 index 0000000000..81be1d7289 --- /dev/null +++ b/sql/updates/0.6/r2008_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1309022, -1309023); diff --git a/sql/updates/0.6/r2009_mangos.sql b/sql/updates/0.6/r2009_mangos.sql new file mode 100644 index 0000000000..46ff7fd75f --- /dev/null +++ b/sql/updates/0.6/r2009_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_dalinda_malem' WHERE entry=5644; diff --git a/sql/updates/0.6/r2009_scriptdev2.sql b/sql/updates/0.6/r2009_scriptdev2.sql new file mode 100644 index 0000000000..2ea71d9bb8 --- /dev/null +++ b/sql/updates/0.6/r2009_scriptdev2.sql @@ -0,0 +1,21 @@ +DELETE FROM script_waypoint WHERE entry=5644; +INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, waittime, point_comment) VALUES +(5644, 1, -339.679, 1752.04, 139.482, 0, ''), +(5644, 2, -328.957, 1734.95, 139.327, 0, ''), +(5644, 3, -338.29, 1731.36, 139.327, 0, ''), +(5644, 4, -350.747, 1731.12, 139.338, 0, ''), +(5644, 5, -365.064, 1739.04, 139.376, 0, ''), +(5644, 6, -371.105, 1746.03, 139.374, 0, ''), +(5644, 7, -383.141, 1738.62, 138.93, 0, ''), +(5644, 8, -390.445, 1733.98, 136.353, 0, ''), +(5644, 9, -401.368, 1726.77, 131.071, 0, ''), +(5644, 10, -416.016, 1721.19, 129.807, 0, ''), +(5644, 11, -437.139, 1709.82, 126.342, 0, ''), +(5644, 12, -455.83, 1695.61, 119.305, 0, ''), +(5644, 13, -459.862, 1687.92, 116.059, 0, ''), +(5644, 14, -463.565, 1679.1, 111.653, 0, ''), +(5644, 15, -461.485, 1670.94, 109.033, 0, ''), +(5644, 16, -471.786, 1647.34, 102.862, 0, ''), +(5644, 17, -477.146, 1625.69, 98.342, 0, ''), +(5644, 18, -475.815, 1615.815, 97.07, 0, ''), +(5644, 19, -474.329, 1590.01, 94.4982, 0, ''); diff --git a/sql/updates/0.6/r2010_mangos.sql b/sql/updates/0.6/r2010_mangos.sql new file mode 100644 index 0000000000..ebcbec9f13 --- /dev/null +++ b/sql/updates/0.6/r2010_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_hand_of_iruxos_crystal' WHERE entry=176581; diff --git a/sql/updates/0.6/r2013_mangos.sql b/sql/updates/0.6/r2013_mangos.sql new file mode 100644 index 0000000000..fafc022d4b --- /dev/null +++ b/sql/updates/0.6/r2013_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=29327; +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=29319; diff --git a/sql/updates/0.6/r2013_scriptdev2.sql b/sql/updates/0.6/r2013_scriptdev2.sql new file mode 100644 index 0000000000..a6bba7d33e --- /dev/null +++ b/sql/updates/0.6/r2013_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1000642, -1000643); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000642,'It\'s a female.',0,5,0,0,'leopard icepaw SAY_ITS_FEMALE'), +(-1000643,'It\'s an angry male!',0,5,0,0,'leopard icepaw SAY_ITS_MALE'); diff --git a/sql/updates/0.6/r2015_mangos.sql b/sql/updates/0.6/r2015_mangos.sql new file mode 100644 index 0000000000..50c0357b28 --- /dev/null +++ b/sql/updates/0.6/r2015_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=17157; diff --git a/sql/updates/0.6/r2017_mangos.sql b/sql/updates/0.6/r2017_mangos.sql new file mode 100644 index 0000000000..ccb71fb65c --- /dev/null +++ b/sql/updates/0.6/r2017_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=6497; diff --git a/sql/updates/0.6/r2018_scriptdev2.sql b/sql/updates/0.6/r2018_scriptdev2.sql new file mode 100644 index 0000000000..a880c0288a --- /dev/null +++ b/sql/updates/0.6/r2018_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11316+) '; diff --git a/sql/updates/0.6/r2020_scriptdev2.sql b/sql/updates/0.6/r2020_scriptdev2.sql new file mode 100644 index 0000000000..aa05ff0ac7 --- /dev/null +++ b/sql/updates/0.6/r2020_scriptdev2.sql @@ -0,0 +1,10 @@ +DELETE FROM script_texts WHERE entry IN (-1409023, -1409024); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1409023,'Very well, $N.',0,0,0,0,'majordomo SAY_SUMMON_0'), +(-1409024,'Impudent whelps! You''ve rushed headlong to your own deaths! See now, the master stirs!',0,1,0,0,'majordomo SAY_SUMMON_1'); + +DELETE FROM gossip_texts WHERE entry IN (-3409000, -3409001, -3409002); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3409000,'Tell me more.','majordomo_executus GOSSIP_ITEM_SUMMON_1'), +(-3409001,'What else do you have to say?','majordomo_executus GOSSIP_ITEM_SUMMON_2'), +(-3409002,'You challenged us and we have come. Where is this master you speak of?','majordomo_executus GOSSIP_ITEM_SUMMON_3'); diff --git a/sql/updates/0.6/r2021_mangos.sql b/sql/updates/0.6/r2021_mangos.sql new file mode 100644 index 0000000000..ba30ad9649 --- /dev/null +++ b/sql/updates/0.6/r2021_mangos.sql @@ -0,0 +1,8 @@ +UPDATE creature_template SET ScriptName='boss_thaddius' WHERE entry=15928; +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; + +DELETE FROM scripted_areatrigger WHERE entry=4113; +INSERT INTO scripted_areatrigger VALUES +(4113,'at_naxxramas'); diff --git a/sql/updates/0.6/r2024_mangos.sql b/sql/updates/0.6/r2024_mangos.sql new file mode 100644 index 0000000000..76919314a2 --- /dev/null +++ b/sql/updates/0.6/r2024_mangos.sql @@ -0,0 +1,3 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=164955; +UPDATE gameobject_template SET ScriptName='' WHERE entry=164956; +UPDATE gameobject_template SET ScriptName='' WHERE entry=164957; diff --git a/sql/updates/0.6/r2025_mangos.sql b/sql/updates/0.6/r2025_mangos.sql new file mode 100644 index 0000000000..b444b113d3 --- /dev/null +++ b/sql/updates/0.6/r2025_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18240; diff --git a/sql/updates/0.6/r2028_scriptdev2.sql b/sql/updates/0.6/r2028_scriptdev2.sql new file mode 100644 index 0000000000..3287576ed6 --- /dev/null +++ b/sql/updates/0.6/r2028_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=3 WHERE entry IN (-1533082,-1533083); diff --git a/sql/updates/0.6/r2031_mangos.sql b/sql/updates/0.6/r2031_mangos.sql new file mode 100644 index 0000000000..95df14ff97 --- /dev/null +++ b/sql/updates/0.6/r2031_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (28053, 28054, 28093); diff --git a/sql/updates/0.6/r2031_scriptdev2.sql b/sql/updates/0.6/r2031_scriptdev2.sql new file mode 100644 index 0000000000..baef2250d3 --- /dev/null +++ b/sql/updates/0.6/r2031_scriptdev2.sql @@ -0,0 +1,10 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000651 AND -1000644; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000644,'Ouch! That\'s it, I quit the target business!',0,0,0,0,'SAY_LUCKY_HIT_1'), +(-1000645,'My ear! You grazed my ear!',0,0,0,0,'SAY_LUCKY_HIT_2'), +(-1000646,'Not the \'stache! Now I\'m asymmetrical!',0,0,0,0,'SAY_LUCKY_HIT_3'), +(-1000647,'Good shot!',0,0,0,0,'SAY_LUCKY_HIT_APPLE'), +(-1000648,'Stop whining. You\'ve still got your luck.',0,0,0,0,'SAY_DROSTAN_GOT_LUCKY_1'), +(-1000649,'Bah, it\'s an improvement.',0,0,0,0,'SAY_DROSTAN_GOT_LUCKY_2'), +(-1000650,'Calm down lad, it\'s just a birdshot!',0,0,0,0,'SAY_DROSTAN_HIT_BIRD_1'), +(-1000651,'The only thing hurt is your pride, lad! Buck up!',0,0,0,0,'SAY_DROSTAN_HIT_BIRD_2'); diff --git a/sql/updates/0.6/r2033_scriptdev2.sql b/sql/updates/0.6/r2033_scriptdev2.sql new file mode 100644 index 0000000000..736a7c4f59 --- /dev/null +++ b/sql/updates/0.6/r2033_scriptdev2.sql @@ -0,0 +1,11 @@ +DELETE FROM script_texts WHERE entry=-1469031; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1469031,'Death Knights, get over here!',0,1,0,0,'nefarian SAY_DEATH_KNIGHT'); + +DELETE FROM gossip_texts WHERE entry IN (-3469000, -3469001, -3469002); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3469000,'I\'ve made no mistakes.','victor_nefarius GOSSIP_ITEM_NEFARIUS_1'), +(-3469001,'You have lost your mind, Nefarius. You speak in riddles.','victor_nefarius GOSSIP_ITEM_NEFARIUS_2'), +(-3469002,'Please do.','victor_nefarius GOSSIP_ITEM_NEFARIUS_3'); + +UPDATE script_texts SET comment='victor_nefarius SAY_NEFARIUS_CORRUPT' WHERE entry=-1469006; diff --git a/sql/updates/0.6/r2036_scriptdev2.sql b/sql/updates/0.6/r2036_scriptdev2.sql new file mode 100644 index 0000000000..890db67259 --- /dev/null +++ b/sql/updates/0.6/r2036_scriptdev2.sql @@ -0,0 +1,3 @@ +UPDATE script_texts SET emote=5 WHERE entry=-1000646; +UPDATE script_texts SET emote=4 WHERE entry=-1000647; +UPDATE script_texts SET emote=11 WHERE entry=-1000649; diff --git a/sql/updates/0.6/r2037_mangos.sql b/sql/updates/0.6/r2037_mangos.sql new file mode 100644 index 0000000000..4f67f0281a --- /dev/null +++ b/sql/updates/0.6/r2037_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=29344; diff --git a/sql/updates/0.6/r2038_mangos.sql b/sql/updates/0.6/r2038_mangos.sql new file mode 100644 index 0000000000..c95ac91cb3 --- /dev/null +++ b/sql/updates/0.6/r2038_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (14742,14743,21493,21494); diff --git a/sql/updates/0.6/r2039_mangos.sql b/sql/updates/0.6/r2039_mangos.sql new file mode 100644 index 0000000000..fa65242d00 --- /dev/null +++ b/sql/updates/0.6/r2039_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=24040; diff --git a/sql/updates/0.6/r2043_scriptdev2.sql b/sql/updates/0.6/r2043_scriptdev2.sql new file mode 100644 index 0000000000..c5bb54f3ef --- /dev/null +++ b/sql/updates/0.6/r2043_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='You there, check out that noise.' WHERE entry=-1036000; diff --git a/sql/updates/0.6/r2044_mangos.sql b/sql/updates/0.6/r2044_mangos.sql new file mode 100644 index 0000000000..0771cad771 --- /dev/null +++ b/sql/updates/0.6/r2044_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_mr_smite' WHERE entry=646; diff --git a/sql/updates/0.6/r2044_scriptdev2.sql b/sql/updates/0.6/r2044_scriptdev2.sql new file mode 100644 index 0000000000..4c80d4f8a6 --- /dev/null +++ b/sql/updates/0.6/r2044_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1036002, -1036003); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1036002,'You land lubbers are tougher than I thought! I\'ll have to improvise!',5778,0,0,21,'smite SAY_PHASE_2'), +(-1036003,'D\'ah! Now you\'re making me angry!',5779,0,0,15,'smite SAY_PHASE_3'); diff --git a/sql/updates/0.6/r2050_mangos.sql b/sql/updates/0.6/r2050_mangos.sql new file mode 100644 index 0000000000..16bad37cfa --- /dev/null +++ b/sql/updates/0.6/r2050_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_dragonmaw_peon' WHERE entry=22252; diff --git a/sql/updates/0.6/r2051_scriptdev2.sql b/sql/updates/0.6/r2051_scriptdev2.sql new file mode 100644 index 0000000000..8a6c6ab5bf --- /dev/null +++ b/sql/updates/0.6/r2051_scriptdev2.sql @@ -0,0 +1,7 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000656 AND -1000652; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000652,'Me so hungry! YUM!',0,0,0,71,'dragonmaw peon SAY_PEON_1'), +(-1000653,'Hey... me not feel so good.',0,0,0,0,'dragonmaw peon SAY_PEON_2'), +(-1000654,'You is bad orc... baaad... or... argh!',0,0,0,0,'dragonmaw peon SAY_PEON_3'), +(-1000655,'Time for eating!?',0,0,0,71,'dragonmaw peon SAY_PEON_4'), +(-1000656,'It put the mutton in the stomach!',0,0,0,71,'dragonmaw peon SAY_PEON_5'); diff --git a/sql/updates/0.6/r2057_scriptdev2.sql b/sql/updates/0.6/r2057_scriptdev2.sql new file mode 100644 index 0000000000..282c5885d1 --- /dev/null +++ b/sql/updates/0.6/r2057_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1329018 AND -1329016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1329016,'Today you have unmade what took me years to create! For this you shall all die by my hand!',0,1,0,0,'dathrohan SAY_AGGRO'), +(-1329017,'You fools think you can defeat me so easily? Face the true might of the Nathrezim!',0,1,0,0,'dathrohan SAY_TRANSFORM'), +(-1329018,'Damn you mortals! All my plans of revenge, all my hate... all burned to ash...',0,0,0,0,'dathrohan SAY_DEATH'); diff --git a/sql/updates/0.6/r2059_mangos.sql b/sql/updates/0.6/r2059_mangos.sql new file mode 100644 index 0000000000..e723f56657 --- /dev/null +++ b/sql/updates/0.6/r2059_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_helice' WHERE entry=28787; diff --git a/sql/updates/0.6/r2059_scriptdev2.sql b/sql/updates/0.6/r2059_scriptdev2.sql new file mode 100644 index 0000000000..43d91253ba --- /dev/null +++ b/sql/updates/0.6/r2059_scriptdev2.sql @@ -0,0 +1,34 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000663 AND -1000657; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000657,'Let\'s get the hell out of here.',0,0,0,5,'helice SAY_HELICE_ACCEPT'), +(-1000658,'Listen up, Venture Company goons! Rule #1: Never keep the prisoner near the explosives.',0,0,0,25,'helice SAY_HELICE_EXPLOSIVES_1'), +(-1000659,'Or THIS is what you get.',0,0,0,0,'helice SAY_HELICE_EXPLODE_1'), +(-1000660,'It\'s getting a little hot over here. Shall we move on?',0,0,0,11,'helice SAY_HELICE_MOVE_ON'), +(-1000661,'Oh, look, it\'s another cartload of explosives! Let\'s help them dispose of it.',0,0,0,25,'helice SAY_HELICE_EXPLOSIVES_2'), +(-1000662,'You really shouldn\'t play with this stuff. Someone could get hurt.',0,0,0,5,'helice SAY_HELICE_EXPLODE_2'), +(-1000663,'We made it! Thank you for getting me out of that hell hole. Tell Hemet to expect me!',0,0,0,4,'helice SAY_HELICE_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=28787; +INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, waittime, point_comment) VALUES +(28787, 1, 5913.516113, 5379.034668, -98.896118, 0, ''), +(28787, 2, 5917.750977, 5374.519043, -98.869781, 0, 'SAY_HELICE_EXPLOSIVES_1'), +(28787, 3, 5926.428711, 5372.145020, -98.884453, 0, ''), +(28787, 4, 5929.214844, 5377.803223, -99.020065, 0, ''), +(28787, 5, 5927.621582, 5378.564941, -99.047890, 0, ''), +(28787, 6, 5917.622070, 5383.494629, -106.310204, 0, ''), +(28787, 7, 5908.991211, 5387.655762, -106.310204, 0, ''), +(28787, 8, 5906.287109, 5390.496582, -106.041801, 0, ''), +(28787, 9, 5902.415039, 5399.741211, -99.306595, 0, ''), +(28787, 10, 5901.444336, 5404.593262, -96.759636, 0, ''), +(28787, 11, 5897.860352, 5406.656250, -96.029709, 0, ''), +(28787, 12, 5892.254395, 5401.291504, -95.848808, 0, ''), +(28787, 13, 5887.421875, 5386.701172, -95.400146, 0, 'SAY_HELICE_EXPLOSIVES_2'), +(28787, 14, 5883.308105, 5385.057617, -94.423698, 0, ''), +(28787, 15, 5879.180664, 5375.897461, -95.088066, 0, ''), +(28787, 16, 5872.613281, 5363.473633, -97.703575, 0, ''), +(28787, 17, 5857.971191, 5354.929688, -98.586090, 0, ''), +(28787, 18, 5848.729004, 5345.326660, -99.428978, 0, ''), +(28787, 19, 5842.330566, 5335.018555, -100.421455, 0, ''), +(28787, 20, 5832.164551, 5323.145020, -98.703285, 0, ''), +(28787, 21, 5824.738770, 5315.712891, -97.758018, 0, ''), +(28787, 22, 5819.650879, 5305.409668, -97.481796, 10000, 'SAY_HELICE_COMPLETE'); diff --git a/sql/updates/0.6/r2061_mangos.sql b/sql/updates/0.6/r2061_mangos.sql new file mode 100644 index 0000000000..2d518d85c6 --- /dev/null +++ b/sql/updates/0.6/r2061_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_oil_stained_wolf' WHERE entry=25791; diff --git a/sql/updates/0.6/r2064_mangos.sql b/sql/updates/0.6/r2064_mangos.sql new file mode 100644 index 0000000000..9d4c04b99d --- /dev/null +++ b/sql/updates/0.6/r2064_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_sinkhole_kill_credit' WHERE entry IN (26248,26249); diff --git a/sql/updates/0.6/r2064_scriptdev2.sql b/sql/updates/0.6/r2064_scriptdev2.sql new file mode 100644 index 0000000000..4ba54cb48b --- /dev/null +++ b/sql/updates/0.6/r2064_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11421+) '; diff --git a/sql/updates/0.6/r2070_mangos.sql b/sql/updates/0.6/r2070_mangos.sql new file mode 100644 index 0000000000..523ce0229e --- /dev/null +++ b/sql/updates/0.6/r2070_mangos.sql @@ -0,0 +1,8 @@ +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'), +(5619,'event_spell_gandling_shadow_portal'), +(5620,'event_spell_gandling_shadow_portal'), +(5621,'event_spell_gandling_shadow_portal'), +(5622,'event_spell_gandling_shadow_portal'), +(5623,'event_spell_gandling_shadow_portal'); diff --git a/sql/updates/0.6/r2072_scriptdev2.sql b/sql/updates/0.6/r2072_scriptdev2.sql new file mode 100644 index 0000000000..f3c2a1c87e --- /dev/null +++ b/sql/updates/0.6/r2072_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry=-1509022; diff --git a/sql/updates/0.6/r2073_mangos.sql b/sql/updates/0.6/r2073_mangos.sql new file mode 100644 index 0000000000..0035507a3a --- /dev/null +++ b/sql/updates/0.6/r2073_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_destructive_ward' WHERE entry=27430; diff --git a/sql/updates/0.6/r2073_scriptdev2.sql b/sql/updates/0.6/r2073_scriptdev2.sql new file mode 100644 index 0000000000..30aa799bb7 --- /dev/null +++ b/sql/updates/0.6/r2073_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1000664, -1000665); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000664,'The Destructive Ward gains in power.',0,5,0,0,'destructive ward SAY_WARD_POWERUP'), +(-1000665,'The Destructive Ward is fully charged!',0,5,0,0,'destructive ward SAY_WARD_CHARGED'); diff --git a/sql/updates/0.6/r2074_scriptdev2.sql b/sql/updates/0.6/r2074_scriptdev2.sql new file mode 100644 index 0000000000..cd1c782198 --- /dev/null +++ b/sql/updates/0.6/r2074_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1109005; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1109005,'The shield be down! Rise up Atal\'ai! Rise up!',5861,6,0,0,'jammalan SAY_JAMMALAN_INTRO'); diff --git a/sql/updates/0.6/r2075_mangos.sql b/sql/updates/0.6/r2075_mangos.sql new file mode 100644 index 0000000000..aa142f8d5a --- /dev/null +++ b/sql/updates/0.6/r2075_mangos.sql @@ -0,0 +1,8 @@ +DELETE FROM scripted_event_id WHERE id IN (3094,3095,3097,3098,3099,3100); +INSERT INTO scripted_event_id VALUES +(3094,'event_antalarion_statue_activation'), +(3095,'event_antalarion_statue_activation'), +(3097,'event_antalarion_statue_activation'), +(3098,'event_antalarion_statue_activation'), +(3099,'event_antalarion_statue_activation'), +(3100,'event_antalarion_statue_activation'); diff --git a/sql/updates/0.6/r2076_scriptdev2.sql b/sql/updates/0.6/r2076_scriptdev2.sql new file mode 100644 index 0000000000..06786b9a6b --- /dev/null +++ b/sql/updates/0.6/r2076_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1429002; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1429002,'At last... Freed from his cursed grasp!',0,6,0,0,'old ironbark SAY_IRONBARK_REDEEM'); diff --git a/sql/updates/0.6/r2077_mangos.sql b/sql/updates/0.6/r2077_mangos.sql new file mode 100644 index 0000000000..dc0698d4c5 --- /dev/null +++ b/sql/updates/0.6/r2077_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_willix_the_importer' WHERE entry=4508; diff --git a/sql/updates/0.6/r2077_scriptdev2.sql b/sql/updates/0.6/r2077_scriptdev2.sql new file mode 100644 index 0000000000..177aea1fa9 --- /dev/null +++ b/sql/updates/0.6/r2077_scriptdev2.sql @@ -0,0 +1,65 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1047012 AND -1047000; +INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,comment) VALUES +(-1047000,'Woo hoo! Finally getting out of here. It\'s going to be rough though. Keep your eyes peeled for trouble.',0,0,0,0,'willix SAY_READY'), +(-1047001,'Up there is where Charlga Razorflank resides. Blasted old crone.',0,0,0,25,'willix SAY_1'), +(-1047002,'There\'s blueleaf tuber in this trench! It\'s like gold waiting to be mined I tell you!',0,0,0,0,'willix SAY_2'), +(-1047003,'There could be danger around every corner here.',0,0,0,0,'willix SAY_3'), +(-1047004,'I don\'t see how these foul animals live in this place... sheesh it smells!',0,0,0,0,'willix SAY_4'), +(-1047005,'I think I see a way for us to get out of this big twisted mess of a bramble.',0,0,0,0,'willix SAY_5'), +(-1047006,'Glad to be out of that wretched trench. Not much nicer up here though!',0,0,0,0,'willix SAY_6'), +(-1047007,'Finally! I\'ll be glad to get out of this place.',0,0,0,0,'willix SAY_7'), +(-1047008,'I think I\'ll rest a moment and catch my breath before heading back to Ratchet. Thanks for all the help!',0,0,0,0,'willix SAY_END'), +(-1047009,'$N heading this way fast! To arms!',0,0,0,0,'willix SAY_AGGRO_1'), +(-1047010,'Eek! $N coming right at us!',0,0,0,0,'willix SAY_AGGRO_2'), +(-1047011,'Egads! $N on me!',0,0,0,0,'willix SAY_AGGRO_3'), +(-1047012,'Help! Get this $N off of me!',0,0,0,0,'willix SAY_AGGRO_4'); + +DELETE FROM script_waypoint WHERE entry=4508; +INSERT INTO script_waypoint VALUES +(4508, 0, 2194.38, 1791.65, 65.48, 5000, ''), +(4508, 1, 2188.56, 1805.87, 64.45, 0, ''), +(4508, 2, 2186.2, 1836.278, 59.859, 5000, 'SAY_WILLIX_1'), +(4508, 3, 2163.27, 1851.67, 56.73, 0, ''), +(4508, 4, 2140.22, 1845.02, 48.32, 0, ''), +(4508, 5, 2131.5, 1804.29, 46.85, 0, ''), +(4508, 6, 2096.18, 1789.03, 51.13, 3000, 'SAY_WILLIX_2'), +(4508, 7, 2074.46, 1780.09, 55.64, 0, ''), +(4508, 8, 2055.12, 1768.67, 58.46, 0, ''), +(4508, 9, 2037.83, 1748.62, 60.27, 5000, 'SAY_WILLIX_3'), +(4508, 10, 2037.51, 1728.94, 60.85, 0, ''), +(4508, 11, 2044.7, 1711.71, 59.71, 0, ''), +(4508, 12, 2067.66, 1701.84, 57.77, 0, ''), +(4508, 13, 2078.91, 1704.54, 56.77, 0, ''), +(4508, 14, 2097.65, 1715.24, 54.74, 3000, 'SAY_WILLIX_4'), +(4508, 15, 2106.44, 1720.98, 54.41, 0, ''), +(4508, 16, 2123.96, 1732.56, 52.27, 0, ''), +(4508, 17, 2153.82, 1728.73, 51.92, 0, ''), +(4508, 18, 2163.49, 1706.33, 54.42, 0, ''), +(4508, 19, 2158.75, 1695.98, 55.70, 0, ''), +(4508, 20, 2142.6, 1680.72, 58.24, 0, ''), +(4508, 21, 2118.31, 1671.54, 59.21, 0, ''), +(4508, 22, 2086.02, 1672.04, 61.24, 0, ''), +(4508, 23, 2068.81, 1658.93, 61.24, 0, ''), +(4508, 24, 2062.82, 1633.31, 64.35, 0, ''), +(4508, 25, 2060.92, 1600.11, 62.41, 3000, 'SAY_WILLIX_5'), +(4508, 26, 2063.05, 1589.16, 63.26, 0, ''), +(4508, 27, 2063.67, 1577.22, 65.89, 0, ''), +(4508, 28, 2057.94, 1560.68, 68.40, 0, ''), +(4508, 29, 2052.56, 1548.05, 73.35, 0, ''), +(4508, 30, 2045.22, 1543.4, 76.65, 0, ''), +(4508, 31, 2034.35, 1543.01, 79.70, 0, ''), +(4508, 32, 2029.95, 1542.94, 80.79, 0, ''), +(4508, 33, 2021.34, 1538.67, 80.8, 0, 'SAY_WILLIX_6'), +(4508, 34, 2012.45, 1549.48, 79.93, 0, ''), +(4508, 35, 2008.05, 1554.92, 80.44, 0, ''), +(4508, 36, 2006.54, 1562.72, 81.11, 0, ''), +(4508, 37, 2003.8, 1576.43, 81.57, 0, ''), +(4508, 38, 2000.57, 1590.06, 80.62, 0, ''), +(4508, 39, 1998.96, 1596.87, 80.22, 0, ''), +(4508, 40, 1991.19, 1600.82, 79.39, 0, ''), +(4508, 41, 1980.71, 1601.44, 79.77, 0, ''), +(4508, 42, 1967.22, 1600.18, 80.62, 0, ''), +(4508, 43, 1956.43, 1596.97, 81.75, 0, ''), +(4508, 44, 1954.87, 1592.02, 82.18, 3000, 'SAY_WILLIX_7'), +(4508, 45, 1948.35, 1571.35, 80.96, 30000, 'SAY_WILLIX_END'), +(4508, 46, 1947.02, 1566.42, 81.80, 30000, ''); diff --git a/sql/updates/0.6/r2080_scriptdev2.sql b/sql/updates/0.6/r2080_scriptdev2.sql new file mode 100644 index 0000000000..e4db2336bc --- /dev/null +++ b/sql/updates/0.6/r2080_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11432+) '; diff --git a/sql/updates/0.6/r2092_mangos.sql b/sql/updates/0.6/r2092_mangos.sql new file mode 100644 index 0000000000..0751cd46d7 --- /dev/null +++ b/sql/updates/0.6/r2092_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_lethon' WHERE entry=14888; diff --git a/sql/updates/0.6/r2092_scriptdev2.sql b/sql/updates/0.6/r2092_scriptdev2.sql new file mode 100644 index 0000000000..68402546e7 --- /dev/null +++ b/sql/updates/0.6/r2092_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts where entry IN (-1000666, -1000667); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000666,'I can sense the SHADOW on your hearts. There can be no rest for the wicked!',0,1,0,0,'lethon SAY_LETHON_AGGRO'), +(-1000667,'Your wicked souls shall feed my power!',0,1,0,0,'lethon SAY_LETHON_SHADE'); diff --git a/sql/updates/0.6/r2101_mangos.sql b/sql/updates/0.6/r2101_mangos.sql new file mode 100644 index 0000000000..45c9a7f72d --- /dev/null +++ b/sql/updates/0.6/r2101_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_infused_crystal' WHERE entry=16364; diff --git a/sql/updates/0.6/r2101_scriptdev2.sql b/sql/updates/0.6/r2101_scriptdev2.sql new file mode 100644 index 0000000000..b767901946 --- /dev/null +++ b/sql/updates/0.6/r2101_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1000668; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000668,'%s releases the last of its energies into the nearby runestone, successfully reactivating it.',0,2,0,0,'infused crystal SAY_DEFENSE_FINISH'); diff --git a/sql/updates/0.6/r2107_scriptdev2.sql b/sql/updates/0.6/r2107_scriptdev2.sql new file mode 100644 index 0000000000..aeb4425772 --- /dev/null +++ b/sql/updates/0.6/r2107_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1229003 AND -1229000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1229000,'%s begins to regain its strength!',0,2,0,0,'pyroguard EMOTE_BEGIN'), +(-1229001,'%s is nearly at full strength!',0,2,0,0,'pyroguard EMOTE_NEAR'), +(-1229002,'%s regains its power and breaks free of its bonds!',0,2,0,0,'pyroguard EMOTE_FULL'), +(-1229003,'Ha! Ha! Ha! Thank you for freeing me, fools. Now let me repay you by charring the flesh from your bones.',0,1,0,0,'pyroguard SAY_FREE'); diff --git a/sql/updates/0.6/r2112_mangos.sql b/sql/updates/0.6/r2112_mangos.sql new file mode 100644 index 0000000000..92532839a6 --- /dev/null +++ b/sql/updates/0.6/r2112_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_belnistrasz' WHERE entry=8516; diff --git a/sql/updates/0.6/r2112_scriptdev2.sql b/sql/updates/0.6/r2112_scriptdev2.sql new file mode 100644 index 0000000000..b1b3f1b1cd --- /dev/null +++ b/sql/updates/0.6/r2112_scriptdev2.sql @@ -0,0 +1,38 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1129012 AND -1129005; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-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'), +(-1129007,'You\'ll rue the day you crossed me, $N',0,0,0,0,'belnistrasz SAY_AGGRO_1'), +(-1129008,'Incoming $N - look sharp, friends!',0,0,0,0,'belnistrasz SAY_AGGRO_2'), +(-1129009,'Three minutes left -- I can feel the energy starting to build! Keep up the solid defense!',0,1,0,0,'belnistrasz SAY_3_MIN'), +(-1129010,'Just two minutes to go! We\'re half way there, but don\'t let your guard down!',0,1,0,0,'belnistrasz SAY_2_MIN'), +(-1129011,'One more minute! Hold on now, the ritual is about to take hold!',0,1,0,0,'belnistrasz SAY_1_MIN'), +(-1129012,'That\'s it -- we made it! The ritual is set in motion, and idol fires are about to go out for good! You truly are the heroes I thought you would be!',0,1,0,4,'belnistrasz SAY_FINISH'); + +DELETE FROM script_waypoint WHERE entry = 8516; +INSERT INTO script_waypoint VALUES +(8516, 1,2603.18, 725.259, 54.6927, 0, ''), +(8516, 2,2587.13, 734.392, 55.231, 0, ''), +(8516, 3,2570.69, 753.572, 54.5855, 0, ''), +(8516, 4,2558.51, 747.66, 54.4482, 0, ''), +(8516, 5,2544.23, 772.924, 47.9255, 0, ''), +(8516, 6,2530.08, 797.475, 45.97, 0, ''), +(8516, 7,2521.83, 799.127, 44.3061, 0, ''), +(8516, 8,2502.61, 789.222, 39.5074, 0, ''), +(8516, 9,2495.25, 789.406, 39.499, 0, ''), +(8516, 10,2488.07, 802.455, 42.9834, 0, ''), +(8516, 11,2486.64, 826.649, 43.6363, 0, ''), +(8516, 12,2492.64, 835.166, 45.1427, 0, ''), +(8516, 13,2505.02, 847.564, 47.6487, 0, ''), +(8516, 14,2538.96, 877.362, 47.6781, 0, ''), +(8516, 15,2546.07, 885.672, 47.6789, 0, ''), +(8516, 16,2548.02, 897.584, 47.7277, 0, ''), +(8516, 17,2544.29, 909.116, 46.2506, 0, ''), +(8516, 18,2523.60, 920.306, 45.8717, 0, ''), +(8516, 19,2522.69, 933.546, 47.5769, 0, ''), +(8516, 20,2531.63, 959.893, 49.4111, 0, ''), +(8516, 21,2540.23, 973.338, 50.1241, 0, ''), +(8516, 22,2547.21, 977.489, 49.9759, 0, ''), +(8516, 23,2558.75, 969.243, 50.7353, 0, ''), +(8516, 24,2575.60, 950.138, 52.8460, 0, ''), +(8516, 25,2575.60, 950.138, 52.8460, 0, ''); diff --git a/sql/updates/0.6/r2113_scriptdev2.sql b/sql/updates/0.6/r2113_scriptdev2.sql new file mode 100644 index 0000000000..01112f73d1 --- /dev/null +++ b/sql/updates/0.6/r2113_scriptdev2.sql @@ -0,0 +1,12 @@ +UPDATE script_texts SET content_default='BURN! You wretches! BURN!' WHERE entry = -1469009; +UPDATE script_texts SET content_default='This cannot be! I am the master here! You mortals are nothing to my kind! Do you hear me? Nothing!' WHERE entry = -1469012; +UPDATE script_texts SET content_default='Ah...the heroes. You are persistent, aren\'t you? Your ally here attempted to match his power against mine - and paid the price. Now he shall serve me...by slaughtering you.' WHERE entry = -1469006; +UPDATE script_texts SET content_default='Too late, friends! Nefarius\' corruption has taken hold...I cannot...control myself.' WHERE entry = -1469026; +UPDATE script_texts SET content_default='I beg you, mortals - FLEE! Flee before I lose all sense of control! The black fire rages within my heart! I MUST- release it!' WHERE entry = -1469027; +UPDATE script_texts SET content_default='FLAME! DEATH! DESTRUCTION! Cower, mortals before the wrath of Lord...NO - I MUST fight this! Alexstrasza help me, I MUST fight it!' WHERE entry = -1469028; +UPDATE script_texts SET content_default='Nefarius\' hate has made me stronger than ever before! You should have fled while you could, mortals! The fury of Blackrock courses through my veins!' WHERE entry = -1469029; +UPDATE script_texts SET content_default='Forgive me, $N! Your death only adds to my failure!' WHERE entry = -1469030; + +DELETE FROM script_texts WHERE entry=-1469032; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1469032,'Get up, little red wyrm...and destroy them!',0,1,0,0,'victor_nefarius SAY_NEFARIUS_CORRUPT_2'); diff --git a/sql/updates/0.6/r2114_scriptdev2.sql b/sql/updates/0.6/r2114_scriptdev2.sql new file mode 100644 index 0000000000..5337d806a9 --- /dev/null +++ b/sql/updates/0.6/r2114_scriptdev2.sql @@ -0,0 +1,7 @@ +UPDATE script_texts SET type=1, emote=1 WHERE entry = -1469004; +UPDATE script_texts SET emote=22 WHERE entry = -1469005; +UPDATE script_texts SET emote=23 WHERE entry = -1469006; +UPDATE script_texts SET emote=1 WHERE entry = -1469026; +UPDATE script_texts SET emote=1 WHERE entry = -1469027; +UPDATE script_texts SET emote=1 WHERE entry = -1469028; +UPDATE script_texts SET emote=1 WHERE entry = -1469032; diff --git a/sql/updates/0.6/r2116_scriptdev2.sql b/sql/updates/0.6/r2116_scriptdev2.sql new file mode 100644 index 0000000000..e9313a7d30 --- /dev/null +++ b/sql/updates/0.6/r2116_scriptdev2.sql @@ -0,0 +1,12 @@ +UPDATE script_texts SET content_default='Run! They are coming!', type=1, comment='vaelastrasz blackwing tech SAY_INTRO_TECH' WHERE entry = -1469002; +UPDATE script_texts SET content_default='Fools! These eggs are more precious than you know!' WHERE entry = -1469023; +UPDATE script_texts SET content_default='No - not another one! I\'ll have your heads for this atrocity!' WHERE entry = -1469024; + +DELETE FROM script_texts WHERE entry=-1469033; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1469033,'%s flee as the controlling power of the orb is drained.',0,2,0,0,'razorgore EMOTE_TROOPS_FLEE'); + +DELETE FROM gossip_texts WHERE entry IN (-3469003,-3469004); +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'); diff --git a/sql/updates/0.6/r2130_scriptdev2.sql b/sql/updates/0.6/r2130_scriptdev2.sql new file mode 100644 index 0000000000..39298d8750 --- /dev/null +++ b/sql/updates/0.6/r2130_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11526+) '; diff --git a/sql/updates/0.6/r2134_scriptdev2.sql b/sql/updates/0.6/r2134_scriptdev2.sql new file mode 100644 index 0000000000..cd63988e7c --- /dev/null +++ b/sql/updates/0.6/r2134_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry BETWEEN -1568078 AND -1568067; diff --git a/sql/updates/0.6/r2138_mangos.sql b/sql/updates/0.6/r2138_mangos.sql new file mode 100644 index 0000000000..a58a7d536c --- /dev/null +++ b/sql/updates/0.6/r2138_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_corrupted_soul_fragment' WHERE entry=36535; diff --git a/sql/updates/0.6/r2139_scriptdev2.sql b/sql/updates/0.6/r2139_scriptdev2.sql new file mode 100644 index 0000000000..ef0296ddfd --- /dev/null +++ b/sql/updates/0.6/r2139_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11558+) '; diff --git a/sql/updates/0.6/r2146_scriptdev2.sql b/sql/updates/0.6/r2146_scriptdev2.sql new file mode 100644 index 0000000000..fea90a6cab --- /dev/null +++ b/sql/updates/0.6/r2146_scriptdev2.sql @@ -0,0 +1,3 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11576+) '; + +UPDATE script_texts SET type=6 WHERE entry=-1533089; diff --git a/sql/updates/0.6/r2147_mangos.sql b/sql/updates/0.6/r2147_mangos.sql new file mode 100644 index 0000000000..d71d7d93a4 --- /dev/null +++ b/sql/updates/0.6/r2147_mangos.sql @@ -0,0 +1,5 @@ +UPDATE gameobject_template SET ScriptName='go_eternal_flame' WHERE entry IN (148418,148419,148420,148421); +UPDATE creature_template SET ScriptName='npc_shade_of_hakkar' WHERE entry=8440; +DELETE FROM scripted_event_id WHERE id=8502; +INSERT INTO scripted_event_id VALUES +(8502,'event_avatar_of_hakkar'); diff --git a/sql/updates/0.6/r2147_scriptdev2.sql b/sql/updates/0.6/r2147_scriptdev2.sql new file mode 100644 index 0000000000..781860b3c8 --- /dev/null +++ b/sql/updates/0.6/r2147_scriptdev2.sql @@ -0,0 +1,7 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1109010 AND -1109006; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1109006,'HAKKAR LIVES!',5870,1,0,0,'avatar SAY_AVATAR_BRAZIER_1'), +(-1109007,'I TASTE THE BLOOD OF LIFE!',5868,1,0,0,'avatar SAY_AVATAR_BRAZIER_2'), +(-1109008,'I DRAW CLOSER TO YOUR WORLD!',5867,1,0,0,'avatar SAY_AVATAR_BRAZIER_3'), +(-1109009,'I AM NEAR!',5869,1,0,0,'avatar SAY_AVATAR_BRAZIER_4'), +(-1109010,'I AM HERE!',0,1,0,0,'avatar SAY_AVATAR_SPAWN'); diff --git a/sql/updates/0.6/r2162_scriptdev2.sql b/sql/updates/0.6/r2162_scriptdev2.sql new file mode 100644 index 0000000000..eb0f8f565a --- /dev/null +++ b/sql/updates/0.6/r2162_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11590+) '; diff --git a/sql/updates/0.6/r2181_scriptdev2.sql b/sql/updates/0.6/r2181_scriptdev2.sql new file mode 100644 index 0000000000..86acf55b1f --- /dev/null +++ b/sql/updates/0.6/r2181_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM gossip_texts WHERE entry=-3033000; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3033000,'Please unlock the courtyard door.','deathstalker adamant/ sorcerer ashcrombe - GOSSIP_ITEM_DOOR'); diff --git a/sql/updates/0.6/r2212_mangos.sql b/sql/updates/0.6/r2212_mangos.sql new file mode 100644 index 0000000000..66731128cd --- /dev/null +++ b/sql/updates/0.6/r2212_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_prison_cell_lever' WHERE entry=181982; diff --git a/sql/updates/0.6/r2212_scriptdev2.sql b/sql/updates/0.6/r2212_scriptdev2.sql new file mode 100644 index 0000000000..7959e301b9 --- /dev/null +++ b/sql/updates/0.6/r2212_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1542015; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1542015,'Kill them!',0,1,0,0,'broggok SAY_BROGGOK_INTRO'); diff --git a/sql/updates/0.6/r2220_scriptdev2.sql b/sql/updates/0.6/r2220_scriptdev2.sql new file mode 100644 index 0000000000..12451c82ca --- /dev/null +++ b/sql/updates/0.6/r2220_scriptdev2.sql @@ -0,0 +1,45 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1724038 AND -1724000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1724000,'Help! I am trapped within this tree! I require aid!',17490,6,0,0,'xerestraza SAY_XERESTRASZA_HELP'), +(-1724001,'Your power wanes, ancient one! Soon, you will join your friends!',17525,6,0,0,'baltharus SAY_BALTHARUS_INTRO'), +(-1724002,'Thank you! I could have not held out for much longer. A terrible thing has happened here.',17491,1,0,0,'xerestraza SAY_XERESTRASZA_THANKS'), +(-1724003,'We believed that the Sanctum was well fortified, but we were not prepareted for the nature of this assault.',17492,0,0,0,'xerestraza SAY_OUTRO_1'), +(-1724004,'The Black Dragonkin materialized from thin air, and set upon us before we could react.',17493,0,0,0,'xerestraza SAY_OUTRO_2'), +(-1724005,'We did not stand a chance. As my brethren perished around me, I managed to retreat hear and bar the entrance.',17494,0,0,0,'xerestraza SAY_OUTRO_3'), +(-1724006,'They slaughtered us with cold efficiency, but the true focus of their interest seemed to be the eggs kept here in the sanctum.',17495,0,0,0,'xerestraza SAY_OUTRO_4'), +(-1724007,'The commander of the forces on the ground here is a cruel brute named Zarithrian. But I fear there are greater powers at work.',17496,0,0,0,'xerestraza SAY_OUTRO_5'), +(-1724008,'In their initial assault I caught a glimpse of their true leader, a fearsome full-grown Twilight Dragon.',17497,0,0,0,'xerestraza SAY_OUTRO_6'), +(-1724009,'I know not the extent of their plans heroes, but I know this: they cannot be allowed to succeed!',17498,0,0,0,'xerestraza SAY_OUTRO_7'), + +(-1724010,'Ah, the entertainment has arrived.',17520,1,0,0,'baltharus SAY_AGGRO'), +(-1724011,'Baltharus leaves no survivors!',17521,1,0,0,'baltharus SAY_SLAY_1'), +(-1724012,'This world has enough heroes.',17522,1,0,0,'baltharus SAY_SLAY_2'), +(-1724013,'I... Didn\'t see that coming...',17523,1,0,0,'baltharus SAY_DEATH'), +(-1724014,'Twice the pain and half the fun.',17524,1,0,0,'baltharus SAY_SPLIT'), + +(-1724015,'You will suffer for this intrusion!',17528,1,0,0,'saviana SAY_AGGRO'), +(-1724016,'As it should be...',17529,1,0,0,'saviana SAY_SLAY_1'), +(-1724017,'Halion will be pleased.',17530,1,0,0,'saviana SAY_SLAY_2'), +(-1724018,'Burn in the master\'s flame!',17532,1,0,0,'saviana SAY_SPECIAL'), + +(-1724019,'Alexstrasza has chosen capable allies... A pity that I must END YOU!',17512,1,0,0,'zarithrian SAY_AGGRO'), +(-1724020,'You thought you stood a chance?',17513,1,0,0,'zarithrian SAY_SLAY_1'), +(-1724021,'It\'s for the best.',17514,1,0,0,'zarithrian SAY_SLAY_2'), +(-1724022,'HALION! I...',17515,1,0,0,'zarithrian SAY_DEATH'), +(-1724023,'Turn them to ash, minions!',17516,1,0,0,'zarithrian SAY_SUMMON'), + +(-1724024,'Meddlesome insects! You\'re too late: The Ruby Sanctum\'s lost.',17499,6,0,0,'halion SAY_SPAWN'), +(-1724025,'Your world teeters on the brink of annihilation. You will ALL bear witness to the coming of a new age of DESTRUCTION!',17500,1,0,0,'halion SAY_AGGRO'), +(-1724026,'Another hero falls.',17501,1,0,0,'halion SAY_SLAY'), +(-1724027,'Relish this victory, mortals, for it will be your last! This world will burn with the master\'s return!',17503,1,0,0,'halion SAY_DEATH'), +(-1724028,'Not good enough.',17504,1,0,0,'halion SAY_BERSERK'), +(-1724029,'The heavens burn!',17505,1,0,0,'halion SAY_FIREBALL'), +(-1724030,'Beware the shadow!',17506,1,0,0,'halion SAY_SPHERES'), +(-1724031,'You will find only suffering within the realm of twilight! Enter if you dare!',17507,1,0,0,'halion SAY_PHASE_2'), +(-1724032,'I am the light and the darkness! Cower, mortals, before the herald of Deathwing!',17508,1,0,0,'halion SAY_PHASE_3'), +(-1724033,'The orbining spheres pulse with dark energy!',0,3,0,0,'halion EMOTE_SPHERES'), +(-1724034,'Your efforts force %s further out of the twillight realm!',0,3,0,0,'halion EMOTE_OUT_OF_TWILLIGHT'), +(-1724035,'Your efforts force %s further out of the physical realm!',0,3,0,0,'halion EMOTE_OUT_OF_PHYSICAL'), +(-1724036,'Your companions\' efforts force Halion further into the twillight realm!',0,3,0,0,'halion EMOTE_INTO_TWILLIGHT'), +(-1724037,'Your companions\' efforts force Halion further into the physical realm!',0,3,0,0,'halion EMOTE_INTO_PHYSICAL'), +(-1724038,'Without pressure in both realms %s begins to regenerate.',0,3,0,0,'halion EMOTE_REGENERATE'); diff --git a/sql/updates/0.6/r2227_mangos.sql b/sql/updates/0.6/r2227_mangos.sql new file mode 100644 index 0000000000..fe4df60217 --- /dev/null +++ b/sql/updates/0.6/r2227_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_crystal_channel_target' WHERE entry=26712; diff --git a/sql/updates/0.6/r2229_mangos.sql b/sql/updates/0.6/r2229_mangos.sql new file mode 100644 index 0000000000..44d66d217e --- /dev/null +++ b/sql/updates/0.6/r2229_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_relic_coffer_door' WHERE entry IN (174554, 174555, 174556, 174557, 174558, 174559, 174560, 174561, 174562, 174563, 174564, 174566); diff --git a/sql/updates/0.6/r2235_mangos.sql b/sql/updates/0.6/r2235_mangos.sql new file mode 100644 index 0000000000..0d2d8c78bb --- /dev/null +++ b/sql/updates/0.6/r2235_mangos.sql @@ -0,0 +1,2 @@ +DELETE FROM scripted_areatrigger WHERE entry=3626; +INSERT INTO scripted_areatrigger VALUES (3626, 'at_vaelastrasz'); diff --git a/sql/updates/0.6/r2235_scriptdev2.sql b/sql/updates/0.6/r2235_scriptdev2.sql new file mode 100644 index 0000000000..c138d9d6bd --- /dev/null +++ b/sql/updates/0.6/r2235_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1469034; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1469034,'Run! They are coming.',0,1,0,0,'blackwing technician SAY_TECHNICIAN_RUN'); diff --git a/sql/updates/0.6/r2239_scriptdev2.sql b/sql/updates/0.6/r2239_scriptdev2.sql new file mode 100644 index 0000000000..e24c0537ef --- /dev/null +++ b/sql/updates/0.6/r2239_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11720+) '; diff --git a/sql/updates/0.6/r2242_scriptdev2.sql b/sql/updates/0.6/r2242_scriptdev2.sql new file mode 100644 index 0000000000..643ecc457b --- /dev/null +++ b/sql/updates/0.6/r2242_scriptdev2.sql @@ -0,0 +1,32 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1580063 AND -1580036; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1580036,'Glory to Kil\'jaeden! Death to all who oppose!',12477,1,0,0,'felmyst SAY_INTRO'), +(-1580037,'I kill for the master!',12480,1,0,0,'felmyst SAY_KILL_1'), +(-1580038,'The end has come! ',12481,1,0,0,'felmyst SAY_KILL_2'), +(-1580039,'Choke on your final breath! ',12478,1,0,0,'felmyst SAY_BREATH'), +(-1580040,'I am stronger than ever before! ',12479,1,0,0,'felmyst SAY_TAKEOFF'), +(-1580041,'No more hesitation! Your fates are written! ',12482,1,0,0,'felmyst SAY_BERSERK'), +(-1580042,'Kil\'jaeden... will... prevail... ',12483,1,0,0,'felmyst SAY_DEATH'), +(-1580043,'Madrigosa deserved a far better fate. You did what had to be done, but this battle is far from over.',12439,1,0,0,'kalecgos SAY_KALECGOS_OUTRO'), + +(-1580044,'Misery...',12484,1,0,0,'sacrolash SAY_INTRO_1'), +(-1580045,'Depravity...',0,1,0,0,'alythess SAY_INTRO_2'), +(-1580046,'Confusion...',0,1,0,0,'sacrolash SAY_INTRO_3'), +(-1580047,'Hatred...',0,1,0,0,'alythess SAY_INTRO_4'), +(-1580048,'Mistrust...',0,1,0,0,'sacrolash SAY_INTRO_5'), +(-1580049,'Chaos...',0,1,0,0,'alythess SAY_INTRO_6'), +(-1580050,'These are the hallmarks...',0,1,0,0,'sacrolash SAY_INTRO_7'), +(-1580051,'These are the pillars...',0,1,0,0,'alythess SAY_INTRO_8'), + +(-1580052,'Shadow to the aid of fire!',12485,1,0,0,'sacrolash SAY_SACROLASH_SHADOW_NOVA'), +(-1580053,'Alythess! Your fire burns within me!',12488,1,0,0,'sacrolash SAY_SACROLASH_EMPOWER'), +(-1580054,'Shadows, engulf!',12486,1,0,0,'sacrolash SAY_SACROLASH_KILL_1'), +(-1580055,'Ee-nok Kryul!',12487,1,0,0,'sacrolash SAY_SACROLASH_KILL_2'), +(-1580056,'I... fade.',12399,1,0,0,'sacrolash SAY_SACROLASH_DEAD'), +(-1580057,'Time is a luxury you no longer possess!',0,1,0,0,'sacrolash SAY_SACROLASH_BERSERK'), +(-1580058,'Fire to the aid of shadow!',12489,1,0,0,'alythess SAY_ALYTHESS_CANFLAGRATION'), +(-1580059,'Sacrolash!',12492,1,0,0,'alythess SAY_ALYTHESS_EMPOWER'), +(-1580060,'Fire, consume!',12490,1,0,0,'alythess SAY_ALYTHESS_KILL_1'), +(-1580061,'Ed-ir Halach!',12491,1,0,0,'alythess SAY_ALYTHESS_KILL_2'), +(-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'); diff --git a/sql/updates/0.6/r2243_scriptdev2.sql b/sql/updates/0.6/r2243_scriptdev2.sql new file mode 100644 index 0000000000..a8cd9d905e --- /dev/null +++ b/sql/updates/0.6/r2243_scriptdev2.sql @@ -0,0 +1,33 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1580094 AND -1580064; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-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'), +(-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'), +(-1580072,'Who can you trust?',12503,1,0,0,'kiljaeden SAY_REFLECTION_1'), +(-1580073,'The enemy is among you.',12504,1,0,0,'kiljaeden SAY_REFLECTION_2'), +(-1580074,'Chaos!',12505,1,0,0,'kiljaeden SAY_DARKNESS_1'), +(-1580075,'Destruction!',12506,1,0,0,'kiljaeden SAY_DARKNESS_2'), +(-1580076,'Oblivion!',12507,1,0,0,'kiljaeden SAY_DARKNESS_3'), +(-1580077,'I will not be denied! This world shall fall!',12508,1,0,0,'kiljaeden SAY_PHASE_3'), +(-1580078,'Do not harbor false hope. You cannot win!',12509,1,0,0,'kiljaeden SAY_PHASE_4'), +(-1580079,'Aggghh! The powers of the Sunwell... turn... against me! What have you done? What have you done???',12510,1,0,0,'kiljaeden SAY_PHASE_5'), +(-1580080,'You are not alone. The Blue Dragonflight shall help you vanquish the Deceiver.',12438,1,0,0,'kalecgos SAY_KALECGOS_INTRO'), +(-1580081,'Anveena, you must awaken, this world needs you!',12445,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_1'), +(-1580082,'I serve only the Master now.',12511,1,0,0,'anveena SAY_ANVEENA_IMPRISONED'), +(-1580083,'You must let go! You must become what you were always meant to be! The time is now, Anveena!',12446,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_2'), +(-1580084,'But I\'m... lost. I cannot find my way back.',12512,1,0,0,'anveena SAY_ANVEENA_LOST'), +(-1580085,'Anveena, I love you! Focus on my voice, come back for me now! Only you can cleanse the Sunwell!',12447,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_4'), +(-1580086,'Kalec... Kalec?',12513,1,0,0,'anveena SAY_ANVEENA_AWAKE'), +(-1580087,'Yes, Anveena! Let fate embrace you now!',12448,1,0,0,'kalecgos SAY_KALECGOS_AWAKE_5'), +(-1580088,'The nightmare is over, the spell is broken! Goodbye, Kalec, my love!',12514,1,0,0,'anveena SAY_ANVEENA_SACRIFICE'), +(-1580089,'Goodbye, Anveena, my love. Few will remember your name, yet this day you change the course of destiny. What was once corrupt is now pure. Heroes, do not let her sacrifice be in vain.',12450,1,0,0,'kalecgos SAY_KALECGOS_GOODBYE'), +(-1580090,'Strike now, heroes, while he is weakened! Vanquish the Deceiver!',12449,1,0,0,'kalecgos SAY_KALECGOS_ENCOURAGE'), +(-1580091,'I will channel my power into the orbs, be ready!',12440,1,0,0,'kalecgos SAY_KALECGOS_ORB_1'), +(-1580092,'I have empowered another orb! Use it quickly!',12441,1,0,0,'kalecgos SAY_KALECGOS_ORB_2'), +(-1580093,'Another orb is ready! Make haste!',12442,1,0,0,'kalecgos SAY_KALECGOS_ORB_3'), +(-1580094,'I have channeled all I can! The power is in your hands!',12443,1,0,0,'kalecgos SAY_KALECGOS_ORB_4'); diff --git a/sql/updates/0.6/r2245_scriptdev2.sql b/sql/updates/0.6/r2245_scriptdev2.sql new file mode 100644 index 0000000000..eea7f95492 --- /dev/null +++ b/sql/updates/0.6/r2245_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1542016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1542016,'How long do you beleive your pathetic sorcery can hold me?',0,6,0,0,'magtheridon SAY_MAGTHERIDON_WARN'); diff --git a/sql/updates/0.6/r2246_scriptdev2.sql b/sql/updates/0.6/r2246_scriptdev2.sql new file mode 100644 index 0000000000..a8c5c536bb --- /dev/null +++ b/sql/updates/0.6/r2246_scriptdev2.sql @@ -0,0 +1,208 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1631192 AND -1631001; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1631001,'This is the beginning AND the end, mortals. None may enter the master\'s sanctum!',16950,1,0,0,'marrowgar SAY_INTRO'), +(-1631002,'The Scourge will wash over this world as a swarm of death and destruction!',16941,1,0,0,'marrowgar SAY_AGGRO'), +(-1631003,'BONE STORM!',16946,1,0,0,'marrowgar SAY_BONE_STORM'), +(-1631004,'Bound by bone!',16947,1,0,0,'marrowgar SAY_BONE_SPIKE_1'), +(-1631005,'Stick Around!',16948,1,0,0,'marrowgar SAY_BONE_SPIKE_2'), +(-1631006,'The only escape is death!',16949,1,0,0,'marrowgar SAY_BONE_SPIKE_3'), +(-1631007,'More bones for the offering!',16942,1,0,0,'marrowgar SAY_SLAY_1'), +(-1631008,'Languish in damnation!',16943,1,0,0,'marrowgar SAY_SLAY_2'), +(-1631009,'I see... only darkness...',16944,1,0,0,'marrowgar SAY_DEATH'), +(-1631010,'THE MASTER\'S RAGE COURSES THROUGH ME!',16945,1,0,0,'marrowgar SAY_BERSERK'), + +(-1631011,'You have found your way here, because you are among the few gifted with true vision in a world cursed with blindness.',17272,1,0,0,'deathwhisper SAY_SPEECH_1'), +(-1631012,'You can see through the fog that hangs over this world like a shroud, and grasp where true power lies.',17273,1,0,0,'deathwhisper SAY_SPEECH_2'), +(-1631013,'Fix your eyes upon your crude hands: the sinew, the soft meat, the dark blood coursing within.',16878,1,0,0,'deathwhisper SAY_SPEECH_3'), +(-1631014,'It is a weakness; a crippling flaw.... A joke played by the Creators upon their own creations.',17268,1,0,0,'deathwhisper SAY_SPEECH_4'), +(-1631015,'The sooner you come to accept your condition as a defect, the sooner you will find yourselves in a position to transcend it.',17269,1,0,0,'deathwhisper SAY_SPEECH_5'), +(-1631016,'Through our Master, all things are possible. His power is without limit, and his will unbending.',17270,1,0,0,'deathwhisper SAY_SPEECH_6'), +(-1631017,'Those who oppose him will be destroyed utterly, and those who serve -- who serve wholly, unquestioningly, with utter devotion of mind and soul -- elevated to heights beyond your ken.',17271,1,0,0,'deathwhisper SAY_SPEECH_7'), +(-1631018,'What is this disturbance?! You dare trespass upon this hallowed ground? This shall be your final resting place.',16868,1,0,0,'deathwhisper SAY_AGGRO'), +(-1631019,'Enough! I see I must take matters into my own hands!',16877,1,0,0,'deathwhisper SAY_PHASE_TWO'), +(-1631020,'Take this blessing and show these intruders a taste of our master\'s power.',16873,1,0,0,'deathwhisper SAY_DARK_EMPOWERMENT'), +(-1631021,'I release you from the curse of flesh!',16874,1,0,0,'deathwhisper SAY_DARK_TRANSFORMATION'), +(-1631022,'Arise and exalt in your pure form!',16875,1,0,0,'deathwhisper SAY_ANIMATE_DEAD'), +(-1631023,'You are weak, powerless to resist my will!',16876,1,0,0,'deathwhisper SAY_DOMINATE_MIND'), +(-1631024,'This charade has gone on long enough.',16872,1,0,0,'deathwhisper SAY_BERSERK'), +(-1631025,'All part of the masters plan! Your end is... inevitable!',16871,1,0,0,'deathwhisper SAY_DEATH'), +(-1631026,'Do you yet grasp of the futility of your actions?',16869,1,0,0,'deathwhisper SAY_SLAY_1'), +(-1631027,'Embrace the darkness... Darkness eternal!',16870,1,0,0,'deathwhisper SAY_SLAY_2'), + +(-1631028,'BY THE MIGHT OF THE LICH KING!',16694,1,0,0,'saurfang SAY_AGGRO'), +(-1631029,'The ground runs red with your blood!',16699,1,0,0,'saurfang SAY_FALLENCHAMPION'), +(-1631030,'Feast, my minions!',16700,1,0,0,'saurfang SAY_BLOODBEASTS'), +(-1631031,'You are nothing!',16695,1,0,0,'saurfang SAY_SLAY_1'), +(-1631032,'Your soul will find no redemption here!',16696,1,0,0,'saurfang SAY_SLAY_2'), +(-1631033,'I have become...DEATH!',16698,1,0,0,'saurfang SAY_BERSERK'), +(-1631034,'I... Am... Released.',16697,1,0,0,'saurfang SAY_DEATH'), +(-1631035,'Let\'s get a move on then! Move ou...',16974,1,0,0,'bronzebeard SAY_INTRO_ALLY_0'), +(-1631036,'For every Horde soldier that you killed, for every Alliance dog that fell, the Lich King\'s armies grew. Even now the Val\'kyr work to raise your fallen... As Scourge.',16701,1,0,0,'saurfang SAY_INTRO_ALLY_1'), +(-1631037,'Things are about to get much worse. Come, taste the power that the Lich King has bestowed upon me!',16702,1,0,0,'saurfang SAY_INTRO_ALLY_2'), +(-1631038,'A lone orc, against the might of the Alliance?',16970,1,0,0,'bronzebeard SAY_INTRO_ALLY_3'), +(-1631039,'Charge!',16971,1,0,0,'bronzebeard SAY_INTRO_ALLY_4'), +(-1631040,'Hahahaha! Dwarves...',16703,1,0,0,'saurfang SAY_INTRO_ALLY_5'), +(-1631041,'Kor\'kron, move out! Champions, watch your backs. The Scourge have been..',17103,1,0,0,'overlord SAY_INTRO_HORDE_1'), +(-1631042,'Join me, father. Join me and we will crush this world in the name of the Scourge -- for the glory of the Lich King!',16704,1,0,0,'saurfang SAY_INTRO_HORDE_2'), +(-1631043,'My boy died at the Wrath Gate. I am here only to collect his body.',17097,0,0,0,'overlord SAY_INTRO_HORDE_3'), +(-1631044,'Stubborn and old. What chance do you have? I am stronger, and more powerful than you ever were.',16705,1,0,0,'saurfang SAY_INTRO_HORDE_4'), +(-1631045,'We named him Dranosh. It means "Heart of Draenor" in orcish. I would not let the warlocks take him. My boy would be safe, hidden away by the elders of Garadar.',17098,0,0,0,'overlord SAY_INTRO_HORDE_5'), +(-1631046,'I made a promise to his mother before she died; that I would cross the Dark Portal alone - whether I lived or died, my son would be safe. Untainted...',17099,0,0,0,'overlord SAY_INTRO_HORDE_6'), +(-1631047,'Today, I fulfill that promise.',17100,0,0,0,'overlord SAY_INTRO_HORDE_7'), +(-1631048,'High Overlord Saurfang charges!',17104,2,0,0,'overlord SAY_INTRO_HORDE_8'), +(-1631049,'Pathetic old orc. Come then heroes. Come and face the might of the Scourge!',16706,1,0,0,'saurfang SAY_INTRO_HORDE_9'), +(-1631050,'%s gasps for air',16975,2,0,0,'bronzebeard SAY_OUTRO_ALLY_1'), +(-1631051,'That was Saurfang\'s boy - the Horde commander at the Wrath Gate. Such a tragic end...',16976,0,0,0,'bronzebeard SAY_OUTRO_ALLY_2'), +(-1631052,'What in the... There, in the distance!',16977,0,0,0,'bronzebeard SAY_OUTRO_ALLY_3'), +(-1631053,'Soldiers, fall in! Looks like the Horde are comin\' in to take another shot!',16978,1,0,0,'bronzebeard SAY_OUTRO_ALLY_4'), +(-1631054,'Don\'t force my hand, orc. We can\'t let you pass.',16972,0,0,0,'bronzebeard SAY_OUTRO_ALLY_5'), +(-1631055,'Behind you lies the body of my only son. Nothing will keep me from him.',17094,0,0,0,'overlord SAY_OUTRO_ALLY_6'), +(-1631056,'He... I can\'t do it. Get back on your ship and we\'ll spare your life.',16973,0,0,0,'bronzebeard SAY_OUTRO_ALLY_7'), +(-1631057,'Stand down, Muradin. Let a grieving father pass.',16690,0,0,0,'varian SAY_OUTRO_ALLY_8'), +(-1631058,'No\'ku kil zil\'nok ha tar.',17096,0,1,0,'overlord SAY_OUTRO_ALLY_9'), +(-1631059,'I will not forget this kindess. I thank you, highness.',17095,0,0,0,'overlord SAY_OUTRO_ALLY_10'), +(-1631060,'I... I was not at the Wrathgate. But the soldiers who survived told me much of what happened. Your son fought with honor. He died a hero\'s death. He deserves a hero\'s burial.',16691,0,0,0,'varian SAY_OUTRO_ALLY_11'), +(-1631061,'%s cries.',16651,2,0,0,'proudmore SAY_OUTRO_ALLY_12'), +(-1631062,'Jaina, why are you crying?',16692,0,0,0,'varian SAY_OUTRO_ALLY_13'), +(-1631063,'It was nothing, your majesty. Just... I\'m proud of my king.',16652,0,0,0,'proudmore SAY_OUTRO_ALLY_14'), +(-1631064,'Bah! Muradin, secure the deck and prepare our soldiers for an assault on the upper citadel. I\'ll send out another regiment from Stormwind.',16693,0,0,0,'varian SAY_OUTRO_ALLY_15'), +(-1631065,'Right away, yer majesty!',16979,0,0,0,'bronzebeard SAY_OUTRO_ALLY_16'), +(-1631066,'%s coughs.',17105,2,0,0,'overlord SAY_OUTRO_HORDE_1'), +(-1631067,'%s weeps over the corpse of his son.',17106,2,0,0,'overlord SAY_OUTRO_HORDE_2'), +(-1631068,'You will have a proper ceremony in Nagrand next to the pyres of your mother and ancestors.',17101,0,0,0,'overlord SAY_OUTRO_HORDE_3'), +(-1631069,'Honor, young heroes... no matter how dire the battle... Never forsake it!',17102,0,0,0,'overlord SAY_OUTRO_HORDE_4'), + +(-1631070,'What? Precious? Noooooooooo!!!',16993,6,0,0,'rotface SAY_PRECIOUS_DIES'), +(-1631071,'WEEEEEE!',16986,1,0,0,'rotface SAY_AGGRO'), +(-1631072,'Icky sticky.',16991,1,0,0,'rotface SAY_SLIME_SPRAY'), +(-1631073,'I think I made an angry poo-poo. It gonna blow!',16992,1,0,0,'rotface SAY_OOZE_EXPLODE'), +(-1631074,'Great news, everyone! The slime is flowing again!',17126,1,0,0,'putricide SAY_SLIME_FLOW_1'), +(-1631075,'Good news, everyone! I\'ve fixed the poison slime pipes!',17123,1,0,0,'putricide SAY_SLIME_FLOW_2'), +(-1631076,'Daddy make toys out of you!',16987,1,0,0,'rotface SAY_SLAY_1'), +(-1631077,'I brokes-ded it...',16988,1,0,0,'rotface SAY_SLAY_2'), +(-1631078,'Sleepy Time!',16990,1,0,0,'rotface SAY_BERSERK'), +(-1631079,'Bad news daddy.',16989,1,0,0,'rotface SAY_DEATH'), +(-1631080,'Terrible news, everyone, Rotface is dead! But great news everyone, he left behind plenty of ooze for me to use! Whaa...? I\'m a poet, and I didn\'t know it? Astounding!',17146,6,0,0,'putricide SAY_ROTFACE_DEATH'), + +(-1631081,'NOOOO! You kill Stinky! You pay!',16907,6,0,0,'festergut SAY_STINKY_DIES'), +(-1631082,'Fun time!',16901,1,0,0,'festergut SAY_AGGRO'), +(-1631083,'Just an ordinary gas cloud. But watch out, because that\'s no ordinary gas cloud! ',17119,1,0,0,'putricide SAY_BLIGHT'), +(-1631084,'%s farts.',16911,2,0,0,'festergut SAY_SPORE'), +(-1631085,'Gyah! Uhhh, I not feel so good...',16906,1,0,0,'festergut SAY_PUNGUENT_BLIGHT'), +(-1631086,'%s vomits',0,2,0,0,'festergut SAY_PUNGUENT_BLIGHT_EMOTE'), +(-1631087,'Daddy, I did it',16902,1,0,0,'festergut SAY_SLAY_1'), +(-1631088,'Dead, dead, dead!',16903,1,0,0,'festergut SAY_SLAY_2'), +(-1631089,'Fun time over!',16905,1,0,0,'festergut SAY_BERSERK'), +(-1631090,'Da ... Ddy...',16904,1,0,0,'festergut SAY_DEATH'), +(-1631091,'Oh, Festergut. You were always my favorite. Next to Rotface. The good news is you left behind so much gas, I can practically taste it!',17124,6,0,0,'putricide SAY_FESTERGUT_DEATH'), + +(-1631092,'Good news, everyone! I think I perfected a plague that will destroy all life on Azeroth!',17114,1,0,0,'putricide SAY_AGGRO'), +(-1631093,'You can\'t come in here all dirty like that! You need that nasty flesh scrubbed off first!',17125,1,0,0,'putricide SAY_AIRLOCK'), +(-1631094,'Two oozes, one room! So many delightful possibilities...',17122,1,0,0,'putricide SAY_PHASE_CHANGE'), +(-1631095,'Hmm. I don\'t feel a thing. Whaa...? Where\'d those come from?',17120,1,0,0,'putricide SAY_TRANSFORM_1'), +(-1631096,'Tastes like... Cherry! Oh! Excuse me!',17121,1,0,0,'putricide SAY_TRANSFORM_2'), +(-1631097,'Hmm... Interesting...',17115,1,0,0,'putricide SAY_SLAY_1'), +(-1631098,'That was unexpected!',17116,1,0,0,'putricide SAY_SLAY_2'), +(-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'), +(-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'), +(-1631104,'Blood will flow!',16728,1,0,0,'keleseth SAY_KELESETH_SPECIAL'), +(-1631105,'Were you ever a threat?',16723,1,0,0,'keleseth SAY_KELESETH_SLAY_1'), +(-1631106,'Truth is found in death.',16724,1,0,0,'keleseth SAY_SKELESETH_SLAY_2'), +(-1631107,'%s cackles maniacally!',16726,2,0,0,'keleseth SAY_KELESETH_BERSERK'), +(-1631108,'My queen... they come...',16725,1,0,0,'keleseth SAY_KELESETH_DEATH'), + +(-1631109,'Tremble before Taldaram, mortals, for the power of the orb flows through me!',16857,1,0,0,'taldaram SAY_TALDARAM_INVOCATION'), +(-1631110,'Delight in the pain!',16858,1,0,0,'taldaram SAY_TALDARAM_SPECIAL'), +(-1631111,'Worm food.',16853,1,0,0,'taldaram SAY_TALDARAM_SLAY_1'), +(-1631112,'Beg for mercy!',16854,1,0,0,'taldaram SAY_TALDARAM_SLAY_2'), +(-1631113,'%s laughs.',16856,2,0,0,'taldaram SAY_TALDARAM_BERSERK'), +(-1631114,'%s gurgles and dies.',16855,2,0,0,'taldaram SAY_TALDARAM_DEATH'), + +(-1631115,'Naxxanar was merely a setback! With the power of the orb, Valanar will have his vengeance!',16685,1,0,0,'valanar SAY_VALANAR_INVOCATION'), +(-1631116,'My cup runneth over.',16686,1,0,0,'valanar SAY_VALANAR_SPECIAL'), +(-1631117,'Dinner... is served.',16681,1,0,0,'valanar SAY_VALANAR_SLAY_1'), +(-1631118,'Dinner... is served.',16682,1,0,0,'valanar SAY_VALANAR_SLAY_2'), +(-1631119,'BOW DOWN BEFORE THE SAN\'LAYN!',16684,1,0,0,'valanar SAY_VALANAR_BERSERK'), +(-1631120,'...why...?',16683,1,0,0,'valanar SAY_VALANAR_DEATH'), + +(-1631121,'You have made an... unwise... decision.',16782,1,0,0,'blood_queen SAY_AGGRO'), +(-1631122,'Just a taste...',16783,1,0,0,'blood_queen SAY_BITE_1'), +(-1631123,'Know my hunger!',16784,1,0,0,'blood_queen SAY_BITE_2'), +(-1631124,'SUFFER!',16786,1,0,0,'blood_queen SAY_SHADOWS'), +(-1631125,'Can you handle this?',16787,1,0,0,'blood_queen SAY_PACT'), +(-1631126,'Yes... feed my precious one! You\'re mine now!',16790,1,0,0,'blood_queen SAY_MC'), +(-1631127,'Here it comes.',16788,1,0,0,'blood_queen SAY_AIR_PHASE'), +(-1631128,'THIS ENDS NOW!',16793,1,0,0,'blood_queen SAY_BERSERK'), +(-1631129,'But... we were getting along... so well...',16794,1,0,0,'blood_queen SAY_DEATH'), + +(-1631130,'Ready your arms, my Argent Brothers. The Vrykul will protect the Frost Queen with their lives.',16819,1,0,0,'scourgebane SAY_SVALNA_EVENT_1'), +(-1631131,'Even dying here beats spending another day collecting reagents for that madman, Finklestein.',16585,1,0,0,'arnath SAY_SVALNA_EVENT_2'), +(-1631132,'Enough idle banter! Our champions have arrived - support them as we push our way through the hall!',16820,1,0,0,'scourgebane SAY_SVALNA_EVENT_3'), +(-1631133,'You may have once fought beside me, Crok, but now you are nothing more than a traitor. Come, your second death approaches!',17017,1,0,0,'svalna SAY_SVALNA_EVENT_4'), +(-1631134,'Miserable creatures, Die!',17018,1,0,0,'svalna SAY_KILLING_CRUSADERS'), +(-1631135,'Foolish Crok, you brought my reinforcements with you! Arise Argent Champions and serve the Lich King in death!',17019,1,0,0,'svalna SAY_RESSURECT'), +(-1631136,'Come Scourgebane, I\'ll show the Lich King which one of us is truly worthy of the title, champion!',17020,1,0,0,'svalna SAY_SVALNA_AGGRO'), +(-1631137,'What? They died so easily? No matter.',17022,1,0,0,'svalna SAY_KILL_CAPTAIN'), +(-1631138,'What a pitiful choice of an ally Crok.',17021,1,0,0,'svalna SAY_KILL_PLAYER'), +(-1631139,'Perhaps... you were right... Crok, you must not approach the Frost Queen, quickly, stop them!',17023,1,0,0,'svalna SAY_DEATH'), + +(-1631140,'Heroes, lend me your aid! I... I cannot hold them off much longer! You must heal my wounds!',17064,1,0,0,'dreamwalker SAY_AGGRO'), +(-1631141,'I have opened a portal into the Dream. Your salvation lies within, heroes.',17068,1,0,0,'dreamwalker SAY_PORTAL'), +(-1631142,'My strength is returning! Press on, heroes!',17070,1,0,0,'dreamwalker SAY_75_HEALTH'), +(-1631143,'I will not last much longer!',17069,1,0,0,'dreamwalker SAY_25_HEALTH'), +(-1631144,'Forgive me for what I do! I... cannot... stop... ONLY NIGHTMARES REMAIN!',17072,1,0,0,'dreamwalker SAY_0_HEALTH'), +(-1631145,'A tragic loss...',17066,1,0,0,'dreamwalker SAY_PLAYER_DIES'), +(-1631146,'FAILURES!',17067,1,0,0,'dreamwalker SAY_BERSERK'), +(-1631147,'I am renewed! Ysera grants me the favor to lay these foul creatures to rest!',17071,1,0,0,'dreamwalker SAY_VICTORY'), + +(-1631148,'You are fools who have come to this place! The icy winds of Northrend will consume your souls!',17007,1,0,0,'sindragosa SAY_AGGRO'), +(-1631149,'Suffer, mortals, as your pathetic magic betrays you!',17014,1,0,0,'sindragosa SAY_UNCHAINED_MAGIC'), +(-1631150,'Can you feel the cold hand of death upon your heart?',17013,1,0,0,'sindragosa SAY_BLISTERING_COLD'), +(-1631151,'Aaah! It burns! What sorcery is this?!',17015,1,0,0,'sindragosa SAY_RESPIRE'), +(-1631152,'Your incursion ends here! None shall survive!',17012,1,0,0,'sindragosa SAY_TAKEOFF'), +(-1631153,'Now feel my master\'s limitless power and despair!',17016,1,0,0,'sindragosa SAY_PHASE_3'), +(-1631154,'Perish!',17008,1,0,0,'sindragosa SAY_SLAY_1'), +(-1631155,'A flaw of mortality...',17009,1,0,0,'sindragosa SAY_SLAY_2'), +(-1631156,'Enough! I tire of these games!',17011,1,0,0,'sindragosa SAY_BERSERK'), +(-1631157,'Free...at last...',17010,1,0,0,'sindragosa SAY_DEATH'), + +(-1631158,'So...the Light\'s vaunted justice has finally arrived. Shall I lay down Frostmourne and throw myself at your mercy, Fordring?',17349,1,0,0,'lich_king SAY_INTRO_1'), +(-1631159,'We will grant you a swift death, Arthas. More than can be said for the thousands you\'ve tortured and slain.',17390,1,0,0,'tirion SAY_INTRO_2'), +(-1631160,'You will learn of that first hand. When my work is complete, you will beg for mercy -- and I will deny you. Your anguished cries will be testament to my unbridled power.',17350,1,0,0,'lich_king SAY_INTRO_3'), +(-1631161,'So be it. Champions, attack!',17391,1,0,0,'tirion SAY_INTRO_4'), +(-1631162,'I\'ll keep you alive to witness the end, Fordring. I would not want the Light\'s greatest champion to miss seeing this wretched world remade in my image.',17351,1,0,0,'lich_king SAY_INTRO_5'), +(-1631163,'Come then champions, feed me your rage!',17352,1,0,0,'lich_king SAY_AGGRO'), +(-1631164,'I will freeze you from within until all that remains is an icy husk!',17369,1,0,0,'lich_king SAY_REMORSELESS_WINTER'), +(-1631165,'Watch as the world around you collapses!',17370,1,0,0,'lich_king SAY_SHATTER_ARENA'), +(-1631166,'Val\'kyr, your master calls!',17373,1,0,0,'lich_king SAY_SUMMON_VALKYR'), +(-1631167,'Frostmourne hungers...',17366,1,0,0,'lich_king SAY_HARVEST_SOUL'), +(-1631168,'You have come to bring Arthas to justice? To see the Lich King destroyed?',17394,1,0,0,'terenas SAY_FM_TERENAS_AID_1'), +(-1631169,'First, you must escape Frostmourne\'s hold, or be damned as I am; trapped within this cursed blade for all eternity.',17395,1,0,0,'terenas SAY_FM_TERENAS_AID_2'), +(-1631170,'Aid me in destroying these tortured souls! Together we will loosen Frostmourne\'s hold and weaken the Lich King from within!',17396,1,0,0,'terenas SAY_FM_TERENAS_AID_3'), +(-1631171,'Argh... Frostmourne, obey me!',17367,1,0,0,'lich_king SAY_FM_PLAYER_ESCAPE'), +(-1631172,'Frostmourne feeds on the soul of your fallen ally!',17368,1,0,0,'lich_king SAY_FM_PLAYER_DEATH'), +(-1631173,'Apocalypse!',17371,1,0,0,'lich_king SAY_SPECIAL_1'), +(-1631174,'Bow down before your lord and master!',17372,1,0,0,'lich_king SAY_SPECIAL_2'), +(-1631175,'You gnats actually hurt me! Perhaps I\'ve toyed with you long enough, now taste the vengeance of the grave!',17359,1,0,0,'lich_king SAY_LAST_PHASE'), +(-1631176,'Hope wanes!',17363,1,0,0,'lich_king SAY_SLAY_1'), +(-1631177,'The end has come!',17364,1,0,0,'lich_king SAY_SLAY_2'), +(-1631178,'Face now your tragic end!',17365,1,0,0,'lich_king SAY_ENRAGE'), +(-1631179,'No question remains unanswered. No doubts linger. You are Azeroth\'s greatest champions! You overcame every challenge I laid before you. My mightiest servants have fallen before your relentless onslaught, your unbridled fury...',17353,1,0,0,'lich_king SAY_OUTRO_1'), +(-1631180,'Is it truly righteousness that drives you? I wonder',17354,1,0,0,'lich_king SAY_OUTRO_2'), +(-1631181,'You trained them well, Fordring. You delivered the greatest fighting force this world has ever known... right into my hands -- exactly as I intended. You shall be rewarded for your unwitting sacrifice.',17355,1,0,0,'lich_king SAY_OUTRO_3'), +(-1631182,'Watch now as I raise them from the dead to become masters of the Scourge. They will shroud this world in chaos and destruction. Azeroth\'s fall will come at their hands -- and you will be the first to die.',17356,1,0,0,'lich_king SAY_OUTRO_4'), +(-1631183,'I delight in the irony.',17357,1,0,0,'lich_king SAY_OUTRO_5'), +(-1631184,'LIGHT, GRANT ME ONE FINAL BLESSING. GIVE ME THE STRENGTH... TO SHATTER THESE BONDS!',17392,1,0,0,'tirion SAY_OUTRO_6'), +(-1631185,'Impossible...',17358,1,0,0,'lich_king SAY_OUTRO_7'), +(-1631186,'No more, Arthas! No more lives will be consumed by your hatred!',17393,1,0,0,'tirion SAY_OUTRO_8'), +(-1631187,'Free at last! It is over, my son. This is the moment of reckoning.',17397,1,0,0,'terenas SAY_OUTRO_9'), +(-1631188,'Rise up, champions of the Light!',17398,1,0,0,'terenas SAY_OUTRO_10'), +(-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'); diff --git a/sql/updates/0.6/r2247_scriptdev2.sql b/sql/updates/0.6/r2247_scriptdev2.sql new file mode 100644 index 0000000000..372e84ba62 --- /dev/null +++ b/sql/updates/0.6/r2247_scriptdev2.sql @@ -0,0 +1,37 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1616034 AND -1616000; +INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,comment) VALUES +(-1616000,'Lesser beings, intruding here! A shame that your excess courage does not compensate for your stupidity!',14512,1,0,0,'malygos SAY_INTRO_1'), +(-1616001,'None but the blue dragonflight are welcome here! Perhaps this is the work of Alexstrasza? Well then, she has sent you to your deaths.',14513,1,0,0,'malygos SAY_INTRO_2'), +(-1616002,'What could you hope to accomplish, to storm brazenly into my domain? To employ MAGIC? Against ME? ',14514,1,0,0,'malygos SAY_INTRO_3'), +(-1616003,'I am without limits here... the rules of your cherished reality do not apply... In this realm, I am in control...',14515,1,0,0,'malygos SAY_INTRO_4'), +(-1616004,'I give you one chance. Pledge fealty to me, and perhaps I won''t slaughter you for your insolence!',14516,1,0,0,'malygos SAY_INTRO_5'), +(-1616005,'My patience has reached its limit, I WILL BE RID OF YOU!',14517,1,0,0,'malygos SAY_AGGRO'), +(-1616006,'Watch helplessly as your hopes are swept away...',14525,1,0,0,'malygos SAY_VORTEX'), +(-1616007,'I AM UNSTOPPABLE!',14533,1,0,0,'malygos SAY_SPARK_BUFF'), +(-1616008,'Your stupidity has finally caught up to you!',14519,1,0,0,'malygos SAY_SLAY_1_A'), +(-1616009,'More artifacts to confiscate...',14520,1,0,0,'malygos SAY_SLAY_1_B'), +(-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'), +(-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'), +(-1616017,'Your spirit will linger here forever!',14528,1,0,0, 'malygos SAY_SLAY_2_C'), +(-1616018,'ENOUGH! If you intend to reclaim Azeroth\'s magic, then you shall have it...',14529,1,0,0,'malygos SAY_END_PHASE_2'), +(-1616019,'Now your benefactors make their appearance...But they are too late. The powers contained here are sufficient to destroy the world ten times over! What do you think they will do to you?',14530,1,0,0,'malygos SAY_INTRO_PHASE_3'), +(-1616020,'SUBMIT!',14531,1,0,0,'malygos SAY_START_PHASE_3'), +(-1616021,'Alexstrasza! Another of your brood falls!',14534,1,0,0,'malygos SAY_SLAY_3_A'), +(-1616022,'Little more then gnats!',14535,1,0,0,'malygos SAY_SLAY_3_B'), +(-1616023,'Your red allies will share your fate...',14536,1,0,1,'malygos SAY_SLAY_3_C'), +(-1616024,'The powers at work here exceed anything you could possibly imagine!',14532,1,0,0,'malygos SAY_SURGE'), +(-1616025,'Still standing? Not for long...',14537,1,0,0,'malygos SAY_SPELL_1'), +(-1616026,'Your cause is lost!',14538,1,0,0,'malygos SAY_SPELL_2'), +(-1616027,'Your fragile mind will be shattered!',14539,1,0,0,'malygos SAY_SPELL_3'), +(-1616028,'UNTHINKABLE! The mortals will destroy... e-everything... my sister... what have you-',14540,1,0,0,'malygos SAY_DEATH'), +(-1616029,'I did what I had to, brother. You gave me no alternative.',14406,1,0,1,'alextrasza SAY_OUTRO_1'), +(-1616030,'And so ends the Nexus War.',14407,1,0,1,'alextrasza SAY_OUTRO_2'), +(-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'); diff --git a/sql/updates/0.6/r2248_scriptdev2.sql b/sql/updates/0.6/r2248_scriptdev2.sql new file mode 100644 index 0000000000..17d9f58db9 --- /dev/null +++ b/sql/updates/0.6/r2248_scriptdev2.sql @@ -0,0 +1,5 @@ +UPDATE script_texts SET content_default='Your forces are nearly marshalled to strike back against your enemies, my liege.', type=6 WHERE entry = -1533084; +UPDATE script_texts SET content_default='Soon we will eradicate the Alliance and Horde, then the rest of Azeroth will fall before the might of my army.', type=6, sound=14768, comment='lich_king SAY_SAPP_DIALOG2_LICH' WHERE entry = -1533085; +UPDATE script_texts SET content_default='Yes, Master. The time of their ultimate demise grows close...What is this?', type=6 WHERE entry = -1533086; +UPDATE script_texts SET content_default='Invaders...here?! DESTROY them, Kel\'Thuzad! Naxxramas must not fall!', type=6, sound=14769, comment='lich_king SAY_SAPP_DIALOG4_LICH' WHERE entry = -1533087; +UPDATE script_texts SET content_default='As you command, Master!', type=6 WHERE entry = -1533088; diff --git a/sql/updates/0.6/r2249_scriptdev2.sql b/sql/updates/0.6/r2249_scriptdev2.sql new file mode 100644 index 0000000000..ea5786d7d8 --- /dev/null +++ b/sql/updates/0.6/r2249_scriptdev2.sql @@ -0,0 +1,2 @@ +UPDATE script_texts SET content_default='Impudent whelps! You\'ve rushed headlong to your own deaths! See now, the master stirs!' WHERE entry=-1409024; +UPDATE script_texts SET content_default='I give you one chance. Pledge fealty to me, and perhaps I won\'t slaughter you for your insolence!' WHERE entry=-1616004; diff --git a/sql/updates/0.6/r2250_mangos.sql b/sql/updates/0.6/r2250_mangos.sql new file mode 100644 index 0000000000..8ea3fd994f --- /dev/null +++ b/sql/updates/0.6/r2250_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_barrett_ramsey' WHERE entry IN (34816, 35035, 35766, 35770, 35771); diff --git a/sql/updates/0.6/r2250_scriptdev2.sql b/sql/updates/0.6/r2250_scriptdev2.sql new file mode 100644 index 0000000000..1f16702e32 --- /dev/null +++ b/sql/updates/0.6/r2250_scriptdev2.sql @@ -0,0 +1,18 @@ +UPDATE script_texts SET comment='varian SAY_VARIAN_PVP_H_INTRO_2' WHERE entry=-1649024; +UPDATE script_texts SET comment='garrosh SAY_GARROSH_PVP_A_INTRO_2' WHERE entry=-1649025; +UPDATE script_texts SET content_default='GLORY TO THE ALLIANCE!' WHERE entry=-1649026; +UPDATE script_texts SET content_default='Ahhh, our guests have arrived, just as the master promised.' WHERE entry=-1649038; + +UPDATE gossip_texts SET comment='barrett GOSSIP_ITEM_BEAST_INIT' WHERE entry=-3649000; +DELETE FROM gossip_texts WHERE entry BETWEEN -3649010 AND -3649001; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3649001,'Bring forth the first challenge!','barrett GOSSIP_ITEM_BEAST_START'), +(-3649002,'We want another shot at those beasts!','barrett GOSSIP_ITEM_BEAST_WIPE_INIT'), +(-3649003,'What new challenge awaits us?','barrett GOSSIP_ITEM_JARAXXUS_INIT'), +(-3649004,'We\'re ready to fight the sorceror again.','barrett GOSSIP_ITEM_JARAXXUS_WIPE_INIT'), +(-3649005,'Of course!','barrett GOSSIP_ITEM_PVP_INIT'), +(-3649006,'Give the signal! We\'re ready to go!','barrett GOSSIP_ITEM_PVP_START'), +(-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'); diff --git a/sql/updates/0.6/r2252_mangos.sql b/sql/updates/0.6/r2252_mangos.sql new file mode 100644 index 0000000000..87a7855716 --- /dev/null +++ b/sql/updates/0.6/r2252_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_beast_combat_stalker' WHERE entry=36549; diff --git a/sql/updates/0.6/r2254_scriptdev2.sql b/sql/updates/0.6/r2254_scriptdev2.sql new file mode 100644 index 0000000000..53dc1f60d8 --- /dev/null +++ b/sql/updates/0.6/r2254_scriptdev2.sql @@ -0,0 +1 @@ +DELETE FROM script_waypoint WHERE entry=18731; diff --git a/sql/updates/0.6/r2255_mangos.sql b/sql/updates/0.6/r2255_mangos.sql new file mode 100644 index 0000000000..e49bd9df7d --- /dev/null +++ b/sql/updates/0.6/r2255_mangos.sql @@ -0,0 +1,6 @@ +DELETE FROM scripted_areatrigger WHERE entry=4937; +INSERT INTO scripted_areatrigger VALUES (4937, 'at_sunwell_plateau'); + +UPDATE creature_template SET ScriptName='boss_alythess' WHERE entry=25166; +UPDATE creature_template SET ScriptName='boss_sacrolash' WHERE entry=25165; +UPDATE creature_template SET ScriptName='npc_shadow_image' WHERE entry=25214; diff --git a/sql/updates/0.6/r2263_mangos.sql b/sql/updates/0.6/r2263_mangos.sql new file mode 100644 index 0000000000..2164eb593b --- /dev/null +++ b/sql/updates/0.6/r2263_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='boss_general_vezax' WHERE entry=33271; +DELETE FROM scripted_event_id WHERE id=9735; +INSERT INTO scripted_event_id VALUES +(9735,'event_spell_saronite_barrier'); diff --git a/sql/updates/0.6/r2268_mangos.sql b/sql/updates/0.6/r2268_mangos.sql new file mode 100644 index 0000000000..0188cf53da --- /dev/null +++ b/sql/updates/0.6/r2268_mangos.sql @@ -0,0 +1,2 @@ +DELETE FROM scripted_areatrigger WHERE entry=4524; +INSERT INTO scripted_areatrigger VALUES (4524,'at_shattered_halls'); diff --git a/sql/updates/0.6/r2268_scriptdev2.sql b/sql/updates/0.6/r2268_scriptdev2.sql new file mode 100644 index 0000000000..3ec82ad32f --- /dev/null +++ b/sql/updates/0.6/r2268_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1540048, -1540049, -1540050); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1540048,'Cowards! You\'ll never pull me into the shadows!',0,1,0,0,'kargath SAY_EVADE'), +(-1540049,'The Alliance dares to intrude this far into my fortress? Bring out the Honor Hold prisoners and call for the executioner! They\'ll pay with their lives for this trespass!',0,6,0,0,'kargath SAY_EXECUTE_ALLY'), +(-1540050,'It looks like we have a ranking officer among our captives...how amusing. Execute the green-skinned dog at once!',0,6,0,0,'kargath SAY_EXECUTE_HORDE'); diff --git a/sql/updates/0.6/r2270_scriptdev2.sql b/sql/updates/0.6/r2270_scriptdev2.sql new file mode 100644 index 0000000000..95b485a916 --- /dev/null +++ b/sql/updates/0.6/r2270_scriptdev2.sql @@ -0,0 +1,2 @@ +UPDATE script_texts SET content_default='Do you see NOW the power of the Darkfallen?' WHERE entry=-1631118; +UPDATE script_texts SET content_default='Perhaps... you were right... Crok.' WHERE entry=-1631139; diff --git a/sql/updates/0.6/r2273_mangos.sql b/sql/updates/0.6/r2273_mangos.sql new file mode 100644 index 0000000000..46cdc72f86 --- /dev/null +++ b/sql/updates/0.6/r2273_mangos.sql @@ -0,0 +1,6 @@ +DELETE FROM world_template WHERE map IN (0, 1, 530, 571); +INSERT INTO world_template VALUES +(0, 'world_map_eastern_kingdoms'), +(1, 'world_map_kalimdor'), +(530, 'world_map_outland'), +(571, 'world_map_northrend'); diff --git a/sql/updates/0.6/r2277_scriptdev2.sql b/sql/updates/0.6/r2277_scriptdev2.sql new file mode 100644 index 0000000000..933e10cdd1 --- /dev/null +++ b/sql/updates/0.6/r2277_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='I must make the necessary preparations before the awakening ritual can begin. You must protect me!' WHERE entry=-1043001; diff --git a/sql/updates/0.6/r2284_scriptdev2.sql b/sql/updates/0.6/r2284_scriptdev2.sql new file mode 100644 index 0000000000..fe4c2f731f --- /dev/null +++ b/sql/updates/0.6/r2284_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry IN (-1568082,-1568083,-1568084,-1568085); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1568082,'%s absorbs the essence of the bear spirit!',0,2,0,0,'zuljin EMOTE_BEAR_SPIRIT'), +(-1568083,'%s absorbs the essence of the eagle spirit!',0,2,0,0,'zuljin EMOTE_EAGLE_SPIRIT'), +(-1568084,'%s absorbs the essence of the lynx spirit!',0,2,0,0,'zuljin EMOTE_LYNX_SPIRIT'), +(-1568085,'%s absorbs the essence of the dragonhawk spirit!',0,2,0,0,'zuljin EMOTE_DRAGONHAWK_SPIRIT'); \ No newline at end of file diff --git a/sql/updates/0.6/r2286_mangos.sql b/sql/updates/0.6/r2286_mangos.sql new file mode 100644 index 0000000000..3fc888726d --- /dev/null +++ b/sql/updates/0.6/r2286_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18538; diff --git a/sql/updates/0.6/r2289_mangos.sql b/sql/updates/0.6/r2289_mangos.sql new file mode 100644 index 0000000000..76dbc52244 --- /dev/null +++ b/sql/updates/0.6/r2289_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_keeper_remulos' WHERE entry=11832; +UPDATE creature_template SET ScriptName='boss_eranikus' WHERE entry=15491; diff --git a/sql/updates/0.6/r2289_scriptdev2.sql b/sql/updates/0.6/r2289_scriptdev2.sql new file mode 100644 index 0000000000..e147711841 --- /dev/null +++ b/sql/updates/0.6/r2289_scriptdev2.sql @@ -0,0 +1,76 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000706 AND -1000669; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000669,'We will locate the origin of the Nightmare through the fragments you collected, $N. From there, we will pull Eranikus through a rift in the Dream. Steel yourself, $C. We are inviting the embodiment of the Nightmare into our world.',0,0,0,0,'remulos SAY_REMULOS_INTRO_1'), +(-1000670,'To Nighthaven! Keep your army close, champion. ',0,0,0,0,'remulos SAY_REMULOS_INTRO_2'), +(-1000671,'The rift will be opened there, above the Lake Elun\'ara. Prepare yourself, $N. Eranikus entry into our world will be wrought with chaos and strife.',0,0,0,0,'remulos SAY_REMULOS_INTRO_3'), +(-1000672,'He will stop at nothing to get to Malfurion\'s physical manifistation. That must not happen... We must keep the beast occupied long enough for Tyrande to arrive.',0,0,0,0,'remulos SAY_REMULOS_INTRO_4'), +(-1000673,'Defend Nightaven, hero...',0,0,0,0,'remulos SAY_REMULOS_INTRO_5'), +(-1000674,'%s has entered our world',0,3,0,0,'eranikus EMOTE_SUMMON_ERANIKUS'), +(-1000675,'Pitful predictable mortals... You know not what you have done! The master\'s will fulfilled. The Moonglade shall be destroyed and Malfurion along with it!',0,1,0,0,'eranikus SAY_ERANIKUS_SPAWN'), +(-1000676,'Fiend! Face the might of Cenarius!',0,1,0,1,'remulos SAY_REMULOS_TAUNT_1'), +(-1000677,'%s lets loose a sinister laugh.',0,2,0,0,'eranikus EMOTE_ERANIKUS_LAUGH'), +(-1000678,'You are certanly not your father, insect. Should it interest me, I would crush you with but a swipe of my claws. Turn Shan\'do Stormrage over to me and your pitiful life will be spared along with the lives of your people.',0,1,0,0,'eranikus SAY_ERANIKUS_TAUNT_2'), +(-1000679,'Who is the predictable one, beast? Surely you did not think that we would summon you on top of Malfurion? Your redemption comes, Eranikus. You will be cleansed of this madness - this corruption.',0,1,0,1,'remulos SAY_REMULOS_TAUNT_3'), +(-1000680,'My redemption? You are bold, little one. My redemption comes by the will of my god.',0,1,0,0,'eranikus SAY_ERANIKUS_TAUNT_4'), +(-1000681,'%s roars furiously.',0,2,0,0,'eranikus EMOTE_ERANIKUS_ATTACK'), +(-1000682,'Hurry, $N! We must find protective cover!',0,0,0,0,'remulos SAY_REMULOS_DEFEND_1'), +(-1000683,'Please, champion, protect our people.',0,0,0,1,'remulos SAY_REMULOS_DEFEND_2'), +(-1000684,'Rise, servants of the Nightmare! Rise and destroy this world! Let there be no survivors...',0,1,0,0,'eranikus SAY_ERANIKUS_SHADOWS'), +(-1000685,'We will battle these fiends, together! Nighthaven\'s Defenders are also among us. They will fight to the death if asked. Now, quickly, we must drive these aberations back to the Nightmare. Destroy them all!',0,0,0,1,'remulos SAY_REMULOS_DEFEND_3'), +(-1000686,'Where is your savior? How long can you hold out against my attacks?',0,1,0,0,'eranikus SAY_ERANIKUS_ATTACK_1'), +(-1000687,'Defeated my minions? Then face me, mortals!',0,1,0,0,'eranikus SAY_ERANIKUS_ATTACK_2'), +(-1000688,'Remulos, look how easy they fall before me? You can stop this, fool. Turn the druid over to me and it will all be over...',0,1,0,0,'eranikus SAY_ERANIKUS_ATTACK_3'), +(-1000689,'Elune, hear my prayers. Grant us serenity! Watch over our fallen...',0,1,0,0,'tyrande SAY_TYRANDE_APPEAR'), +(-1000690,'Tend to the injuries of the wounded, sisters!',0,0,0,0,'tyrande SAY_TYRANDE_HEAL'), +(-1000691,'Seek absolution, Eranikus. All will be forgiven...',0,1,0,0,'tyrande SAY_TYRANDE_FORGIVEN_1'), +(-1000692,'You will be forgiven, Eranikus. Elune will always love you. Break free of the bonds that command you!',0,1,0,0,'tyrande SAY_TYRANDE_FORGIVEN_2'), +(-1000693,'The grasp of the Old Gods is unmoving. He is consumed by their dark thoughts... I... I... I cannot... cannot channel much longer... Elune aide me.',0,0,0,0,'tyrande SAY_TYRANDE_FORGIVEN_3'), +(-1000694,'IT BURNS! THE PAIN.. SEARING...',0,1,0,0,'eranikus SAY_ERANIKUS_DEFEAT_1'), +(-1000695,'WHY? Why did this happen to... to me? Where were you Tyrande? Where were you when I fell from the grace of Elune?',0,1,0,0,'eranikus SAY_ERANIKUS_DEFEAT_2'), +(-1000696,'I... I feel... I feel the touch of Elune upon my being once more... She smiles upon me... Yes... I...', 0,1,0,0,'eranikus SAY_ERANIKUS_DEFEAT_3'), +(-1000697,'%s is wholly consumed by the Light of Elune. Tranquility sets in over the Moonglade',0,2,0,0,'eranikus EMOTE_ERANIKUS_REDEEM'), +(-1000698,'%s falls to one knee.',0,2,0,0,'tyrande EMOTE_TYRANDE_KNEEL'), +(-1000699,'Praise be to Elune... Eranikus is redeemed.',0,1,0,0,'tyrande SAY_TYRANDE_REDEEMED'), +(-1000700,'For so long, I was lost... The Nightmare\'s corruption had consumed me... And now, you... all of you.. you have saved me. Released me from its grasp.',0,0,0,0,'eranikus SAY_REDEEMED_1'), +(-1000701,'But... Malfurion, Cenarius, Ysera... They still fight. They need me. I must return to the Dream at once.', 0,0,0,0,'eranikus SAY_REDEEMED_2'), +(-1000702,'My lady, I am unworthy of your prayer. Truly, you are an angel of light. Please, assist me in returning to the barrow den so that I may return to the Dream. I like Malfurion, also have a love awaiting me... I must return to her... to protect her...', 0,0,0,0,'eranikus SAY_REDEEMED_3'), +(-1000703,'And heroes... I hold that which you seek. May it once more see the evil dissolved. Remulos, see to it that our champion receives the shard of the Green Flight.',0,0,0,0,'eranikus SAY_REDEEMED_4'), +(-1000704,'It will be done, Eranikus. Be well, ancient one.',0,0,0,0,'remulos SAY_REMULOS_OUTRO_1'), +(-1000705,'Let us leave Nighthave, hero. Seek me out at the grove.',0,0,0,0,'remulos SAY_REMULOS_OUTRO_2'), +(-1000706,'Your world shall suffer an unmerciful end. The Nightmare comes for you!',0,0,0,0,'eranikus SAY_ERANIKUS_KILL'); + +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'), +(11832, 1, 7848.385645, -2216.356670, 470.888333, 5000, 'SAY_REMULOS_INTRO_2'), +(11832, 2, 7829.785645, -2244.836670, 463.853333, 0, ''), +(11832, 3, 7819.010742, -2304.344238, 455.956726, 0, ''), +(11832, 4, 7931.099121, -2314.350830, 473.054047, 0, ''), +(11832, 5, 7943.553223, -2324.688721, 477.676819, 0, ''), +(11832, 6, 7952.017578, -2351.135010, 485.234924, 0, ''), +(11832, 7, 7963.672852, -2412.990967, 488.953369, 0, ''), +(11832, 8, 7975.178223, -2551.602051, 490.079926, 0, ''), +(11832, 9, 7948.046875, -2570.828613, 489.750732, 0, ''), +(11832, 10, 7947.161133, -2583.396729, 490.066284, 0, ''), +(11832, 11, 7951.086426, -2596.215088, 489.831268, 0, ''), +(11832, 12, 7948.267090, -2610.062988, 492.340424, 0, ''), +(11832, 13, 7928.521973, -2625.954346, 492.447540, 14000, 'SAY_REMULOS_INTRO_3'), +(11832, 14, 7928.521973, -2625.954346, 492.447540, 12000, 'SAY_REMULOS_INTRO_4'), +(11832, 15, 7928.521973, -2625.954346, 492.447540, 5000, 'SAY_REMULOS_INTRO_5'), +(11832, 16, 7928.521973, -2625.954346, 492.447540, 13000, 'SPELL_CONJURE_RIFT'), +(11832, 17, 7928.521973, -2625.954346, 492.447540, 11000, 'SAY_ERANIKUS_SPAWN'), +(11832, 18, 7928.521973, -2625.954346, 492.447540, 5000, 'SAY_REMULOS_TAUNT_1'), +(11832, 19, 7928.521973, -2625.954346, 492.447540, 3000, 'EMOTE_ERANIKUS_LAUGH'), +(11832, 20, 7928.521973, -2625.954346, 492.447540, 10000, 'SAY_ERANIKUS_TAUNT_2'), +(11832, 21, 7928.521973, -2625.954346, 492.447540, 12000, 'SAY_REMULOS_TAUNT_3'), +(11832, 22, 7928.521973, -2625.954346, 492.447540, 6000, 'SAY_ERANIKUS_TAUNT_4'), +(11832, 23, 7928.521973, -2625.954346, 492.447540, 7000, 'EMOTE_ERANIKUS_ATTACK'), +(11832, 24, 7928.521973, -2625.954346, 492.447540, 0, 'SAY_REMULOS_DEFEND_1 - eranikus flies up'), +(11832, 25, 7948.267090, -2610.062988, 492.340424, 0, ''), +(11832, 26, 7952.318848, -2594.118408, 490.070374, 0, ''), +(11832, 27, 7913.988770, -2567.002686, 488.330566, 0, ''), +(11832, 28, 7835.454102, -2571.099121, 489.289246, 6000, 'SAY_REMULOS_DEFEND_2'), +(11832, 29, 7835.454102, -2571.099121, 489.289246, 4000, 'SAY_ERANIKUS_SHADOWS'), +(11832, 30, 7835.454102, -2571.099121, 489.289246, 0, 'SAY_REMULOS_DEFEND_3 - escort paused'), +(11832, 31, 7897.283691, -2560.652344, 487.461304, 0, ''), +(11832, 32, 7897.283691, -2560.652344, 487.461304, 0, ''); diff --git a/sql/updates/0.6/r2298_scriptdev2.sql b/sql/updates/0.6/r2298_scriptdev2.sql new file mode 100644 index 0000000000..965fab0ced --- /dev/null +++ b/sql/updates/0.6/r2298_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='$N is impaled!' WHERE entry=-1604030; diff --git a/sql/updates/0.6/r2300_scriptdev2.sql b/sql/updates/0.6/r2300_scriptdev2.sql new file mode 100644 index 0000000000..cdfd62dc90 --- /dev/null +++ b/sql/updates/0.6/r2300_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1036000, -1036001); diff --git a/sql/updates/0.6/r2305_scriptdev2.sql b/sql/updates/0.6/r2305_scriptdev2.sql new file mode 100644 index 0000000000..2965bfc8c1 --- /dev/null +++ b/sql/updates/0.6/r2305_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11812+) '; diff --git a/sql/updates/0.6/r2306_mangos.sql b/sql/updates/0.6/r2306_mangos.sql new file mode 100644 index 0000000000..fcfcff321b --- /dev/null +++ b/sql/updates/0.6/r2306_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=101833; diff --git a/sql/updates/0.6/r2307_mangos.sql b/sql/updates/0.6/r2307_mangos.sql new file mode 100644 index 0000000000..7e09bb2a0d --- /dev/null +++ b/sql/updates/0.6/r2307_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_auriaya' WHERE entry=33515; +UPDATE creature_template SET ScriptName='boss_feral_defender' WHERE entry=34035; diff --git a/sql/updates/0.6/r2309_mangos.sql b/sql/updates/0.6/r2309_mangos.sql new file mode 100644 index 0000000000..c5227c910c --- /dev/null +++ b/sql/updates/0.6/r2309_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_ranshalla' WHERE entry=10300; +UPDATE gameobject_template SET ScriptName='go_elune_fire' WHERE entry IN (177417, 177404); diff --git a/sql/updates/0.6/r2309_scriptdev2.sql b/sql/updates/0.6/r2309_scriptdev2.sql new file mode 100644 index 0000000000..8d4a935703 --- /dev/null +++ b/sql/updates/0.6/r2309_scriptdev2.sql @@ -0,0 +1,82 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000739 AND -1000707; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000707,'This blue light... It\'s strange. What do you think it means?',0,0,0,0,'Ranshalla SAY_ENTER_OWL_THICKET'), +(-1000708,'We\'ve found it!',0,0,0,0,'Ranshalla SAY_REACH_TORCH_1'), +(-1000709,'Please, light this while I am channeling',0,0,0,0,'Ranshalla SAY_REACH_TORCH_2'), +(-1000710,'This is the place. Let\'s light it.',0,0,0,0,'Ranshalla SAY_REACH_TORCH_3'), +(-1000711,'Let\'s find the next one.',0,0,0,0,'Ranshalla SAY_AFTER_TORCH_1'), +(-1000712,'We must continue on now.',0,0,0,0,'Ranshalla SAY_AFTER_TORCH_2'), +(-1000713,'It is time for the final step; we must activate the altar.',0,0,0,0,'Ranshalla SAY_REACH_ALTAR_1'), +(-1000714,'I will read the words carved into the stone, and you must find a way to light it.',0,0,0,0,'Ranshalla SAY_REACH_ALTAR_2'), +(-1000715,'The altar is glowing! We have done it!',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_1'), +(-1000716,'What is happening? Look!',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_2'), +(-1000717,'It has been many years...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_3'), +(-1000718,'Who has disturbed the altar of the goddess?',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_4'), +(-1000719,'Please, priestesses, forgive us for our intrusion. We do not wish any harm here.',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_5'), +(-1000720,'We only wish to know why the wildkin guard this area...',0,0,0,0,'Ranshalla SAY_RANSHALLA_ALTAR_6'), +(-1000721,'Enu thora\'serador. This is a sacred place.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_7'), +(-1000722,'We will show you...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_8'), +(-1000723,'Look above you; thara dormil dorah...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_9'), +(-1000724,'This gem once allowed direct communication with Elune, herself.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_10'), +(-1000725,'Through the gem, Elune channeled her infinite wisdom...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_11'), +(-1000726,'Realizing that the gem needed to be protected, we turned to the goddess herself.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_12'), +(-1000727,'Soon after, we began to have visions of a creature... A creature with the feathers of an owl, but the will and might of a bear...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_13'), +(-1000728,'It was on that day that the wildkin were given to us. Fierce guardians, the goddess assigned the wildkin to protect all of her sacred places.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_14'), +(-1000729,'Anu\'dorini Talah, Ru shallora enudoril.',0,0,0,0,'Voice of Elune SAY_VOICE_ALTAR_15'), +(-1000730,'But now, many years later, the wildkin have grown more feral, and without the guidance of the goddess, they are confused...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_16'), +(-1000731,'Without a purpose, they wander... But many find their way back to the sacred areas that they once were sworn to protect.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_17'), +(-1000732,'Wildkin are inherently magical; this power was bestowed upon them by the goddess.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_18'), +(-1000733,'Know that wherever you might find them in the world, they are protecting something of importance, as they were entrusted to do so long ago.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_19'), +(-1000734,'Please, remember what we have shown you...',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_20'), +(-1000735,'Farewell.',0,0,0,0,'Priestess of Elune SAY_PRIESTESS_ALTAR_21'), +(-1000736,'Thank you for you help, $n. I wish you well in your adventures.',0,0,0,0,'Ranshalla SAY_QUEST_END_1'), +(-1000737,'I want to stay here and reflect on what we have seen. Please see Erelas and tell him what we have learned.',0,0,0,0,'Ranshalla SAY_QUEST_END_2'), +(-1000738,'%s begins chanting a strange spell...',0,2,0,0,'Ranshalla EMOTE_CHANT_SPELL'), +(-1000739,'Remember, I need your help to properly channel. I will ask you to aid me several times in our path, so please be ready.',0,0,0,0,'Ranshalla SAY_QUEST_START'); + +DELETE FROM script_waypoint WHERE entry=10300; +INSERT INTO script_waypoint VALUES +(10300, 1, 5728.81, -4801.15, 778.18, 0, ''), +(10300, 2, 5730.22, -4818.34, 777.11, 0, ''), +(10300, 3, 5728.12, -4835.76, 778.15, 1000, 'SAY_ENTER_OWL_THICKET'), +(10300, 4, 5718.85, -4865.62, 787.56, 0, ''), +(10300, 5, 5697.13, -4909.12, 801.53, 0, ''), +(10300, 6, 5684.20, -4913.75, 801.60, 0, ''), +(10300, 7, 5674.67, -4915.78, 802.13, 0, ''), +(10300, 8, 5665.61, -4919.22, 804.85, 0, ''), +(10300, 9, 5638.22, -4897.58, 804.97, 0, ''), +(10300, 10, 5632.67, -4892.05, 805.44, 0, 'Cavern 1 - EMOTE_CHANT_SPELL'), +(10300, 11, 5664.58, -4921.84, 804.91, 0, ''), +(10300, 12, 5684.21, -4943.81, 802.80, 0, ''), +(10300, 13, 5724.92, -4983.69, 808.25, 0, ''), +(10300, 14, 5753.39, -4990.73, 809.84, 0, ''), +(10300, 15, 5765.62, -4994.89, 809.42, 0, 'Cavern 2 - EMOTE_CHANT_SPELL'), +(10300, 16, 5724.94, -4983.58, 808.29, 0, ''), +(10300, 17, 5699.61, -4989.82, 808.03, 0, ''), +(10300, 18, 5686.80, -5012.17, 807.27, 0, ''), +(10300, 19, 5691.43, -5037.43, 807.73, 0, ''), +(10300, 20, 5694.24, -5054.64, 808.85, 0, 'Cavern 3 - EMOTE_CHANT_SPELL'), +(10300, 21, 5686.88, -5012.18, 807.23, 0, ''), +(10300, 22, 5664.94, -5001.12, 807.78, 0, ''), +(10300, 23, 5647.12, -5002.84, 807.54, 0, ''), +(10300, 24, 5629.23, -5014.88, 807.94, 0, ''), +(10300, 25, 5611.26, -5025.62, 808.36, 0, 'Cavern 4 - EMOTE_CHANT_SPELL'), +(10300, 26, 5647.13, -5002.85, 807.57, 0, ''), +(10300, 27, 5641.12, -4973.22, 809.39, 0, ''), +(10300, 28, 5622.97, -4953.58, 811.12, 0, ''), +(10300, 29, 5601.52, -4939.49, 820.77, 0, ''), +(10300, 30, 5571.87, -4936.22, 831.35, 0, ''), +(10300, 31, 5543.23, -4933.67, 838.33, 0, ''), +(10300, 32, 5520.86, -4942.05, 843.02, 0, ''), +(10300, 33, 5509.15, -4946.31, 849.36, 0, ''), +(10300, 34, 5498.45, -4950.08, 849.98, 0, ''), +(10300, 35, 5485.78, -4963.40, 850.43, 0, ''), +(10300, 36, 5467.92, -4980.67, 851.89, 0, 'Cavern 5 - EMOTE_CHANT_SPELL'), +(10300, 37, 5498.68, -4950.45, 849.96, 0, ''), +(10300, 38, 5518.68, -4921.94, 844.65, 0, ''), +(10300, 39, 5517.66, -4920.82, 845.12, 0, 'SAY_REACH_ALTAR_1'), +(10300, 40, 5518.38, -4913.47, 845.57, 0, ''), +(10300, 41, 5511.31, -4913.82, 847.17, 5000, 'light the spotlights'), +(10300, 42, 5511.31, -4913.82, 847.17, 0, 'start altar cinematic - SAY_RANSHALLA_ALTAR_2'), +(10300, 43, 5510.36, -4921.17, 846.33, 0, ''), +(10300, 44, 5517.66, -4920.82, 845.12, 0, 'escort paused'); diff --git a/sql/updates/0.6/r2310_scriptdev2.sql b/sql/updates/0.6/r2310_scriptdev2.sql new file mode 100644 index 0000000000..4f2ed914bd --- /dev/null +++ b/sql/updates/0.6/r2310_scriptdev2.sql @@ -0,0 +1,21 @@ +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'), +(11832, 1, 7848.385645, -2216.356670, 470.888333, 5000, 'SAY_REMULOS_INTRO_2'), +(11832, 2, 7829.785645, -2244.836670, 463.853333, 0, ''), +(11832, 3, 7819.010742, -2304.344238, 455.956726, 0, ''), +(11832, 4, 7931.099121, -2314.350830, 473.054047, 0, ''), +(11832, 5, 7943.553223, -2324.688721, 477.676819, 0, ''), +(11832, 6, 7952.017578, -2351.135010, 485.234924, 0, ''), +(11832, 7, 7963.672852, -2412.990967, 488.953369, 0, ''), +(11832, 8, 7975.178223, -2551.602051, 490.079926, 0, ''), +(11832, 9, 7948.046875, -2570.828613, 489.750732, 0, ''), +(11832, 10, 7947.161133, -2583.396729, 490.066284, 0, ''), +(11832, 11, 7951.086426, -2596.215088, 489.831268, 0, ''), +(11832, 12, 7948.267090, -2610.062988, 492.340424, 0, ''), +(11832, 13, 7928.521973, -2625.954346, 492.447540, 0, 'escort paused - SAY_REMULOS_INTRO_3'), +(11832, 14, 7948.267090, -2610.062988, 492.340424, 0, ''), +(11832, 15, 7952.318848, -2594.118408, 490.070374, 0, ''), +(11832, 16, 7913.988770, -2567.002686, 488.330566, 0, ''), +(11832, 17, 7835.454102, -2571.099121, 489.289246, 0, 'escort paused - SAY_REMULOS_DEFEND_2'), +(11832, 18, 7897.283691, -2560.652344, 487.461304, 0, 'escort paused'); diff --git a/sql/updates/0.6/r2313_mangos.sql b/sql/updates/0.6/r2313_mangos.sql new file mode 100644 index 0000000000..5fe0836f4c --- /dev/null +++ b/sql/updates/0.6/r2313_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_anachronos_the_ancient' WHERE entry=15381; +UPDATE gameobject_template SET ScriptName='go_crystalline_tear' WHERE entry=180633; diff --git a/sql/updates/0.6/r2313_scriptdev2.sql b/sql/updates/0.6/r2313_scriptdev2.sql new file mode 100644 index 0000000000..406edf0992 --- /dev/null +++ b/sql/updates/0.6/r2313_scriptdev2.sql @@ -0,0 +1,33 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000770 AND -1000740; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000740,'We must act quickly or shall be lost!',0,0,0,1,'SAY_ANACHRONOS_INTRO_1'), +(-1000741,'My forces cannot overcome the Qiraji defenses. We will not be able to get close enough to place our precious barrier, dragon.',0,0,0,0,'SAY_FANDRAL_INTRO_2'), +(-1000742,'There is a way...',0,0,0,22,'SAY_MERITHRA_INTRO_3'), +(-1000743,'%s nods knowingly.',0,2,0,0,'EMOTE_ARYGOS_NOD'), +(-1000744,'Aye, Fandral, remember these words: Let not your grief guide your faith. These thoughts you hold... dark places you go, night elf.Absolution cannot be had through misguided vengeance.',0,0,0,1,'SAY_CAELESTRASZ_INTRO_4'), +(-1000745,'%s glances at her compatriots.',0,2,0,0,'EMOTE_MERITHRA_GLANCE'), +(-1000746,'We will push him back, Anachronos. This is wow. Uphold your end of this task. Let not your hands falter as you seal our fates behind the barrier.',0,0,0,1,'SAY_MERITHRA_INTRO_5'), +(-1000747,'Succumb to the endless dream, little ones. Let it comsume you!',0,1,0,22,'SAY_MERITHRA_ATTACK_1'), +(-1000748,'Anachronos, the diversion will give you an the young druid time enough to seal the gate. Do not falter. Now, let us see how they deal with chaotic magic.',0,0,0,1,'SAY_ARYGOS_ATTACK_2'), +(-1000749,'Let them feelt the wrath of the blue flight! May Malygos protect me!',0,1,0,22,'SAY_ARYGOS_ATTACK_3'), +(-1000750,'Do not forget sacrifices made on this day, night elf. We have all suffered immensely at the hands of these beasts.',0,0,0,1,'SAY_CAELESTRASZ_ATTACK_4'), +(-1000751,'Alexstrasza, give me the resolve to drive your enemies back.',0,1,0,22,'SAY_CAELESTRASZ_ATTACK_5'), +(-1000752,'NOW,STAGHELM! WE GO NOW! Prepare your magic!',0,0,0,22,'SAY_ANACHRONOS_SEAL_1'), +(-1000753,'It is done, dragon. Lead the way!',0,0,0,25,'SAY_FANDRAL_SEAL_2'), +(-1000754,'Stay close.',0,0,0,0,'SAY_ANACHRONOS_SEAL_3'), +(-1000755,'The sands of time will halt, but only for a moment! I will now conjure the barrier.',0,0,0,0,'SAY_ANACHRONOS_SEAL_4'), +(-1000756,'FINISH THE SPELL, STAGHELM! I CANNOT HOLD THE GLYPHS OF WARDING IN PLACE MUCH LONGER! CALL FORTH THE ROOTS!', 0,0,0,0,'SAY_ANACHRONOS_SEAL_5'), +(-1000757,'Ancient ones guide my hand... Wake from your slumber! WAKE AND SEAL THIS CURSED PLACE!',0,0,0,0, 'SAY_FANDRAL_SEAL_6'), +(-1000758,'%s falls to one knee - exhausted.',0,2,0,0,'EMOTE_FANDRAL_EXHAUSTED'), +(-1000759,'It... It is over, Lord Staghelm. We are victorious. Albeit the cost for this victory was great.',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_1'), +(-1000760,'There is but one duty that remains',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_2'), +(-1000761,'Before I leave this place, I make one final offering for you, Lord Staghelm. Should a time arise in which you must gain entry to this accursed fortress, use the scepter of the shifting sands on the sacred gong. The magic holding the barrier together will dissipate an the horrors of the Ahn\'Qiraj will be unleashed upon the world once more.',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_3'), +(-1000762,'%s hands the Scepter of the Shifting Sands to $N.',0,2,0,0,'EMOTE_ANACHRONOS_SCEPTER'), +(-1000763,'After the savagery that my people have witnessed and felt, you expect me to accept another burden, dragon? Surely you are mad.',0,0,0,1,'SAY_FANDRAL_EPILOGUE_4'), +(-1000764,'I want nothing to do with Silithus, the Qiraji and least of all, any damed dragons!',0,0,0,1,'SAY_FANDRAL_EPILOGUE_5'), +(-1000765,'%s hurls the Scepter of the Shifting Sands into the barrier, shattering it.',0,2,0,0,'EMOTE_FANDRAL_SHATTER'), +(-1000766,'Lord Staghelm, where are you going? You would shatter our bond for the sake of pride?',0,0,0,1,'SAY_ANACHRONOS_EPILOGUE_6'), +(-1000767,'My son\'s soul will find no comfort in this hollow victory, dragon! I will have him back. Though it takes a millenia. I WILL have my son back!',0,0,0,1,'SAY_FANDRAL_EPILOGUE_7'), +(-1000768,'%s shakes his head in disappointment.',0,2,0,25,'EMOTE_ANACHRONOS_DISPPOINTED'), +(-1000769,'%s kneels down to pickup the fragments of the shattered scepter.',0,2,0,0,'EMOTE_ANACHRONOS_PICKUP'), +(-1000770,'And now you know all that there is to know, mortal',0,0,0,0,'SAY_ANACHRONOS_EPILOGUE_8'); diff --git a/sql/updates/0.6/r2314_mangos.sql b/sql/updates/0.6/r2314_mangos.sql new file mode 100644 index 0000000000..9b9546407c --- /dev/null +++ b/sql/updates/0.6/r2314_mangos.sql @@ -0,0 +1,40 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=19361; +UPDATE creature_template SET ScriptName='' WHERE entry=18197; +UPDATE creature_template SET ScriptName='' WHERE entry=18019; +UPDATE creature_template SET ScriptName='' WHERE entry=20142; +UPDATE creature_template SET ScriptName='' WHERE entry IN (29665,29725,29728); +UPDATE creature_template SET ScriptName='' WHERE entry=18166; +UPDATE creature_template SET ScriptName='' WHERE entry=16819; +UPDATE creature_template SET ScriptName='' WHERE entry=19409; +UPDATE creature_template SET ScriptName='' WHERE entry=7172; +UPDATE creature_template SET ScriptName='' WHERE entry=23309; +UPDATE creature_template SET ScriptName='' WHERE entry=21657; +UPDATE creature_template SET ScriptName='' WHERE entry=20235; +UPDATE creature_template SET ScriptName='' WHERE entry=18261; +UPDATE creature_template SET ScriptName='' WHERE entry=25967; +UPDATE creature_template SET ScriptName='' WHERE entry=23704; +UPDATE creature_template SET ScriptName='' WHERE entry=21981; +UPDATE creature_template SET ScriptName='' WHERE entry=23413; +UPDATE creature_template SET ScriptName='' WHERE entry=23415; +UPDATE creature_template SET ScriptName='' WHERE entry=21727; +UPDATE creature_template SET ScriptName='' WHERE entry=21725; +UPDATE creature_template SET ScriptName='' WHERE entry=21183; +UPDATE creature_template SET ScriptName='' WHERE entry=19401; +UPDATE creature_template SET ScriptName='' WHERE entry=18585; +UPDATE creature_template SET ScriptName='' WHERE entry=20162; +UPDATE creature_template SET ScriptName='' WHERE entry=22932; +UPDATE creature_template SET ScriptName='' WHERE entry=23373; +UPDATE creature_template SET ScriptName='' WHERE entry=25590; +UPDATE creature_template SET ScriptName='' WHERE entry=26219; +UPDATE creature_template SET ScriptName='' WHERE entry=30051; +UPDATE creature_template SET ScriptName='' WHERE entry=26602; +UPDATE creature_template SET ScriptName='' WHERE entry=24795; +UPDATE creature_template SET ScriptName='' WHERE entry=31848; +UPDATE creature_template SET ScriptName='' WHERE entry=29975; +UPDATE creature_template SET ScriptName='' WHERE entry=31333; +UPDATE creature_template SET ScriptName='' WHERE entry=29445; +UPDATE creature_template SET ScriptName='' WHERE entry=31247; +UPDATE creature_template SET ScriptName='' WHERE entry=29811; +UPDATE creature_template SET ScriptName='' WHERE entry IN (29169,23729,26673,27158,29158,29161,26471,29155,29159,29160,29162); + +UPDATE gameobject_template SET ScriptName='' WHERE entry=181606; diff --git a/sql/updates/0.6/r2314_scriptdev2.sql b/sql/updates/0.6/r2314_scriptdev2.sql new file mode 100644 index 0000000000..86f0153799 --- /dev/null +++ b/sql/updates/0.6/r2314_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='REUSE ME', comment='REUSE ME' WHERE entry=-1000195; diff --git a/sql/updates/0.6/r2318_mangos.sql b/sql/updates/0.6/r2318_mangos.sql new file mode 100644 index 0000000000..43e9bf4b3d --- /dev/null +++ b/sql/updates/0.6/r2318_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_feero_ironhand' WHERE entry=4484; diff --git a/sql/updates/0.6/r2318_scriptdev2.sql b/sql/updates/0.6/r2318_scriptdev2.sql new file mode 100644 index 0000000000..2cc5a85a8c --- /dev/null +++ b/sql/updates/0.6/r2318_scriptdev2.sql @@ -0,0 +1,48 @@ +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'), +(-1000773,'Assassins from that cult you found... Let\'s get moving before someone else finds us out here.',0,0,0,0,'Feero Ironhand SAY_FIRST_AMBUSH_END'), +(-1000774,'Hold! I sense an evil presence... Undead!',0,0,0,0,'Feero Ironhand SAY_SECOND_AMBUSH_START'), +(-1000775,'A $C! Slaying him would please the master. Attack!',0,0,0,0,'Forsaken Scout SAY_SCOUT_SECOND_AMBUSH'), +(-1000776,'They\'re coming out of the woodwork today. Let\'s keep moving or we may find more things that want me dead.',0,0,0,0,'Feero Ironhand SAY_SECOND_AMBUSH_END'), +(-1000777,'These three again?',0,0,0,0,'Feero Ironhand SAY_FINAL_AMBUSH_START'), +(-1000778,'Not quite so sure of yourself without the Purifier, hm?',0,0,0,0,'Balizar the Umbrage SAY_BALIZAR_FINAL_AMBUSH'), +(-1000779,'I\'ll finish you off for good this time!',0,0,0,0,'Feero Ironhand SAY_FINAL_AMBUSH_ATTACK'), +(-1000780,'Well done! I should be fine on my own from here. Remember to talk to Delgren when you return to Maestra\'s Post in Ashenvale.',0,0,0,0,'Feero Ironhand SAY_QUEST_END'); + +DELETE FROM script_waypoint WHERE entry=4484; +INSERT INTO script_waypoint VALUES +(4484, 0, 3178.57, 188.52, 4.27, 0, 'SAY_QUEST_START'), +(4484, 1, 3189.82, 198.56, 5.62, 0, ''), +(4484, 2, 3215.21, 185.78, 6.43, 0, ''), +(4484, 3, 3224.05, 183.08, 6.74, 0, ''), +(4484, 4, 3228.11, 194.97, 7.51, 0, ''), +(4484, 5, 3225.33, 201.78, 7.25, 0, ''), +(4484, 6, 3233.33, 226.88, 10.18, 0, ''), +(4484, 7, 3274.12, 225.83, 10.72, 0, ''), +(4484, 8, 3321.63, 209.82, 12.36, 0, ''), +(4484, 9, 3369.66, 226.21, 11.69, 0, ''), +(4484, 10, 3402.35, 227.20, 9.48, 0, ''), +(4484, 11, 3441.92, 224.75, 10.85, 0, ''), +(4484, 12, 3453.87, 220.31, 12.52, 0, ''), +(4484, 13, 3472.51, 213.68, 13.26, 0, ''), +(4484, 14, 3515.49, 212.96, 9.76, 5000, 'SAY_FIRST_AMBUSH_START'), +(4484, 15, 3516.21, 212.84, 9.52, 20000, 'SAY_FIRST_AMBUSH_END'), +(4484, 16, 3548.22, 217.12, 7.34, 0, ''), +(4484, 17, 3567.57, 219.43, 5.22, 0, ''), +(4484, 18, 3659.85, 209.68, 2.27, 0, ''), +(4484, 19, 3734.90, 177.64, 6.75, 0, ''), +(4484, 20, 3760.24, 162.51, 7.49, 5000, 'SAY_SECOND_AMBUSH_START'), +(4484, 21, 3761.58, 161.14, 7.37, 20000, 'SAY_SECOND_AMBUSH_END'), +(4484, 22, 3801.17, 129.87, 9.38, 0, ''), +(4484, 23, 3815.53, 118.53, 10.14, 0, ''), +(4484, 24, 3894.58, 44.88, 15.49, 0, ''), +(4484, 25, 3972.83, 0.42, 17.34, 0, ''), +(4484, 26, 4026.41, -7.63, 16.77, 0, ''), +(4484, 27, 4086.24, 12.32, 16.12, 0, ''), +(4484, 28, 4158.79, 50.67, 25.86, 0, ''), +(4484, 29, 4223.48, 99.52, 35.47, 5000, 'SAY_FINAL_AMBUSH_START'), +(4484, 30, 4224.28, 100.02, 35.49, 10000, 'SAY_QUEST_END'), +(4484, 31, 4243.45, 117.44, 38.83, 0, ''), +(4484, 32, 4264.18, 134.22, 42.96, 0, ''); diff --git a/sql/updates/0.6/r2320_mangos.sql b/sql/updates/0.6/r2320_mangos.sql new file mode 100644 index 0000000000..973d35e7a9 --- /dev/null +++ b/sql/updates/0.6/r2320_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_alar' WHERE entry=19514; diff --git a/sql/updates/0.6/r2321_scriptdev2.sql b/sql/updates/0.6/r2321_scriptdev2.sql new file mode 100644 index 0000000000..8843196173 --- /dev/null +++ b/sql/updates/0.6/r2321_scriptdev2.sql @@ -0,0 +1,2 @@ +UPDATE script_texts SET content_default='You there! Check out that noise.' WHERE entry=-1036000; +UPDATE script_texts SET content_default='We\'re under attack! A vast, ye swabs! Repel the invaders!' WHERE entry=-1036001; diff --git a/sql/updates/0.6/r2323_mangos.sql b/sql/updates/0.6/r2323_mangos.sql new file mode 100644 index 0000000000..0d69bab2aa --- /dev/null +++ b/sql/updates/0.6/r2323_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=3216; diff --git a/sql/updates/0.6/r2324_mangos.sql b/sql/updates/0.6/r2324_mangos.sql new file mode 100644 index 0000000000..65077b0889 --- /dev/null +++ b/sql/updates/0.6/r2324_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=16224; diff --git a/sql/updates/0.6/r2325_mangos.sql b/sql/updates/0.6/r2325_mangos.sql new file mode 100644 index 0000000000..58f3056427 --- /dev/null +++ b/sql/updates/0.6/r2325_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=28315; diff --git a/sql/updates/0.6/r2325_scriptdev2.sql b/sql/updates/0.6/r2325_scriptdev2.sql new file mode 100644 index 0000000000..3c2b7c79f3 --- /dev/null +++ b/sql/updates/0.6/r2325_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='REUSE ME', comment='REUSE ME' WHERE entry=-1000208; diff --git a/sql/updates/0.6/r2326_mangos.sql b/sql/updates/0.6/r2326_mangos.sql new file mode 100644 index 0000000000..c4c4029d8b --- /dev/null +++ b/sql/updates/0.6/r2326_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=8479; diff --git a/sql/updates/0.6/r2328_mangos.sql b/sql/updates/0.6/r2328_mangos.sql new file mode 100644 index 0000000000..c735e4cd8d --- /dev/null +++ b/sql/updates/0.6/r2328_mangos.sql @@ -0,0 +1,4 @@ +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; diff --git a/sql/updates/0.6/r2345_mangos.sql b/sql/updates/0.6/r2345_mangos.sql new file mode 100644 index 0000000000..bc69bcb7e8 --- /dev/null +++ b/sql/updates/0.6/r2345_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (7885,7886,12204,12205); diff --git a/sql/updates/0.6/r2347_mangos.sql b/sql/updates/0.6/r2347_mangos.sql new file mode 100644 index 0000000000..564129a52a --- /dev/null +++ b/sql/updates/0.6/r2347_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_kiljaeden' WHERE entry=25315; diff --git a/sql/updates/0.6/r2348_scriptdev2.sql b/sql/updates/0.6/r2348_scriptdev2.sql new file mode 100644 index 0000000000..5ab80f170a --- /dev/null +++ b/sql/updates/0.6/r2348_scriptdev2.sql @@ -0,0 +1,14 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1580106 AND -1580095; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1580095,'Mortal heroes - your victory here today was foretold long ago. My brother\'s anguished cry of defeat will echo across the universe - bringing renewed hope to all those who still stand against the Burning Crusade.',12515,1,0,0,'velen SAY_OUTRO_1'), +(-1580096,'As the Legion\'s final defeat draws ever-nearer, stand proud in the knowledge that you have saved worlds without number from the flame.',12516,1,0,0,'velen SAY_OUTRO_2'), +(-1580097,'Just as this day marks an ending, so too does it herald a new beginning...',12517,1,0,0,'velen SAY_OUTRO_3'), +(-1580098,'The creature Entropius, whom you were forced to destroy, was once the noble naaru, M\'uru. In life, M\'uru channeled vast energies of LIGHT and HOPE. For a time, a misguided few sought to steal those energies...',12518,1,0,0,'velen SAY_OUTRO_4'), +(-1580099,'Our arrogance was unpardonable. We damned one of the most noble beings of all. We may never atone for this sin.',12524,1,0,0,'liadrin SAY_OUTRO_5'), +(-1580100,'Than fortunate it is, that I have reclaimed the noble naaru\'s spark from where it fell! Where faith dwells, hope is never lost, young blood elf.',12519,1,0,0,'velen SAY_OUTRO_6'), +(-1580101,'Can it be ?',12525,1,0,0,'liadrin SAY_OUTRO_7'), +(-1580102,'Gaz now, mortals - upon the HEART OF M\'URU! Umblemished. Bathed by the light of Creation - just as it was at the Dawn.',12520,1,0,0,'velen SAY_OUTRO_8'), +(-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,1,0,0,'velen SAY_OUTRO_9'), +(-1580104,'Blessed ancestors! I feel it... so much love... so much grace... there are... no words... impossible to describe...',12526,1,0,0,'liadrin SAY_OUTRO_10'), +(-1580105,'Salvation, young one. It waits for us all.',12522,1,0,0,'velen SAY_OUTRO_11'), +(-1580106,'Farewell...!',12523,1,0,0,'velen SAY_OUTRO_12'); diff --git a/sql/updates/0.6/r2355_mangos.sql b/sql/updates/0.6/r2355_mangos.sql new file mode 100644 index 0000000000..ee55c4d155 --- /dev/null +++ b/sql/updates/0.6/r2355_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=187055; diff --git a/sql/updates/0.6/r2357_mangos.sql b/sql/updates/0.6/r2357_mangos.sql new file mode 100644 index 0000000000..daed40708e --- /dev/null +++ b/sql/updates/0.6/r2357_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_ossirian' WHERE entry=15339; +UPDATE gameobject_template SET ScriptName='go_ossirian_crystal' WHERE entry=180619; diff --git a/sql/updates/0.6/r2359_mangos.sql b/sql/updates/0.6/r2359_mangos.sql new file mode 100644 index 0000000000..d508f47bef --- /dev/null +++ b/sql/updates/0.6/r2359_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_kiljaeden_controller' WHERE entry=25608; diff --git a/sql/updates/0.6/r2359_scriptdev2.sql b/sql/updates/0.6/r2359_scriptdev2.sql new file mode 100644 index 0000000000..37fc3c3ff1 --- /dev/null +++ b/sql/updates/0.6/r2359_scriptdev2.sql @@ -0,0 +1,2 @@ +UPDATE script_texts SET emote=1, type=0 WHERE entry BETWEEN -1580106 AND -1580095; +UPDATE script_texts SET type=0 WHERE entry=-1580089; diff --git a/sql/updates/0.6/r2360_scriptdev2.sql b/sql/updates/0.6/r2360_scriptdev2.sql new file mode 100644 index 0000000000..06d65eb34b --- /dev/null +++ b/sql/updates/0.6/r2360_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='That was fun, but I still await a true challenge!' WHERE entry=-1580020; diff --git a/sql/updates/0.6/r2361_mangos.sql b/sql/updates/0.6/r2361_mangos.sql new file mode 100644 index 0000000000..f0a5ca951e --- /dev/null +++ b/sql/updates/0.6/r2361_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc_brutallus_cloud' WHERE entry=25703; +UPDATE creature_template SET ScriptName='boss_felmyst' WHERE entry=25038; diff --git a/sql/updates/0.6/r2364_scriptdev2.sql b/sql/updates/0.6/r2364_scriptdev2.sql new file mode 100644 index 0000000000..b1b8d38d24 --- /dev/null +++ b/sql/updates/0.6/r2364_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=0 WHERE entry IN (-1580088, -1580086, -1580084, -1580082); diff --git a/sql/updates/0.6/r2369_mangos.sql b/sql/updates/0.6/r2369_mangos.sql new file mode 100644 index 0000000000..65c1d52a56 --- /dev/null +++ b/sql/updates/0.6/r2369_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' where entry=179552; diff --git a/sql/updates/0.6/r2370_mangos.sql b/sql/updates/0.6/r2370_mangos.sql new file mode 100644 index 0000000000..e9436f9b7f --- /dev/null +++ b/sql/updates/0.6/r2370_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=179879; diff --git a/sql/updates/0.6/r2371_mangos.sql b/sql/updates/0.6/r2371_mangos.sql new file mode 100644 index 0000000000..4882654de2 --- /dev/null +++ b/sql/updates/0.6/r2371_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=12144; diff --git a/sql/updates/0.6/r2372_mangos.sql b/sql/updates/0.6/r2372_mangos.sql new file mode 100644 index 0000000000..0f3357fd10 --- /dev/null +++ b/sql/updates/0.6/r2372_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=14387; diff --git a/sql/updates/0.6/r2373_mangos.sql b/sql/updates/0.6/r2373_mangos.sql new file mode 100644 index 0000000000..6f86f2ec52 --- /dev/null +++ b/sql/updates/0.6/r2373_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (918, 3328, 4163, 4583, 5165, 5167, 13283, 16684); diff --git a/sql/updates/0.6/r2374_mangos.sql b/sql/updates/0.6/r2374_mangos.sql new file mode 100644 index 0000000000..dff9de1d02 --- /dev/null +++ b/sql/updates/0.6/r2374_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=23678; diff --git a/sql/updates/0.6/r2374_scriptdev2.sql b/sql/updates/0.6/r2374_scriptdev2.sql new file mode 100644 index 0000000000..68c333729c --- /dev/null +++ b/sql/updates/0.6/r2374_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000783 AND -1000781; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000781,'I knew Lurielle would send help! Thank you, friend, and give Lurielle my thanks as well!',0,0,0,0,'Chill Nymph SAY_FREE_1'), +(-1000782,'Where am I? What happend to me? You... you freed me?',0,0,0,0,'Chill Nymph SAY_FREE_2'), +(-1000783,'Thank you. I thought I would die without seeing my sisters again!',0,0,0,0,'Chill Nymph SAY_FREE_3'); diff --git a/sql/updates/0.6/r2375_mangos.sql b/sql/updates/0.6/r2375_mangos.sql new file mode 100644 index 0000000000..316790f0d7 --- /dev/null +++ b/sql/updates/0.6/r2375_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=8436; diff --git a/sql/updates/0.6/r2383_scriptdev2.sql b/sql/updates/0.6/r2383_scriptdev2.sql new file mode 100644 index 0000000000..3d1d22f0f1 --- /dev/null +++ b/sql/updates/0.6/r2383_scriptdev2.sql @@ -0,0 +1,23 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1578019 AND -1578000; +INSERT INTO `script_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`) VALUES +(-1578000,'What do we have here... those would defy the Spell-Weaver? Those without foresight or understanding. How could I make you see? Malygos is saving the world from itself! Bah! You are hardly worth my time!',13635,1,0,'urom SAY_SUMMON_1'), +(-1578001,'Clearly my pets failed. Perhaps another demonstration is in order.',13636,1,0,'urom SAY_SUMMON_2'), +(-1578002,'Still you fight. Still you cling to misguided principles. If you survive, you\'ll find me in the center ring.',13637,1,0,'urom SAY_SUMMON_3'), +(-1578003,'Poor blind fools!',13638,1,0,'urom SAY_AGGRO'), +(-1578004,'A taste... just a small taste... of the Spell-Weaver\'s power!',13639,1,0,'urom SAY_EXPLOSION_1'), +(-1578005,'So much unstable energy... but worth the risk to destroy you!',13640,1,0,'urom SAY_EXPLOSION_2'), +(-1578006,'If only you understood!',13641,1,0,'urom SAY_KILL_1'), +(-1578007,'Now do you see? Do you?!',13642,1,0,'urom SAY_KILL_2'), +(-1578008,'Unfortunate, but necessary.',13643,1,0,'urom SAY_KILL_3'), +(-1578009,'Everything I\'ve done... has been for Azeroth...',13644,1,0,'urom SAY_DEATH'), + +(-1578010,'Simpletons! You cannot comprehend the forces you have set in motion. The ley line conduit will not be disrupted! Your defeat shall be absolute!',13622,6,0,'eregos SAY_SPAWN'), +(-1578011,'You brash interlopers are out of your element! I will ground you!',13623,1,0,'eregos SAY_AGGRO'), +(-1578012,'We command the arcane! It shall not be used against us.',13626,1,0,'eregos SAY_ARCANE_SHIELD'), +(-1578013,'It is trivial to extinguish your fire!',13627,1,0,'eregos SAY_FIRE_SHIELD'), +(-1578014,'No magic of nature will help you now!',13625,1,0,'eregos SAY_NATURE_SHIELD'), +(-1578015,'Such insolence... such arrogance... must be PUNISHED!',13624,1,0,'eregos SAY_FRENZY'), +(-1578016,'It\'s a long way down...',13628,1,0,'eregos SAY_KILL_1'), +(-1578017,'Back to the earth with you!',13629,1,0,'eregos SAY_KILL_2'), +(-1578018,'Enjoy the fall!',13630,1,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,'eregos SAY_DEATH'); diff --git a/sql/updates/0.6/r2385_mangos.sql b/sql/updates/0.6/r2385_mangos.sql new file mode 100644 index 0000000000..cbb854df5a --- /dev/null +++ b/sql/updates/0.6/r2385_mangos.sql @@ -0,0 +1 @@ +UPDATE instance_template SET ScriptName='instance_oculus' WHERE map=578; diff --git a/sql/updates/0.6/r2385_scriptdev2.sql b/sql/updates/0.6/r2385_scriptdev2.sql new file mode 100644 index 0000000000..5ee8326591 --- /dev/null +++ b/sql/updates/0.6/r2385_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1578020, -1578021); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-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'); diff --git a/sql/updates/0.6/r2387_mangos.sql b/sql/updates/0.6/r2387_mangos.sql new file mode 100644 index 0000000000..95d3097c50 --- /dev/null +++ b/sql/updates/0.6/r2387_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_eregos' WHERE entry=27656; +UPDATE creature_template SET ScriptName='boss_urom' WHERE entry=27655; diff --git a/sql/updates/0.6/r2397_scriptdev2.sql b/sql/updates/0.6/r2397_scriptdev2.sql new file mode 100644 index 0000000000..c09c0a1725 --- /dev/null +++ b/sql/updates/0.6/r2397_scriptdev2.sql @@ -0,0 +1,6 @@ +UPDATE script_texts SET content_default='Shgla\'yos plahf mh\'naus.' WHERE entry=-1619033; +UPDATE script_texts SET content_default='Gul\'kafh an\'shel. Yoq\'al shn ky ywaq nuul.' WHERE entry=-1619034; +UPDATE script_texts SET content_default='Ywaq puul skshgn: on\'ma yeh\'glu zuq.' WHERE entry=-1619035; +UPDATE script_texts SET content_default='Ywaq ma phgwa\'cul hnakf.' WHERE entry=-1619036; +UPDATE script_texts SET content_default='Ywaq maq oou; ywaq maq ssaggh. Ywaq ma shg\'fhn.' WHERE entry=-1619037; +UPDATE script_texts SET content_default='Iilth vwah, uhn\'agth fhssh za.' WHERE entry=-1619039; diff --git a/sql/updates/0.6/r2399_scriptdev2.sql b/sql/updates/0.6/r2399_scriptdev2.sql new file mode 100644 index 0000000000..a00e36dbcd --- /dev/null +++ b/sql/updates/0.6/r2399_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM gossip_texts WHERE entry=-3564000; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3564000,'We are ready to fight alongside you, Akama','akama(shade) GOSSIP_ITEM_START_ENCOUNTER'); diff --git a/sql/updates/0.6/r2400_scriptdev2.sql b/sql/updates/0.6/r2400_scriptdev2.sql new file mode 100644 index 0000000000..1cfa582641 --- /dev/null +++ b/sql/updates/0.6/r2400_scriptdev2.sql @@ -0,0 +1,4 @@ +UPDATE script_texts SET sound=14059 WHERE entry=-1601019; +UPDATE script_texts SET sound=14058 WHERE entry=-1601020; +UPDATE script_texts SET sound=14068 WHERE entry=-1601022; +UPDATE script_texts SET sound=14067 WHERE entry=-1601023; diff --git a/sql/updates/0.6/r2409_mangos.sql b/sql/updates/0.6/r2409_mangos.sql new file mode 100644 index 0000000000..6e231ae957 --- /dev/null +++ b/sql/updates/0.6/r2409_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_shirrak' WHERE entry=18371; diff --git a/sql/updates/0.6/r2409_scriptdev2.sql b/sql/updates/0.6/r2409_scriptdev2.sql new file mode 100644 index 0000000000..0f0e8e6d50 --- /dev/null +++ b/sql/updates/0.6/r2409_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1558010; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1558010,'%s focuses on $N',0,3,0,0,'shirrak EMOTE_FOCUS'); diff --git a/sql/updates/0.6/r2416_mangos.sql b/sql/updates/0.6/r2416_mangos.sql new file mode 100644 index 0000000000..565caf9930 --- /dev/null +++ b/sql/updates/0.6/r2416_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_void_traveler' WHERE entry=19226; diff --git a/sql/updates/0.6/r2422_mangos.sql b/sql/updates/0.6/r2422_mangos.sql new file mode 100644 index 0000000000..050af636bf --- /dev/null +++ b/sql/updates/0.6/r2422_mangos.sql @@ -0,0 +1,3 @@ +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; diff --git a/sql/updates/0.6/r2445_mangos.sql b/sql/updates/0.6/r2445_mangos.sql new file mode 100644 index 0000000000..bc9bd2f1ae --- /dev/null +++ b/sql/updates/0.6/r2445_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_hive_zara_larva' WHERE entry=15555; diff --git a/sql/updates/0.6/r2446_mangos.sql b/sql/updates/0.6/r2446_mangos.sql new file mode 100644 index 0000000000..6eb930eec2 --- /dev/null +++ b/sql/updates/0.6/r2446_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_buru' WHERE entry=15370; +UPDATE creature_template SET ScriptName='npc_buru_egg' WHERE entry=15514; diff --git a/sql/updates/0.6/r2447_mangos.sql b/sql/updates/0.6/r2447_mangos.sql new file mode 100644 index 0000000000..ce99574187 --- /dev/null +++ b/sql/updates/0.6/r2447_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_melizza_brimbuzzle' WHERE entry=12277; diff --git a/sql/updates/0.6/r2447_scriptdev2.sql b/sql/updates/0.6/r2447_scriptdev2.sql new file mode 100644 index 0000000000..60aa038618 --- /dev/null +++ b/sql/updates/0.6/r2447_scriptdev2.sql @@ -0,0 +1,34 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000788 AND -1000784; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000784,'Thanks $N. Now let\'s get out of here!',0,0,0,0,'melizza SAY_MELIZZA_START'), +(-1000785,'We made it! Thanks again! I\'m going to run ahead!',0,0,0,0,'melizza SAY_MELIZZA_FINISH'), +(-1000786,'Hey Hornizz! I\'m back! And there are some people behind me who helped me out of a jam.',0,0,0,1,'melizza SAY_MELIZZA_1'), +(-1000787,'We\'re going to have to scratch the Maraudines off our list. Too hard to work with...',0,0,0,1,'melizza SAY_MELIZZA_2'), +(-1000788,'Well, I\'m off to the Gelkis. They\'re not as dumb as the Maraudines, but they\'re more reasonable.',0,0,0,3,'melizza SAY_MELIZZA_3'); + +DELETE FROM script_waypoint WHERE entry=12277; +INSERT INTO script_waypoint VALUES +(12277, 1, -1154.87, 2708.16, 111.123, 1000, 'SAY_MELIZZA_START'), +(12277, 2, -1162.62, 2712.86, 111.549, 0, ''), +(12277, 3, -1183.37, 2709.45, 111.601, 0, ''), +(12277, 4, -1245.09, 2676.43, 111.572, 0, ''), +(12277, 5, -1260.54, 2672.48, 111.55, 0, ''), +(12277, 6, -1272.71, 2666.38, 111.555, 0, ''), +(12277, 7, -1342.95, 2580.82, 111.557, 0, ''), +(12277, 8, -1362.24, 2561.74, 110.848, 0, ''), +(12277, 9, -1376.56, 2514.06, 95.6146, 0, ''), +(12277, 10, -1379.06, 2510.88, 93.3256, 0, ''), +(12277, 11, -1383.14, 2489.17, 89.009, 0, ''), +(12277, 12, -1395.34, 2426.15, 88.6607, 0, 'SAY_MELIZZA_FINISH'), +(12277, 13, -1366.23, 2317.17, 91.8086, 0, ''), +(12277, 14, -1353.81, 2213.52, 90.726, 0, ''), +(12277, 15, -1354.19, 2208.28, 88.7386, 0, ''), +(12277, 16, -1354.59, 2193.77, 77.6702, 0, ''), +(12277, 17, -1367.62, 2160.64, 67.1482, 0, ''), +(12277, 18, -1379.44, 2132.77, 64.1326, 0, ''), +(12277, 19, -1404.81, 2088.68, 61.8162, 0, 'SAY_MELIZZA_1'), +(12277, 20, -1417.15, 2082.65, 62.4112, 0, ''), +(12277, 21, -1423.28, 2074.19, 62.2046, 0, ''), +(12277, 22, -1432.99, 2070.56, 61.7811, 0, ''), +(12277, 23, -1469.27, 2078.68, 63.1141, 0, ''), +(12277, 24, -1507.21, 2115.12, 62.3578, 0, ''); diff --git a/sql/updates/0.6/r2448_scriptdev2.sql b/sql/updates/0.6/r2448_scriptdev2.sql new file mode 100644 index 0000000000..b08f269d0c --- /dev/null +++ b/sql/updates/0.6/r2448_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='We saved. You nice, dryskin.' WHERE entry=-1000612; diff --git a/sql/updates/0.6/r2450_mangos.sql b/sql/updates/0.6/r2450_mangos.sql new file mode 100644 index 0000000000..21de8f0f8b --- /dev/null +++ b/sql/updates/0.6/r2450_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_apothecary_hummel' WHERE entry=36296; +UPDATE creature_template SET ScriptName='npc_valentine_boss_manager' WHERE entry=36643; diff --git a/sql/updates/0.6/r2450_scriptdev2.sql b/sql/updates/0.6/r2450_scriptdev2.sql new file mode 100644 index 0000000000..1dcb3169ef --- /dev/null +++ b/sql/updates/0.6/r2450_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1033025 AND -1033020; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1033020,'Did they bother to tell you who I am and why I am doing this?',0,0,0,0,'hummel SAY_INTRO_1'), +(-1033021,'...or are they just using you like they do everybody else?',0,0,0,0,'hummel SAY_INTRO_2'), +(-1033022,'But what does it matter. It is time for this to end.',0,0,0,0,'hummel SAY_INTRO_3'), +(-1033023,'Baxter! Get in there and help! NOW!',0,0,0,0,'hummel SAY_CALL_BAXTER'), +(-1033024,'It is time, Frye! Attack!',0,0,0,0,'hummel SAY_CALL_FRYE'), +(-1033025,'...please don\'t think less of me.',0,0,0,0,'hummel SAY_DEATH'); diff --git a/sql/updates/0.6/r2459_mangos.sql b/sql/updates/0.6/r2459_mangos.sql new file mode 100644 index 0000000000..89de250716 --- /dev/null +++ b/sql/updates/0.6/r2459_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_stratholme_postbox' WHERE entry IN (176346,176349,176350,176351,176352,176353); diff --git a/sql/updates/0.6/r2461_scriptdev2.sql b/sql/updates/0.6/r2461_scriptdev2.sql new file mode 100644 index 0000000000..3b732bf904 --- /dev/null +++ b/sql/updates/0.6/r2461_scriptdev2.sql @@ -0,0 +1,17 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1229018 AND -1229004; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1229004,'Excellent... it would appear as if the meddlesome insects have arrived just in time to feed my legion. Welcome, mortals!',0,1,0,0,'nefarius SAY_INTRO_1'), +(-1229005,'Let not even a drop of their blood remain upon the arena floor, my children. Feast on their souls!',0,1,0,0,'nefarius SAY_INTRO_2'), +(-1229006,'Foolsss...Kill the one in the dress!',0,1,0,0,'nefarius SAY_ATTACK_1'), +(-1229007,'Sire, let me join the fray! I shall tear their spines out with my bare hands!',0,1,0,0,'rend SAY_REND_JOIN'), +(-1229008,'Concentrate your attacks upon the healer!',0,1,0,0,'nefarius SAY_ATTACK_2'), +(-1229009,'Inconceivable!',0,1,0,0,'nefarius SAY_ATTACK_3'), +(-1229010,'Do not force my hand, children! I shall use your hides to line my boots.',0,1,0,0,'nefarius SAY_ATTACK_4'), +(-1229011,'Defilers!',0,1,0,0,'rend SAY_LOSE_1'), +(-1229012,'Impossible!',0,1,0,0,'rend SAY_LOSE_2'), +(-1229013,'Your efforts will prove fruitless. None shall stand in our way!',0,1,0,0,'nefarius SAY_LOSE_3'), +(-1229014,'THIS CANNOT BE!!! Rend, deal with these insects.',0,1,0,0,'nefarius SAY_LOSE_4'), +(-1229015,'With pleasure...',0,1,0,0,'rend SAY_REND_ATTACK'), +(-1229016,'The Warchief shall make quick work of you, mortals. Prepare yourselves!',0,1,0,0,'nefarius SAY_WARCHIEF'), +(-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,0,'nefarius SAY_VICTORY'); diff --git a/sql/updates/0.6/r2462_mangos.sql b/sql/updates/0.6/r2462_mangos.sql new file mode 100644 index 0000000000..982a3ac9a4 --- /dev/null +++ b/sql/updates/0.6/r2462_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_volcor' WHERE entry=3692; diff --git a/sql/updates/0.6/r2462_scriptdev2.sql b/sql/updates/0.6/r2462_scriptdev2.sql new file mode 100644 index 0000000000..13857ce613 --- /dev/null +++ b/sql/updates/0.6/r2462_scriptdev2.sql @@ -0,0 +1,25 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000794 AND -1000789; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000789,'Well, now or never I suppose. Remember, once we get to the road safety, return to Terenthis to let him know we escaped.',0,0,0,0,'volcor SAY_START'), +(-1000790,'We made it, My friend. Remember to find Terenthis and let him know we\'re safe. Thank you again.',0,0,0,0,'volcor SAY_END'), +(-1000791,'Here they come.',0,0,0,0,'volcor SAY_FIRST_AMBUSH'), +(-1000792,'We can overcome these foul creatures.',0,0,0,0,'volcor SAY_AGGRO_1'), +(-1000793,'We shall earn our deaths at the very least!',0,0,0,0,'volcor SAY_AGGRO_2'), +(-1000794,'Don\'t give up! Fight, to the death!',0,0,0,0,'volcor SAY_AGGRO_3'); + +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'); diff --git a/sql/updates/0.6/r2463_mangos.sql b/sql/updates/0.6/r2463_mangos.sql new file mode 100644 index 0000000000..e222535bd5 --- /dev/null +++ b/sql/updates/0.6/r2463_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=169294; diff --git a/sql/updates/0.6/r2472_scriptdev2.sql b/sql/updates/0.6/r2472_scriptdev2.sql new file mode 100644 index 0000000000..5926422d2f --- /dev/null +++ b/sql/updates/0.6/r2472_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1545024; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1545024,'Enjoy the storm, warm bloods!',0,1,0,0,'thespia SAY_CLOUD'); diff --git a/sql/updates/0.6/r2479_mangos.sql b/sql/updates/0.6/r2479_mangos.sql new file mode 100644 index 0000000000..10d40a9bfd --- /dev/null +++ b/sql/updates/0.6/r2479_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=10307; diff --git a/sql/updates/0.6/r2480_mangos.sql b/sql/updates/0.6/r2480_mangos.sql new file mode 100644 index 0000000000..db3c585f13 --- /dev/null +++ b/sql/updates/0.6/r2480_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=17435; diff --git a/sql/updates/0.6/r2481_mangos.sql b/sql/updates/0.6/r2481_mangos.sql new file mode 100644 index 0000000000..32fe361bc8 --- /dev/null +++ b/sql/updates/0.6/r2481_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=17824; diff --git a/sql/updates/0.6/r2482_mangos.sql b/sql/updates/0.6/r2482_mangos.sql new file mode 100644 index 0000000000..39d62f7ebc --- /dev/null +++ b/sql/updates/0.6/r2482_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (27263,27264,27265); diff --git a/sql/updates/0.6/r2484_mangos.sql b/sql/updates/0.6/r2484_mangos.sql new file mode 100644 index 0000000000..ed2ea8977f --- /dev/null +++ b/sql/updates/0.6/r2484_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_lazy_peon' WHERE entry=10556; diff --git a/sql/updates/0.6/r2484_scriptdev2.sql b/sql/updates/0.6/r2484_scriptdev2.sql new file mode 100644 index 0000000000..5482093d51 --- /dev/null +++ b/sql/updates/0.6/r2484_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1000795,-1000796); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000795,'OK boss, I get back to tree hitting.',0,0,0,0,'lazy peon SAY_AWAKE_1'), +(-1000796,'Sleepy... so sleepy...',0,0,0,0,'lazy peon SAY_AWAKE_2'); diff --git a/sql/updates/0.6/r2488_scriptdev2.sql b/sql/updates/0.6/r2488_scriptdev2.sql new file mode 100644 index 0000000000..49da29202f --- /dev/null +++ b/sql/updates/0.6/r2488_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET content_default='$N coming in fast! Prepare to fight!' WHERE entry=-1000104; diff --git a/sql/updates/0.6/r2490_mangos.sql b/sql/updates/0.6/r2490_mangos.sql new file mode 100644 index 0000000000..ee51ec2f0a --- /dev/null +++ b/sql/updates/0.6/r2490_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName="npc_skywing" WHERE entry=22424; diff --git a/sql/updates/0.6/r2490_scriptdev2.sql b/sql/updates/0.6/r2490_scriptdev2.sql new file mode 100644 index 0000000000..33f8e47ba8 --- /dev/null +++ b/sql/updates/0.6/r2490_scriptdev2.sql @@ -0,0 +1,93 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000802 AND -1000797; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000797,'%s squawks and heads toward Veil Shalas. Hurry and follow!',0,2,0,0,'skywing SAY_SKYWING_START'), +(-1000798,'%s pauses briefly before the tree and then heads inside.',0,2,0,0,'skywing SAY_SKYWING_TREE_DOWN'), +(-1000799,'%s seems to be looking for something. He wants you to follow.',0,2,0,0,'skywing SAY_SKYWING_TREE_UP'), +(-1000800,'%s flies to the platform below! You\'d better jump if you want to keep up. Hurry!',0,2,0,0,'skywing SAY_SKYWING_JUMP'), +(-1000801,'%s bellows a loud squawk!',0,2,0,0,'skywing SAY_SKYWING_SUMMON'), +(-1000802,'Free at last from that horrible curse! Thank you! Please send word to Rilak the Redeemed that I am okay. My mission lies in Skettis. Terokk must be defeated!',0,0,0,0,'skywing SAY_SKYWING_END'); + +DELETE FROM script_waypoint WHERE entry=22424; +INSERT INTO script_waypoint VALUES +(22424, 1, -3620.54, 4164.57, 1.81, 0, 'SKYWING_START'), +(22424, 2, -3624.78, 4149.65, 7.44, 0, ''), +(22424, 3, -3630.30, 4124.84, 21.28, 0, ''), +(22424, 4, -3629.14, 4093.65, 44.35, 0, ''), +(22424, 5, -3626.34, 4080.29, 52.39, 0, ''), +(22424, 6, -3619.35, 4063.86, 60.86, 3000, 'SAY_SKYWING_TREE_DOWN'), +(22424, 7, -3615.09, 4054.17, 62.46, 0, ''), +(22424, 8, -3611.39, 4046.60, 65.07, 0, ''), +(22424, 9, -3606.68, 4040.50, 66.00, 0, ''), +(22424, 10, -3600.88, 4038.69, 67.14, 0, ''), +(22424, 11, -3597.88, 4033.84, 68.53, 0, ''), +(22424, 12, -3602.19, 4027.89, 69.36, 0, ''), +(22424, 13, -3609.85, 4028.37, 70.78, 0, ''), +(22424, 14, -3613.01, 4031.10, 72.14, 0, ''), +(22424, 15, -3613.18, 4035.63, 73.52, 0, ''), +(22424, 16, -3609.84, 4039.73, 75.25, 0, ''), +(22424, 17, -3604.55, 4040.12, 77.01, 0, ''), +(22424, 18, -3600.61, 4036.03, 78.84, 0, ''), +(22424, 19, -3602.63, 4029.99, 81.01, 0, ''), +(22424, 20, -3608.87, 4028.64, 83.27, 0, ''), +(22424, 21, -3612.53, 4032.74, 85.24, 0, ''), +(22424, 22, -3611.08, 4038.13, 87.31, 0, ''), +(22424, 23, -3605.09, 4039.35, 89.55, 0, ''), +(22424, 24, -3601.87, 4035.44, 91.64, 0, ''), +(22424, 25, -3603.08, 4030.58, 93.66, 0, ''), +(22424, 26, -3608.47, 4029.23, 95.91, 0, ''), +(22424, 27, -3611.68, 4033.35, 98.09, 0, ''), +(22424, 28, -3609.51, 4038.25, 100.45, 0, ''), +(22424, 29, -3604.54, 4038.01, 102.72, 0, ''), +(22424, 30, -3602.40, 4033.48, 105.12, 0, ''), +(22424, 31, -3606.17, 4029.69, 107.63, 0, ''), +(22424, 32, -3609.93, 4031.26, 109.53, 0, ''), +(22424, 33, -3609.38, 4035.86, 110.67, 0, ''), +(22424, 34, -3603.58, 4043.03, 112.89, 0, ''), +(22424, 35, -3600.99, 4046.49, 111.81, 0, ''), +(22424, 36, -3602.32, 4051.77, 111.81, 3000, 'SAY_SKYWING_TREE_UP'), +(22424, 37, -3609.55, 4055.95, 112.00, 0, ''), +(22424, 38, -3620.93, 4043.77, 111.99, 0, ''), +(22424, 39, -3622.44, 4038.95, 111.99, 0, ''), +(22424, 40, -3621.64, 4025.39, 111.99, 0, ''), +(22424, 41, -3609.62, 4015.20, 111.99, 0, ''), +(22424, 42, -3598.37, 4017.72, 111.99, 0, ''), +(22424, 43, -3590.21, 4026.62, 111.99, 0, ''), +(22424, 44, -3586.55, 4034.13, 112.00, 0, ''), +(22424, 45, -3580.39, 4033.46, 112.00, 0, ''), +(22424, 46, -3568.83, 4032.53, 107.16, 0, ''), +(22424, 47, -3554.81, 4031.23, 105.31, 0, ''), +(22424, 48, -3544.39, 4030.10, 106.58, 0, ''), +(22424, 49, -3531.91, 4029.25, 111.70, 0, ''), +(22424, 50, -3523.50, 4030.24, 112.47, 0, ''), +(22424, 51, -3517.48, 4037.42, 112.66, 0, ''), +(22424, 52, -3510.40, 4040.77, 112.92, 0, ''), +(22424, 53, -3503.83, 4041.35, 113.17, 0, ''), +(22424, 54, -3498.31, 4040.65, 113.11, 0, ''), +(22424, 55, -3494.05, 4031.67, 113.11, 0, ''), +(22424, 56, -3487.71, 4025.58, 113.12, 0, ''), +(22424, 57, -3500.42, 4012.93, 113.11, 0, ''), +(22424, 58, -3510.86, 4010.15, 113.10, 0, ''), +(22424, 59, -3518.07, 4008.62, 112.97, 0, ''), +(22424, 60, -3524.74, 4014.55, 112.41, 2000, 'SAY_SKYWING_JUMP'), +(22424, 61, -3537.81, 4008.59, 92.53, 0, ''), +(22424, 62, -3546.25, 4008.81, 92.79, 0, ''), +(22424, 63, -3552.07, 4006.48, 92.84, 0, ''), +(22424, 64, -3556.29, 4000.14, 92.92, 0, ''), +(22424, 65, -3556.16, 3991.24, 92.92, 0, ''), +(22424, 66, -3551.48, 3984.28, 92.91, 0, ''), +(22424, 67, -3542.90, 3981.64, 92.91, 0, ''), +(22424, 68, -3534.82, 3983.98, 92.92, 0, ''), +(22424, 69, -3530.58, 3989.91, 92.85, 0, ''), +(22424, 70, -3529.85, 3998.77, 92.59, 0, ''), +(22424, 71, -3534.15, 4008.45, 92.34, 0, ''), +(22424, 72, -3532.87, 4012.97, 91.64, 0, ''), +(22424, 73, -3530.57, 4023.42, 86.82, 0, ''), +(22424, 74, -3528.24, 4033.91, 85.69, 0, ''), +(22424, 75, -3526.22, 4043.75, 87.26, 0, ''), +(22424, 76, -3523.84, 4054.29, 92.42, 0, ''), +(22424, 77, -3522.44, 4059.06, 92.92, 0, ''), +(22424, 78, -3514.26, 4060.72, 92.92, 0, ''), +(22424, 79, -3507.76, 4065.21, 92.92, 0, ''), +(22424, 80, -3503.24, 4076.63, 92.92, 0, 'SAY_SKYWING_SUMMON'), +(22424, 81, -3504.23, 4080.47, 92.92, 7000, 'SPELL_TRANSFORM'), +(22424, 82, -3504.23, 4080.47, 92.92, 20000, 'SAY_SKYWING_END'); diff --git a/sql/updates/0.6/r2491_mangos.sql b/sql/updates/0.6/r2491_mangos.sql new file mode 100644 index 0000000000..e41c277b17 --- /dev/null +++ b/sql/updates/0.6/r2491_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_spawned_oronok_tornheart' WHERE entry=21685; diff --git a/sql/updates/0.6/r2491_scriptdev2.sql b/sql/updates/0.6/r2491_scriptdev2.sql new file mode 100644 index 0000000000..e0beb83223 --- /dev/null +++ b/sql/updates/0.6/r2491_scriptdev2.sql @@ -0,0 +1,18 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000814 AND -1000803; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000803,'You do not fight alone, %n! Together, we will banish this spawn of hellfire!',0,1,0,0,'Oronok SAY_ORONOK_TOGETHER'), +(-1000804,'We will fight when you are ready.',0,0,0,0, 'Oronok SAY_ORONOK_READY'), +(-1000805,'We will set the elements free of your grasp by force!',0,1,0,0,'Oronok SAY_ORONOK_ELEMENTS'), +(-1000806,'What say the elements, Torlok? I only hear silence.',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_1'), +(-1000807,'I hear what you hear, brother. Look behind you...',0,0,0,1,'Torlok SAY_TORLOK_EPILOGUE_2'), +(-1000808,'They are redeemed! Then we have won?',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_3'), +(-1000809,'It is now as it should be, shaman. You have done well.',0,0,0,0,'Spirit of Earth SAY_EARTH_EPILOGUE_4'), +(-1000810,'Yes... Well enough for the elements that are here, but the cipher is known to another... The spirits of fire are in turmoil... If this force is not stopped, the world where these mortals came from will cease.',0,0,0,0,'Spirit of Fire SAY_FIRE_EPILOGUE_5'), +(-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'); + +DELETE FROM gossip_texts WHERE entry=-3000109; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000109,'I am ready, Oronok. Let us destroy Cyrukh and free the elements!','oronok torn-heart GOSSIP_ITEM_FIGHT'); diff --git a/sql/updates/0.6/r2492_mangos.sql b/sql/updates/0.6/r2492_mangos.sql new file mode 100644 index 0000000000..8adc65fc12 --- /dev/null +++ b/sql/updates/0.6/r2492_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=12919; diff --git a/sql/updates/0.6/r2493_mangos.sql b/sql/updates/0.6/r2493_mangos.sql new file mode 100644 index 0000000000..7c741f766b --- /dev/null +++ b/sql/updates/0.6/r2493_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=23602; diff --git a/sql/updates/0.6/r2494_mangos.sql b/sql/updates/0.6/r2494_mangos.sql new file mode 100644 index 0000000000..c23e56e999 --- /dev/null +++ b/sql/updates/0.6/r2494_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=180368; diff --git a/sql/updates/0.6/r2495_mangos.sql b/sql/updates/0.6/r2495_mangos.sql new file mode 100644 index 0000000000..da84e2034d --- /dev/null +++ b/sql/updates/0.6/r2495_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=8816; diff --git a/sql/updates/0.6/r2496_mangos.sql b/sql/updates/0.6/r2496_mangos.sql new file mode 100644 index 0000000000..b27bcb90b5 --- /dev/null +++ b/sql/updates/0.6/r2496_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=12384; diff --git a/sql/updates/0.6/r2497_mangos.sql b/sql/updates/0.6/r2497_mangos.sql new file mode 100644 index 0000000000..11dac671e8 --- /dev/null +++ b/sql/updates/0.6/r2497_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=17832; diff --git a/sql/updates/0.6/r2498_mangos.sql b/sql/updates/0.6/r2498_mangos.sql new file mode 100644 index 0000000000..ae2446dfb8 --- /dev/null +++ b/sql/updates/0.6/r2498_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=23559; diff --git a/sql/updates/0.6/r2499_mangos.sql b/sql/updates/0.6/r2499_mangos.sql new file mode 100644 index 0000000000..e0278d63d8 --- /dev/null +++ b/sql/updates/0.6/r2499_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=8696; diff --git a/sql/updates/0.6/r2501_mangos.sql b/sql/updates/0.6/r2501_mangos.sql new file mode 100644 index 0000000000..1f00382cca --- /dev/null +++ b/sql/updates/0.6/r2501_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=10618; diff --git a/sql/updates/0.6/r2502_mangos.sql b/sql/updates/0.6/r2502_mangos.sql new file mode 100644 index 0000000000..0a992e8151 --- /dev/null +++ b/sql/updates/0.6/r2502_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=4968; diff --git a/sql/updates/0.6/r2503_scriptdev2.sql b/sql/updates/0.6/r2503_scriptdev2.sql new file mode 100644 index 0000000000..ed90bdc98b --- /dev/null +++ b/sql/updates/0.6/r2503_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11942+) '; diff --git a/sql/updates/0.6/r2504_mangos.sql b/sql/updates/0.6/r2504_mangos.sql new file mode 100644 index 0000000000..606aeb1051 --- /dev/null +++ b/sql/updates/0.6/r2504_mangos.sql @@ -0,0 +1,17 @@ +DELETE FROM scripted_areatrigger WHERE entry BETWEEN 1726 AND 1740; +INSERT INTO scripted_areatrigger VALUES +(1726,'at_scent_larkorwi'), +(1727,'at_scent_larkorwi'), +(1728,'at_scent_larkorwi'), +(1729,'at_scent_larkorwi'), +(1730,'at_scent_larkorwi'), +(1731,'at_scent_larkorwi'), +(1732,'at_scent_larkorwi'), +(1733,'at_scent_larkorwi'), +(1734,'at_scent_larkorwi'), +(1735,'at_scent_larkorwi'), +(1736,'at_scent_larkorwi'), +(1737,'at_scent_larkorwi'), +(1738,'at_scent_larkorwi'), +(1739,'at_scent_larkorwi'), +(1740,'at_scent_larkorwi'); diff --git a/sql/updates/0.6/r2509_mangos.sql b/sql/updates/0.6/r2509_mangos.sql new file mode 100644 index 0000000000..7a6b3b86b1 --- /dev/null +++ b/sql/updates/0.6/r2509_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=2708; diff --git a/sql/updates/0.6/r2510_mangos.sql b/sql/updates/0.6/r2510_mangos.sql new file mode 100644 index 0000000000..a52002af04 --- /dev/null +++ b/sql/updates/0.6/r2510_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=4488; diff --git a/sql/updates/0.6/r2511_mangos.sql b/sql/updates/0.6/r2511_mangos.sql new file mode 100644 index 0000000000..03506fef72 --- /dev/null +++ b/sql/updates/0.6/r2511_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (11056,11057); diff --git a/sql/updates/0.6/r2512_mangos.sql b/sql/updates/0.6/r2512_mangos.sql new file mode 100644 index 0000000000..95ad7a3d13 --- /dev/null +++ b/sql/updates/0.6/r2512_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=20201; diff --git a/sql/updates/0.6/r2514_mangos.sql b/sql/updates/0.6/r2514_mangos.sql new file mode 100644 index 0000000000..24d1b06c48 --- /dev/null +++ b/sql/updates/0.6/r2514_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_event_id WHERE id=4884; +INSERT INTO scripted_event_id VALUES +(4884,'event_spell_altar_emberseer'); diff --git a/sql/updates/0.6/r2516_mangos.sql b/sql/updates/0.6/r2516_mangos.sql new file mode 100644 index 0000000000..1ffde492f7 --- /dev/null +++ b/sql/updates/0.6/r2516_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (8888,9299,26924); diff --git a/sql/updates/0.6/r2518_mangos.sql b/sql/updates/0.6/r2518_mangos.sql new file mode 100644 index 0000000000..4583c0e9d0 --- /dev/null +++ b/sql/updates/0.6/r2518_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_spirit_shade' WHERE entry=15261; diff --git a/sql/updates/0.6/r2519_scriptdev2.sql b/sql/updates/0.6/r2519_scriptdev2.sql new file mode 100644 index 0000000000..fc48f40a9f --- /dev/null +++ b/sql/updates/0.6/r2519_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 11962+) '; diff --git a/sql/updates/0.6/r2525_mangos.sql b/sql/updates/0.6/r2525_mangos.sql new file mode 100644 index 0000000000..959fe860e8 --- /dev/null +++ b/sql/updates/0.6/r2525_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_spring_rabbit' WHERE entry=32791; diff --git a/sql/updates/0.6/r2528_scriptdev2.sql b/sql/updates/0.6/r2528_scriptdev2.sql new file mode 100644 index 0000000000..20edaa9997 --- /dev/null +++ b/sql/updates/0.6/r2528_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry=-1229019; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1229019,'%s is knocked off his drake!',0,2,0,0,'rend EMOTE_KNOCKED_OFF'); +UPDATE script_texts SET emote=1 WHERE entry IN (-1229004,-1229005,-1229007,-1229014,-1229018); +UPDATE script_texts SET emote=25 WHERE entry IN (-1229016); diff --git a/sql/updates/0.6/r2532_mangos.sql b/sql/updates/0.6/r2532_mangos.sql new file mode 100644 index 0000000000..30389eda67 --- /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 0000000000..252155b510 --- /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 0000000000..6c58d1938b --- /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 0000000000..bfddcec62c --- /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 0000000000..b9c0660730 --- /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 0000000000..0d093b0e2c --- /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 0000000000..91b4800ead --- /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 0000000000..29549be4be --- /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 0000000000..79fe6bce66 --- /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 0000000000..422155843f --- /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 0000000000..a0a0922fbc --- /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 0000000000..415fe13809 --- /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 0000000000..e89bb224a1 --- /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 0000000000..4e07132746 --- /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 0000000000..a1d04e707b --- /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 0000000000..fa9a05fc37 --- /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 0000000000..1de67a0e51 --- /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 0000000000..1e11253c1e --- /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 0000000000..a2d40acc07 --- /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 0000000000..a520c43426 --- /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 0000000000..1022603792 --- /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 0000000000..0266f5783c --- /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 0000000000..1d0fbafe16 --- /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 0000000000..8cc4152151 --- /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 0000000000..9707d02741 --- /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 0000000000..81c929143b --- /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 0000000000..836dd3d389 --- /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 0000000000..a3aac9996c --- /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 0000000000..d76b80625a --- /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 0000000000..244fd9cf95 --- /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 0000000000..20ec0ac803 --- /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 0000000000..cb20694454 --- /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 0000000000..c5ca2ac718 --- /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 0000000000..e3d5fb5e38 --- /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 0000000000..e0655415dc --- /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 0000000000..0a96c906e4 --- /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 0000000000..b1140712ed --- /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 0000000000..0a53a4dc9b --- /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 0000000000..f4592d2d77 --- /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 0000000000..f6c9e9fa1a --- /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 0000000000..a44ff675e0 --- /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 0000000000..cc3043bb4d --- /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 0000000000..11bae9151b --- /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 0000000000..19bdd36cc7 --- /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 0000000000..f6f99233e1 --- /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 0000000000..ab8d87891c --- /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 0000000000..8aa1f5b89e --- /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 0000000000..8a830c20d8 --- /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 0000000000..396b8d435c --- /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 0000000000..5e5c9baabe --- /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 0000000000..df879be3ef --- /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 0000000000..36b8701f20 --- /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 0000000000..c510c9cff5 --- /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 0000000000..a80fcadc06 --- /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 0000000000..8cc4e5ba44 --- /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 0000000000..03f565b36f --- /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 0000000000..dacfd326c8 --- /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 0000000000..8d23b1e67a --- /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 0000000000..0d63cfd751 --- /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 0000000000..a72318fd88 --- /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 0000000000..5e9113a06d --- /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 0000000000..a48f87a80d --- /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 0000000000..37bfc7b0d8 --- /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 0000000000..1cce2b13a5 --- /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 0000000000..af9da46980 --- /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 0000000000..db84b7f6d2 --- /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 0000000000..dd493a2665 --- /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 0000000000..57f6f93720 --- /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 0000000000..74e59c5ea2 --- /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 0000000000..055f148fe3 --- /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 0000000000..5e7ef3e72a --- /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 0000000000..e3b431692c --- /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 0000000000..40ef4eb79a --- /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 0000000000..a1c62ed28b --- /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 0000000000..9360af0c8d --- /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 0000000000..3763238ac7 --- /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 0000000000..08285c826e --- /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 0000000000..262da6df85 --- /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 0000000000..e84c430de1 --- /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 0000000000..59692026d3 --- /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 0000000000..de06faf836 --- /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 0000000000..4280ee2189 --- /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 0000000000..7271f68e73 --- /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 0000000000..d8777c4acb --- /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 0000000000..8fa66e5668 --- /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 0000000000..bf693d239c --- /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 0000000000..0d615c21ec --- /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 0000000000..dde13c3e14 --- /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 0000000000..39d4516070 --- /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 0000000000..673919bdfa --- /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 0000000000..9322a60edf --- /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 0000000000..faffc5d774 --- /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 0000000000..02fac67e5b --- /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 0000000000..c5d3d8cf85 --- /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 0000000000..def81fae26 --- /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 0000000000..3088ed78a8 --- /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 0000000000..2d4199f69f --- /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 0000000000..a270ba8843 --- /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 0000000000..032ea5e4de --- /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 0000000000..0dad5e2639 --- /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 0000000000..525d678559 --- /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 0000000000..84e04bf499 --- /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 0000000000..4d0461bcda --- /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 0000000000..bcaf00f305 --- /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 0000000000..5f457a20dc --- /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 0000000000..beb28edd7b --- /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 0000000000..d4e726dd86 --- /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 0000000000..971d0bb88b --- /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 0000000000..b588bef55f --- /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 0000000000..fba8074de3 --- /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 0000000000..dc9cf5160a --- /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 0000000000..55a8fe3beb --- /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 0000000000..f3f99148fa --- /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 0000000000..b0d17ba4e9 --- /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 0000000000..039ed20e31 --- /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 0000000000..a70d283417 --- /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 0000000000..04c79f9534 --- /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 0000000000..ddafeaeac5 --- /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 0000000000..1acb18d33f --- /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 0000000000..fdaf5b7527 --- /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 0000000000..ad92fdf846 --- /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 0000000000..efc5127fe2 --- /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 0000000000..980044589e --- /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 0000000000..18a79d1650 --- /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 0000000000..5a50904fe8 --- /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 0000000000..494bd50cf8 --- /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 0000000000..68cb2dbb84 --- /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 0000000000..de3461ca51 --- /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 0000000000..84f796272e --- /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 0000000000..8f4f1e5b75 --- /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 0000000000..d8822639dd --- /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 0000000000..c9314865b6 --- /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 0000000000..cb49c6ef06 --- /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 0000000000..b0d8618696 --- /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 0000000000..1a336d9c19 --- /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 0000000000..4d16e708a9 --- /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 0000000000..e80d822547 --- /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 0000000000..c6c2e38d02 --- /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 0000000000..60804b924f --- /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 0000000000..2fce2de056 --- /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 0000000000..ca7403767e --- /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 0000000000..6819ca8415 --- /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 0000000000..1b3927857b --- /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 0000000000..a916d8e6be --- /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 0000000000..c5b3652d42 --- /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 0000000000..07444dbc86 --- /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 0000000000..a6ea9b233f --- /dev/null +++ b/sql/updates/0.6/r2745_mangos.sql @@ -0,0 +1,30 @@ +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; + +Delete from creature where id=23089; +DELETE FROM creature_linking_template WHERE entry IN (23089, 23197, 23226, 23498, 22996, 22997, 23375); +INSERT INTO creature_linking_template (entry, map, master_entry, flag, search_range) VALUES +(23089, 564, 22917, 4096, 0), +(23197, 564, 22917, 4096, 0), +(23226, 564, 22917, 4112, 0), +(23498, 564, 22917, 4112, 0), +(22996, 564, 22917, 4096, 0), +(22997, 564, 22917, 4096, 0), +(23375, 564, 22917, 4096, 0); +delete from spell_script_target where entry in (39635,39849); +insert into spell_script_target values +(39635, 1, 23448), +(39849, 1, 23448); +-- cage spells +delete from spell_script_target where entry in (40704, 40707, 40708, 40709, 40710, 40711, 40712, 40713); +insert into spell_script_target values +(40704, 1, 23292), +(40707, 1, 23293), +(40708, 1, 23294), +(40709, 1, 23295), +(40710, 1, 23296), +(40711, 1, 23297), +(40712, 1, 23298), +(40713, 1, 23299); \ No newline at end of file diff --git a/sql/updates/0.6/r2745_scriptdev2.sql b/sql/updates/0.6/r2745_scriptdev2.sql new file mode 100644 index 0000000000..97f51a36ca --- /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 0000000000..6ded09da24 --- /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 0000000000..7c5fb4b8a8 --- /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/r2757_mangos.sql b/sql/updates/r2757_mangos.sql new file mode 100644 index 0000000000..8ce5af829e --- /dev/null +++ b/sql/updates/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/r2758_mangos.sql b/sql/updates/r2758_mangos.sql new file mode 100644 index 0000000000..ee8d476d16 --- /dev/null +++ b/sql/updates/r2758_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_scarlet_ghoul' WHERE entry=28845; diff --git a/sql/updates/r2758_scriptdev2.sql b/sql/updates/r2758_scriptdev2.sql new file mode 100644 index 0000000000..b6e3b42af8 --- /dev/null +++ b/sql/updates/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/r2761_mangos.sql b/sql/updates/r2761_mangos.sql new file mode 100644 index 0000000000..abb49c1c0b --- /dev/null +++ b/sql/updates/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/r2761_scriptdev2.sql b/sql/updates/r2761_scriptdev2.sql new file mode 100644 index 0000000000..64d4632ce8 --- /dev/null +++ b/sql/updates/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/r2762_scriptdev2.sql b/sql/updates/r2762_scriptdev2.sql new file mode 100644 index 0000000000..1214251637 --- /dev/null +++ b/sql/updates/r2762_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MangosR2 2473+ / C-MaNGOS 12280+)'; diff --git a/sql/updates/r2763_mangos.sql b/sql/updates/r2763_mangos.sql new file mode 100644 index 0000000000..1cb445c9e4 --- /dev/null +++ b/sql/updates/r2763_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_acherus_deathcharger' WHERE entry=28782; diff --git a/sql/updates/r2763_scriptdev2.sql b/sql/updates/r2763_scriptdev2.sql new file mode 100644 index 0000000000..e4a1170669 --- /dev/null +++ b/sql/updates/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/r2764_scriptdev2.sql b/sql/updates/r2764_scriptdev2.sql new file mode 100644 index 0000000000..46a52b00e1 --- /dev/null +++ b/sql/updates/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/r2765_scriptdev2.sql b/sql/updates/r2765_scriptdev2.sql new file mode 100644 index 0000000000..8482a5a325 --- /dev/null +++ b/sql/updates/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/r2766_mangos.sql b/sql/updates/r2766_mangos.sql new file mode 100644 index 0000000000..4fb6f9969a --- /dev/null +++ b/sql/updates/r2766_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_lich_king_light_dawn' WHERE entry=29183; diff --git a/sql/updates/r2768_scriptdev2.sql b/sql/updates/r2768_scriptdev2.sql new file mode 100644 index 0000000000..4ea4d2ae32 --- /dev/null +++ b/sql/updates/r2768_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12292+) '; diff --git a/sql/updates/r2773_scriptdev2.sql b/sql/updates/r2773_scriptdev2.sql new file mode 100644 index 0000000000..813405d900 --- /dev/null +++ b/sql/updates/r2773_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12308+) '; diff --git a/sql/updates/r2779_scriptdev2.sql b/sql/updates/r2779_scriptdev2.sql new file mode 100644 index 0000000000..6f32983b14 --- /dev/null +++ b/sql/updates/r2779_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12316+) '; diff --git a/sql/updates/r2783_scriptdev2.sql b/sql/updates/r2783_scriptdev2.sql new file mode 100644 index 0000000000..d5495df52f --- /dev/null +++ b/sql/updates/r2783_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12328+) '; diff --git a/sql/updates/r2785_scriptdev2.sql b/sql/updates/r2785_scriptdev2.sql new file mode 100644 index 0000000000..fca8408f08 --- /dev/null +++ b/sql/updates/r2785_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12361+) '; diff --git a/sql/updates/r2801_mangos.sql b/sql/updates/r2801_mangos.sql new file mode 100644 index 0000000000..ca24aa2c43 --- /dev/null +++ b/sql/updates/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/r2801_scriptdev2.sql b/sql/updates/r2801_scriptdev2.sql new file mode 100644 index 0000000000..8de4f70ce1 --- /dev/null +++ b/sql/updates/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/r2806_mangos.sql b/sql/updates/r2806_mangos.sql new file mode 100644 index 0000000000..0224a7a348 --- /dev/null +++ b/sql/updates/r2806_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=21729; diff --git a/sql/updates/r2820_scriptdev2.sql b/sql/updates/r2820_scriptdev2.sql new file mode 100644 index 0000000000..0d2e702c4e --- /dev/null +++ b/sql/updates/r2820_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12409+) '; diff --git a/sql/updates/r2821_mangos.sql b/sql/updates/r2821_mangos.sql new file mode 100644 index 0000000000..872467ffdb --- /dev/null +++ b/sql/updates/r2821_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=13016; diff --git a/sql/updates/r2822_scriptdev2.sql b/sql/updates/r2822_scriptdev2.sql new file mode 100644 index 0000000000..06bfa1c745 --- /dev/null +++ b/sql/updates/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/r2823_mangos.sql b/sql/updates/r2823_mangos.sql new file mode 100644 index 0000000000..e471353d1a --- /dev/null +++ b/sql/updates/r2823_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_impale_target' WHERE entry=29184; diff --git a/sql/updates/r2824_scriptdev2.sql b/sql/updates/r2824_scriptdev2.sql new file mode 100644 index 0000000000..d44a9e24dd --- /dev/null +++ b/sql/updates/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/r2831_mangos.sql b/sql/updates/r2831_mangos.sql new file mode 100644 index 0000000000..52f05db688 --- /dev/null +++ b/sql/updates/r2831_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_father_flame' WHERE entry=175245; diff --git a/sql/updates/r2831_scriptdev2.sql b/sql/updates/r2831_scriptdev2.sql new file mode 100644 index 0000000000..bc20cb3687 --- /dev/null +++ b/sql/updates/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/r2832_mangos.sql b/sql/updates/r2832_mangos.sql new file mode 100644 index 0000000000..7fe65fe975 --- /dev/null +++ b/sql/updates/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/r2832_scriptdev2.sql b/sql/updates/r2832_scriptdev2.sql new file mode 100644 index 0000000000..25534c1fad --- /dev/null +++ b/sql/updates/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/r2835_scriptdev2.sql b/sql/updates/r2835_scriptdev2.sql new file mode 100644 index 0000000000..f82b94b60f --- /dev/null +++ b/sql/updates/r2835_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=1 WHERE entry IN (-1658007,-1658010,-1658011); diff --git a/sql/updates/r2836_scriptdev2.sql b/sql/updates/r2836_scriptdev2.sql new file mode 100644 index 0000000000..cf40248ef3 --- /dev/null +++ b/sql/updates/r2836_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1658020,-1658047); diff --git a/sql/updates/r2837_mangos.sql b/sql/updates/r2837_mangos.sql new file mode 100644 index 0000000000..727ebf74c5 --- /dev/null +++ b/sql/updates/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/r2837_scriptdev2.sql b/sql/updates/r2837_scriptdev2.sql new file mode 100644 index 0000000000..4487e190ef --- /dev/null +++ b/sql/updates/r2837_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1658048,-1658049); diff --git a/sql/updates/r2838_mangos.sql b/sql/updates/r2838_mangos.sql new file mode 100644 index 0000000000..529040375b --- /dev/null +++ b/sql/updates/r2838_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_collapsing_icicle' WHERE entry=36847; diff --git a/sql/updates/r2840_mangos.sql b/sql/updates/r2840_mangos.sql new file mode 100644 index 0000000000..053198064c --- /dev/null +++ b/sql/updates/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/r2840_scriptdev2.sql b/sql/updates/r2840_scriptdev2.sql new file mode 100644 index 0000000000..bf1fbaa477 --- /dev/null +++ b/sql/updates/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/r2842_mangos.sql b/sql/updates/r2842_mangos.sql new file mode 100644 index 0000000000..cce22fbdcc --- /dev/null +++ b/sql/updates/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/r2846_mangos.sql b/sql/updates/r2846_mangos.sql new file mode 100644 index 0000000000..d9b0e057a7 --- /dev/null +++ b/sql/updates/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/r2853_scriptdev2.sql b/sql/updates/r2853_scriptdev2.sql new file mode 100644 index 0000000000..ad9b962cc4 --- /dev/null +++ b/sql/updates/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/r2856_mangos.sql b/sql/updates/r2856_mangos.sql new file mode 100644 index 0000000000..96fbc5a5d7 --- /dev/null +++ b/sql/updates/r2856_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_black_dragon_egg' WHERE entry=177807; diff --git a/sql/updates/r2856_scriptdev2.sql b/sql/updates/r2856_scriptdev2.sql new file mode 100644 index 0000000000..bac4197359 --- /dev/null +++ b/sql/updates/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/r2858_scriptdev2.sql b/sql/updates/r2858_scriptdev2.sql new file mode 100644 index 0000000000..2eb1d8bf00 --- /dev/null +++ b/sql/updates/r2858_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12451+) '; diff --git a/sql/updates/r2861_mangos.sql b/sql/updates/r2861_mangos.sql new file mode 100644 index 0000000000..3a1beed9bd --- /dev/null +++ b/sql/updates/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/r2863_mangos.sql b/sql/updates/r2863_mangos.sql new file mode 100644 index 0000000000..e6049ab7b9 --- /dev/null +++ b/sql/updates/r2863_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_feather_vortex' WHERE entry=24136; diff --git a/sql/updates/r2870_scriptdev2.sql b/sql/updates/r2870_scriptdev2.sql new file mode 100644 index 0000000000..417b0d053d --- /dev/null +++ b/sql/updates/r2870_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12458+) '; diff --git a/sql/updates/r2873_mangos.sql b/sql/updates/r2873_mangos.sql new file mode 100644 index 0000000000..607c1a0fdc --- /dev/null +++ b/sql/updates/r2873_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_power_blue_flight' WHERE entry=25653; diff --git a/sql/updates/r2874_mangos.sql b/sql/updates/r2874_mangos.sql new file mode 100644 index 0000000000..d1dd899e8e --- /dev/null +++ b/sql/updates/r2874_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_snufflenose_gopher' WHERE entry=4781; diff --git a/sql/updates/r2875_mangos.sql b/sql/updates/r2875_mangos.sql new file mode 100644 index 0000000000..f245badedd --- /dev/null +++ b/sql/updates/r2875_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_therylune' WHERE entry=3584; diff --git a/sql/updates/r2875_scriptdev2.sql b/sql/updates/r2875_scriptdev2.sql new file mode 100644 index 0000000000..f398bd3cc9 --- /dev/null +++ b/sql/updates/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/r2878_mangos.sql b/sql/updates/r2878_mangos.sql new file mode 100644 index 0000000000..d315c20237 --- /dev/null +++ b/sql/updates/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/r2879_mangos.sql b/sql/updates/r2879_mangos.sql new file mode 100644 index 0000000000..dcb9c2dcf2 --- /dev/null +++ b/sql/updates/r2879_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_fire_cyclone' WHERE entry=30648; diff --git a/sql/updates/r2880_mangos.sql b/sql/updates/r2880_mangos.sql new file mode 100644 index 0000000000..85324d697e --- /dev/null +++ b/sql/updates/r2880_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_sapphiron_birth' WHERE entry=181356; diff --git a/sql/updates/r2885_mangos.sql b/sql/updates/r2885_mangos.sql new file mode 100644 index 0000000000..1ca53c899e --- /dev/null +++ b/sql/updates/r2885_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_zumrah' WHERE entry=7271; diff --git a/sql/updates/r2885_scriptdev2.sql b/sql/updates/r2885_scriptdev2.sql new file mode 100644 index 0000000000..70aef751d5 --- /dev/null +++ b/sql/updates/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/r2889_scriptdev2.sql b/sql/updates/r2889_scriptdev2.sql new file mode 100644 index 0000000000..8278411764 --- /dev/null +++ b/sql/updates/r2889_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12491+) '; diff --git a/sql/updates/r2891_mangos.sql b/sql/updates/r2891_mangos.sql new file mode 100644 index 0000000000..1de3cdfbd5 --- /dev/null +++ b/sql/updates/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/r2893_mangos.sql b/sql/updates/r2893_mangos.sql new file mode 100644 index 0000000000..60f56b8dbf --- /dev/null +++ b/sql/updates/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/r2894_mangos.sql b/sql/updates/r2894_mangos.sql new file mode 100644 index 0000000000..91e3fa25ff --- /dev/null +++ b/sql/updates/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/r2894_scriptdev2.sql b/sql/updates/r2894_scriptdev2.sql new file mode 100644 index 0000000000..65f4d3e9d3 --- /dev/null +++ b/sql/updates/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/r2896_mangos.sql b/sql/updates/r2896_mangos.sql new file mode 100644 index 0000000000..b23ef47b7e --- /dev/null +++ b/sql/updates/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/r2897_mangos.sql b/sql/updates/r2897_mangos.sql new file mode 100644 index 0000000000..dd8d03be33 --- /dev/null +++ b/sql/updates/r2897_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_veneratus_spawn_node' WHERE entry=21334; diff --git a/sql/updates/r2897_scriptdev2.sql b/sql/updates/r2897_scriptdev2.sql new file mode 100644 index 0000000000..064ea9970a --- /dev/null +++ b/sql/updates/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/r2898_mangos.sql b/sql/updates/r2898_mangos.sql new file mode 100644 index 0000000000..78684f24a4 --- /dev/null +++ b/sql/updates/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/r2898_scriptdev2.sql b/sql/updates/r2898_scriptdev2.sql new file mode 100644 index 0000000000..078ea407d9 --- /dev/null +++ b/sql/updates/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/r2899_mangos.sql b/sql/updates/r2899_mangos.sql new file mode 100644 index 0000000000..833a294912 --- /dev/null +++ b/sql/updates/r2899_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_demonic_vapor' WHERE entry=25265; diff --git a/sql/updates/r2899_scriptdev2.sql b/sql/updates/r2899_scriptdev2.sql new file mode 100644 index 0000000000..6524bbfe30 --- /dev/null +++ b/sql/updates/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/r2901_scriptdev2.sql b/sql/updates/r2901_scriptdev2.sql new file mode 100644 index 0000000000..6b922423cb --- /dev/null +++ b/sql/updates/r2901_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12514+) '; diff --git a/sql/updates/r2902_mangos.sql b/sql/updates/r2902_mangos.sql new file mode 100644 index 0000000000..7650acd4b5 --- /dev/null +++ b/sql/updates/r2902_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_simon_game_bunny' WHERE entry=22923; diff --git a/sql/updates/r2903_scriptdev2.sql b/sql/updates/r2903_scriptdev2.sql new file mode 100644 index 0000000000..5426b09155 --- /dev/null +++ b/sql/updates/r2903_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12524+) '; diff --git a/sql/updates/r2904_mangos.sql b/sql/updates/r2904_mangos.sql new file mode 100644 index 0000000000..a96298513f --- /dev/null +++ b/sql/updates/r2904_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_anchorite_truuen' WHERE entry=17238; diff --git a/sql/updates/r2904_scriptdev2.sql b/sql/updates/r2904_scriptdev2.sql new file mode 100644 index 0000000000..bed35b3a32 --- /dev/null +++ b/sql/updates/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/r2905_mangos.sql b/sql/updates/r2905_mangos.sql new file mode 100644 index 0000000000..f39be10b26 --- /dev/null +++ b/sql/updates/r2905_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_lich_king_village' WHERE entry=24248; diff --git a/sql/updates/r2905_scriptdev2.sql b/sql/updates/r2905_scriptdev2.sql new file mode 100644 index 0000000000..9432c3af4a --- /dev/null +++ b/sql/updates/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/r2907_mangos.sql b/sql/updates/r2907_mangos.sql new file mode 100644 index 0000000000..6a99f08800 --- /dev/null +++ b/sql/updates/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/r2907_scriptdev2.sql b/sql/updates/r2907_scriptdev2.sql new file mode 100644 index 0000000000..1417614eca --- /dev/null +++ b/sql/updates/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/r2908_mangos.sql b/sql/updates/r2908_mangos.sql new file mode 100644 index 0000000000..c6a3885b51 --- /dev/null +++ b/sql/updates/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/r2908_scriptdev2.sql b/sql/updates/r2908_scriptdev2.sql new file mode 100644 index 0000000000..604f95da12 --- /dev/null +++ b/sql/updates/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/r2912_mangos.sql b/sql/updates/r2912_mangos.sql new file mode 100644 index 0000000000..4ec9d9357a --- /dev/null +++ b/sql/updates/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/r2913_scriptdev2.sql b/sql/updates/r2913_scriptdev2.sql new file mode 100644 index 0000000000..1075c4ac52 --- /dev/null +++ b/sql/updates/r2913_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=293 WHERE entry=-1580032; diff --git a/sql/updates/r2914_scriptdev2.sql b/sql/updates/r2914_scriptdev2.sql new file mode 100644 index 0000000000..bdc36b3a4a --- /dev/null +++ b/sql/updates/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/r2915_mangos.sql b/sql/updates/r2915_mangos.sql new file mode 100644 index 0000000000..ee844e62f0 --- /dev/null +++ b/sql/updates/r2915_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_kinelory' WHERE entry=2713; diff --git a/sql/updates/r2915_scriptdev2.sql b/sql/updates/r2915_scriptdev2.sql new file mode 100644 index 0000000000..ebc0528d87 --- /dev/null +++ b/sql/updates/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/r2916_mangos.sql b/sql/updates/r2916_mangos.sql new file mode 100644 index 0000000000..2b44a6e3c9 --- /dev/null +++ b/sql/updates/r2916_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_stinky_ignatz' WHERE entry=4880; diff --git a/sql/updates/r2916_scriptdev2.sql b/sql/updates/r2916_scriptdev2.sql new file mode 100644 index 0000000000..05044e053d --- /dev/null +++ b/sql/updates/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/r2917_mangos.sql b/sql/updates/r2917_mangos.sql new file mode 100644 index 0000000000..eabbbf8a7d --- /dev/null +++ b/sql/updates/r2917_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_rabid_bear' WHERE entry=2164; diff --git a/sql/updates/r2918_mangos.sql b/sql/updates/r2918_mangos.sql new file mode 100644 index 0000000000..847cd57cbd --- /dev/null +++ b/sql/updates/r2918_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_kernobee' WHERE entry=7850; diff --git a/sql/updates/r2920_mangos.sql b/sql/updates/r2920_mangos.sql new file mode 100644 index 0000000000..5797c6aca8 --- /dev/null +++ b/sql/updates/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/r2920_scriptdev2.sql b/sql/updates/r2920_scriptdev2.sql new file mode 100644 index 0000000000..496eff467c --- /dev/null +++ b/sql/updates/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/r2921_mangos.sql b/sql/updates/r2921_mangos.sql new file mode 100644 index 0000000000..76872f107e --- /dev/null +++ b/sql/updates/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/r2926_mangos.sql b/sql/updates/r2926_mangos.sql new file mode 100644 index 0000000000..816b05c922 --- /dev/null +++ b/sql/updates/r2926_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_hogger' WHERE entry=448; diff --git a/sql/updates/r2926_scriptdev2.sql b/sql/updates/r2926_scriptdev2.sql new file mode 100644 index 0000000000..97eb8e7137 --- /dev/null +++ b/sql/updates/r2926_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1004002 AND -1004000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1004000,'Yipe! Help Hogger!',0,1,0,0,'hogger SAY_CALL_HELP'), +(-1004001,'Hogger is eating! Stop him!',0,5,0,0,'hogger WHISPER_EATING'), +(-1004002,'No hurt Hogger!',0,1,0,0,'hogger SAY_HOGGER_BEATEN'); diff --git a/sql/updates/r2955_mangos.sql b/sql/updates/r2955_mangos.sql new file mode 100644 index 0000000000..0fcef2fb9e --- /dev/null +++ b/sql/updates/r2955_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName="npc_cenarion_sparrowhawk" WHERE entry=22972; diff --git a/sql/updates/r2955_scriptdev2.sql b/sql/updates/r2955_scriptdev2.sql new file mode 100644 index 0000000000..a7664bc4e6 --- /dev/null +++ b/sql/updates/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/r2969_mangos.sql b/sql/updates/r2969_mangos.sql new file mode 100644 index 0000000000..1280a23f4d --- /dev/null +++ b/sql/updates/r2969_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (22208,22212,22213); diff --git a/sql/updates/r2980_mangos.sql b/sql/updates/r2980_mangos.sql new file mode 100644 index 0000000000..c25fc00829 --- /dev/null +++ b/sql/updates/r2980_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (30169); diff --git a/sql/updates/r2981_mangos.sql b/sql/updates/r2981_mangos.sql new file mode 100644 index 0000000000..739d66e075 --- /dev/null +++ b/sql/updates/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/r2983_scriptdev2.sql b/sql/updates/r2983_scriptdev2.sql new file mode 100644 index 0000000000..98f8c428c6 --- /dev/null +++ b/sql/updates/r2983_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12587+) '; diff --git a/sql/updates/r2984_mangos.sql b/sql/updates/r2984_mangos.sql new file mode 100644 index 0000000000..ec4cf22988 --- /dev/null +++ b/sql/updates/r2984_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_nexus_drake_hatchling' WHERE entry=26127; diff --git a/sql/updates/r2985_mangos.sql b/sql/updates/r2985_mangos.sql new file mode 100644 index 0000000000..75259cc543 --- /dev/null +++ b/sql/updates/r2985_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_rethhedron' WHERE entry=22357; diff --git a/sql/updates/r2985_scriptdev2.sql b/sql/updates/r2985_scriptdev2.sql new file mode 100644 index 0000000000..94d0e8a853 --- /dev/null +++ b/sql/updates/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/r2987_mangos.sql b/sql/updates/r2987_mangos.sql new file mode 100644 index 0000000000..22290edd94 --- /dev/null +++ b/sql/updates/r2987_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_drijya' WHERE entry=20281; diff --git a/sql/updates/r2987_scriptdev2.sql b/sql/updates/r2987_scriptdev2.sql new file mode 100644 index 0000000000..e1afb9f534 --- /dev/null +++ b/sql/updates/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/r2988_mangos.sql b/sql/updates/r2988_mangos.sql new file mode 100644 index 0000000000..0524736d70 --- /dev/null +++ b/sql/updates/r2988_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_firecrackers_bunny' WHERE entry=24230; diff --git a/sql/updates/r2989_mangos.sql b/sql/updates/r2989_mangos.sql new file mode 100644 index 0000000000..f8386f37e9 --- /dev/null +++ b/sql/updates/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/r2991_scriptdev2.sql b/sql/updates/r2991_scriptdev2.sql new file mode 100644 index 0000000000..5fb3f18ac9 --- /dev/null +++ b/sql/updates/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/r2992_mangos.sql b/sql/updates/r2992_mangos.sql new file mode 100644 index 0000000000..927a5e5232 --- /dev/null +++ b/sql/updates/r2992_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_scourged_flamespitter' WHERE entry=25582; diff --git a/sql/updates/r2994_mangos.sql b/sql/updates/r2994_mangos.sql new file mode 100644 index 0000000000..2e811e2832 --- /dev/null +++ b/sql/updates/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/r2994_scriptdev2.sql b/sql/updates/r2994_scriptdev2.sql new file mode 100644 index 0000000000..fda85199e6 --- /dev/null +++ b/sql/updates/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/r2995_mangos.sql b/sql/updates/r2995_mangos.sql new file mode 100644 index 0000000000..2a289a578d --- /dev/null +++ b/sql/updates/r2995_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_dorius_stonetender' WHERE entry=8284; diff --git a/sql/updates/r2995_scriptdev2.sql b/sql/updates/r2995_scriptdev2.sql new file mode 100644 index 0000000000..b3e8c39e9c --- /dev/null +++ b/sql/updates/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/r2996_mangos.sql b/sql/updates/r2996_mangos.sql new file mode 100644 index 0000000000..e224d0f630 --- /dev/null +++ b/sql/updates/r2996_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_fhwoor' WHERE entry=17877; diff --git a/sql/updates/r2996_scriptdev2.sql b/sql/updates/r2996_scriptdev2.sql new file mode 100644 index 0000000000..a2778120e4 --- /dev/null +++ b/sql/updates/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/r2997_mangos.sql b/sql/updates/r2997_mangos.sql new file mode 100644 index 0000000000..69928c88e0 --- /dev/null +++ b/sql/updates/r2997_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_nagrand_captive' WHERE entry IN (18209,18210); diff --git a/sql/updates/r2997_scriptdev2.sql b/sql/updates/r2997_scriptdev2.sql new file mode 100644 index 0000000000..4d36a5055b --- /dev/null +++ b/sql/updates/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/r2998_mangos.sql b/sql/updates/r2998_mangos.sql new file mode 100644 index 0000000000..d2fdb99b89 --- /dev/null +++ b/sql/updates/r2998_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName="npc_skyguard_prisoner" WHERE entry=23383; diff --git a/sql/updates/r2998_scriptdev2.sql b/sql/updates/r2998_scriptdev2.sql new file mode 100644 index 0000000000..029cc1417e --- /dev/null +++ b/sql/updates/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/r2999_mangos.sql b/sql/updates/r2999_mangos.sql new file mode 100644 index 0000000000..d3ef848c11 --- /dev/null +++ b/sql/updates/r2999_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_bonker_togglevolt' WHERE entry=25589; diff --git a/sql/updates/r2999_scriptdev2.sql b/sql/updates/r2999_scriptdev2.sql new file mode 100644 index 0000000000..54b16dbb16 --- /dev/null +++ b/sql/updates/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/r3001_scriptdev2.sql b/sql/updates/r3001_scriptdev2.sql new file mode 100644 index 0000000000..26fa9744d0 --- /dev/null +++ b/sql/updates/r3001_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MangosR2 3157+ / for CMaNGOS 12661+)'; diff --git a/sql/updates/r3005_mangos.sql b/sql/updates/r3005_mangos.sql new file mode 100644 index 0000000000..c3fab4ebd7 --- /dev/null +++ b/sql/updates/r3005_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_injured_miner' WHERE entry=29434; diff --git a/sql/updates/r3005_scriptdev2.sql b/sql/updates/r3005_scriptdev2.sql new file mode 100644 index 0000000000..2b13b1541b --- /dev/null +++ b/sql/updates/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/r3006_mangos.sql b/sql/updates/r3006_mangos.sql new file mode 100644 index 0000000000..103770c391 --- /dev/null +++ b/sql/updates/r3006_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_harrison_jones' WHERE entry=26814; diff --git a/sql/updates/r3006_scriptdev2.sql b/sql/updates/r3006_scriptdev2.sql new file mode 100644 index 0000000000..dbfdcbbfa0 --- /dev/null +++ b/sql/updates/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/r3007_mangos.sql b/sql/updates/r3007_mangos.sql new file mode 100644 index 0000000000..313da0f3f7 --- /dev/null +++ b/sql/updates/r3007_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_apothecary_hanes' WHERE entry=23784; diff --git a/sql/updates/r3007_scriptdev2.sql b/sql/updates/r3007_scriptdev2.sql new file mode 100644 index 0000000000..45e88c4b87 --- /dev/null +++ b/sql/updates/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/r3008_mangos.sql b/sql/updates/r3008_mangos.sql new file mode 100644 index 0000000000..aa4667cd83 --- /dev/null +++ b/sql/updates/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/r3008_scriptdev2.sql b/sql/updates/r3008_scriptdev2.sql new file mode 100644 index 0000000000..ddf70608b0 --- /dev/null +++ b/sql/updates/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/r3010_mangos.sql b/sql/updates/r3010_mangos.sql new file mode 100644 index 0000000000..20aea03861 --- /dev/null +++ b/sql/updates/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/r3011_mangos.sql b/sql/updates/r3011_mangos.sql new file mode 100644 index 0000000000..82d573c565 --- /dev/null +++ b/sql/updates/r3011_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_tethyr' WHERE entry=23899; diff --git a/sql/updates/r3012_mangos.sql b/sql/updates/r3012_mangos.sql new file mode 100644 index 0000000000..488026be5d --- /dev/null +++ b/sql/updates/r3012_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_shay_leafrunner' WHERE entry=7774; diff --git a/sql/updates/r3012_scriptdev2.sql b/sql/updates/r3012_scriptdev2.sql new file mode 100644 index 0000000000..52a221402c --- /dev/null +++ b/sql/updates/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/r3013_mangos.sql b/sql/updates/r3013_mangos.sql new file mode 100644 index 0000000000..192c5418c1 --- /dev/null +++ b/sql/updates/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/r3014_mangos.sql b/sql/updates/r3014_mangos.sql new file mode 100644 index 0000000000..19489ecf7a --- /dev/null +++ b/sql/updates/r3014_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_saronite_mine_slave' WHERE entry=31397; diff --git a/sql/updates/r3014_scriptdev2.sql b/sql/updates/r3014_scriptdev2.sql new file mode 100644 index 0000000000..69d1155237 --- /dev/null +++ b/sql/updates/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/r3015_mangos.sql b/sql/updates/r3015_mangos.sql new file mode 100644 index 0000000000..d9b1a966fc --- /dev/null +++ b/sql/updates/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/r3015_scriptdev2.sql b/sql/updates/r3015_scriptdev2.sql new file mode 100644 index 0000000000..db83160505 --- /dev/null +++ b/sql/updates/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/r3016_scriptdev2.sql b/sql/updates/r3016_scriptdev2.sql new file mode 100644 index 0000000000..dd04e9c1d1 --- /dev/null +++ b/sql/updates/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/r3017_mangos.sql b/sql/updates/r3017_mangos.sql new file mode 100644 index 0000000000..f778d76cc4 --- /dev/null +++ b/sql/updates/r3017_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_head_of_horseman' WHERE entry=23775; diff --git a/sql/updates/r3018_scriptdev2.sql b/sql/updates/r3018_scriptdev2.sql new file mode 100644 index 0000000000..ea50fe55c2 --- /dev/null +++ b/sql/updates/r3018_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12674+) '; diff --git a/sql/updates/r3019_mangos.sql b/sql/updates/r3019_mangos.sql new file mode 100644 index 0000000000..f83fd315d2 --- /dev/null +++ b/sql/updates/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/r3021_scriptdev2.sql b/sql/updates/r3021_scriptdev2.sql new file mode 100644 index 0000000000..03e74caadb --- /dev/null +++ b/sql/updates/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/r3022_mangos.sql b/sql/updates/r3022_mangos.sql new file mode 100644 index 0000000000..1dea888f59 --- /dev/null +++ b/sql/updates/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/r3022_scriptdev2.sql b/sql/updates/r3022_scriptdev2.sql new file mode 100644 index 0000000000..c6f8a3fc84 --- /dev/null +++ b/sql/updates/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/r3023_mangos.sql b/sql/updates/r3023_mangos.sql new file mode 100644 index 0000000000..8924058190 --- /dev/null +++ b/sql/updates/r3023_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_captured_arkonarin' WHERE entry=11016; diff --git a/sql/updates/r3023_scriptdev2.sql b/sql/updates/r3023_scriptdev2.sql new file mode 100644 index 0000000000..869977199c --- /dev/null +++ b/sql/updates/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/r3024_mangos.sql b/sql/updates/r3024_mangos.sql new file mode 100644 index 0000000000..fa66c09887 --- /dev/null +++ b/sql/updates/r3024_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_arei' WHERE entry=9598; diff --git a/sql/updates/r3024_scriptdev2.sql b/sql/updates/r3024_scriptdev2.sql new file mode 100644 index 0000000000..dfe9c20d76 --- /dev/null +++ b/sql/updates/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/r3025_scriptdev2.sql b/sql/updates/r3025_scriptdev2.sql new file mode 100644 index 0000000000..1aa4d2fb1b --- /dev/null +++ b/sql/updates/r3025_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12682+) '; diff --git a/sql/updates/r3028_mangos.sql b/sql/updates/r3028_mangos.sql new file mode 100644 index 0000000000..5c92ef8151 --- /dev/null +++ b/sql/updates/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/r3028_scriptdev2.sql b/sql/updates/r3028_scriptdev2.sql new file mode 100644 index 0000000000..6eb0469f20 --- /dev/null +++ b/sql/updates/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/r3029_mangos.sql b/sql/updates/r3029_mangos.sql new file mode 100644 index 0000000000..1b3c03c5a5 --- /dev/null +++ b/sql/updates/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/r3031_mangos.sql b/sql/updates/r3031_mangos.sql new file mode 100644 index 0000000000..7c8383710b --- /dev/null +++ b/sql/updates/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/r3031_scriptdev2.sql b/sql/updates/r3031_scriptdev2.sql new file mode 100644 index 0000000000..8a03440597 --- /dev/null +++ b/sql/updates/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/r3034_scriptdev2.sql b/sql/updates/r3034_scriptdev2.sql new file mode 100644 index 0000000000..3bd09be2d4 --- /dev/null +++ b/sql/updates/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_mr/custom_scriptdev2_bsw_table.sql b/sql_mr/custom_scriptdev2_bsw_table.sql new file mode 100644 index 0000000000..6ceddc2557 --- /dev/null +++ b/sql_mr/custom_scriptdev2_bsw_table.sql @@ -0,0 +1,33 @@ +DROP TABLE IF EXISTS `boss_spell_table`; +CREATE TABLE IF NOT EXISTS `boss_spell_table` ( + `entry` mediumint(8) NOT NULL DEFAULT '0' COMMENT 'Creature entry', + `spellID_N10` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell ID for 10 normal', + `spellID_N25` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell ID for 25 normal', + `spellID_H10` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell ID for 10 heroic', + `spellID_H25` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell ID for 25 heroic', + `timerMin_N10` mediumint(8) unsigned NOT NULL DEFAULT '15000' COMMENT 'Minimum timer for this spell (in ms.) for 10 normal', + `timerMin_N25` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Minimum timer for this spell (in ms.) for 25 normal', + `timerMin_H10` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Minimum timer for this spell (in ms.) for 10 heroic', + `timerMin_H25` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Minimum timer for this spell (in ms.) for 25 heroic', + `timerMax_N10` mediumint(8) unsigned NOT NULL DEFAULT '30000' COMMENT 'Maximum timer for this spell (in ms.) for 10 normal', + `timerMax_N25` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Maximum timer for this spell (in ms.) for 25 normal', + `timerMax_H10` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Maximum timer for this spell (in ms.) for 10 heroic', + `timerMax_H25` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Maximum timer for this spell (in ms.) for 25 heroic', + `data1` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Various INT data for this spell or summon for 10 normal', + `data2` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Various INT data for this spell for 25 normal', + `data3` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Various INT data for this spell for 10 heroic', + `data4` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Various INT data for this spell for 25 heroic', + `locData_x` float NOT NULL DEFAULT '0' COMMENT 'Location X data for this spell', + `locData_y` float NOT NULL DEFAULT '0' COMMENT 'Location Y data for this spell', + `locData_z` float NOT NULL DEFAULT '0' COMMENT 'Location Z data for this spell', + `varData` mediumint(8) NOT NULL DEFAULT '0' COMMENT 'Special data field for this spell (basepoint for Aura, for example)', + `StageMask_N` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Stage mask for this spell (don\'t used now)', + `StageMask_H` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Stage mask for this spell - heroic mode (don\'t used now)', + `CastType` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Type of cast (by enum BossSpellTableParameters)', + `isVisualEffect` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Is spell is Visual effect only', + `isBugged` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Is spell bugged and need override', + `textEntry` mediumint(8) NOT NULL DEFAULT '0' COMMENT 'Text from script_texts for this spell casting', + `comment` text, + PRIMARY KEY (`entry`,`spellID_N10`,`CastType`), + INDEX `idx_entry`(`entry`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT 'Boss spell table by /dev/rsa'; diff --git a/sql_mr/last_mangos_sql_at_every_db_update.sql b/sql_mr/last_mangos_sql_at_every_db_update.sql new file mode 100644 index 0000000000..f9acf77ad4 --- /dev/null +++ b/sql_mr/last_mangos_sql_at_every_db_update.sql @@ -0,0 +1,69 @@ +-- ---------------------------------------- +-- mangosR2 EAI CleanUp for Quests && SD2 - +-- ---------------------------------------- + +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 25316; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 26127; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 27483; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 28610; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 28939; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29199; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29200; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29204; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29206; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29219; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 32149; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 32257; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 36626; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 36678; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29395; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30660; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30661; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30662; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30663; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30664; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30666; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30667; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30668; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 32191; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30695; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 31011; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 31079; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 32191; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 31118; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 29395; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 31513; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 39814; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 38163; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 38422; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 38508; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37949; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 34800; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 36791; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37863; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37868; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37886; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37934; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37890; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37918; + + +-- fixes for YTDB DB update +UPDATE creature_template SET ScriptName='' WHERE entry IN (35035, 35770, 35771, 35766); +UPDATE creature_template SET ScriptName='' WHERE entry=36549; +UPDATE `creature_template` SET `scriptname` = 'npc_toc_announcer' WHERE `entry` = 34816; -- needed to be rerun + + +DELETE FROM `gameobject` WHERE `id` = 190643 AND `guid` = 511000; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(511000, 190643, 571, 1, 1, 5545.45, 5767.53, -77.8042, 5.39307, 0, 0, 0.959937, 0.280215, -25, 0, 1); + +-- EAI Text clean up for quests/sd2 +DELETE FROM `creature_ai_texts` WHERE `entry` BETWEEN -1128 AND -1120; +DELETE FROM `creature_ai_texts` WHERE `entry` BETWEEN -565 AND -555; +DELETE FROM `creature_ai_texts` WHERE `entry` IN(-696, -697); +DELETE FROM `creature_ai_texts` WHERE `entry`= -1137; + +-- Official Sd2 Clean up +UPDATE creature_template SET ScriptName='' WHERE entry IN (30679,32174); +UPDATE gameobject_template SET ScriptName='' WHERE entry = 193611; diff --git a/sql_mr/mr00001_mangos_fishing_extravaganza.sql b/sql_mr/mr00001_mangos_fishing_extravaganza.sql new file mode 100644 index 0000000000..d980b95adc --- /dev/null +++ b/sql_mr/mr00001_mangos_fishing_extravaganza.sql @@ -0,0 +1,48 @@ +-- set ai for riggle +UPDATE `creature_template` SET `ScriptName`='npc_riggle_bassbait' WHERE entry=15077; +-- updated start time for event Fishing Extravaganza +UPDATE `game_event` SET `start_time` = '2009-06-14 14:00:00' WHERE `entry` = 15; +-- Create Jang +UPDATE `creature` SET `equipment_id` = 1711, `position_x` = -14438, `position_y` = 473.661, `position_z` = 15.3137, `orientation` = 3.65362, `curhealth` = 3200 WHERE `id` = 15078; +-- Create Fishbot 5000 +UPDATE `creature` SET `position_x` = -14440, `position_y` = 477.446, `position_z` = 15.25, `orientation` = 3.71802, `curhealth` = 2600 WHERE `id` = 15079; +-- Create Riggle Bassbait +UPDATE `creature` SET `equipment_id` = 13, `position_x` = -14439.3, `position_y` = 475.42, `position_z` = 15.892, `orientation` = 3.68503, `curhealth` = 3700 WHERE `id` = 15077; +-- Create Soapbox gameobject +DELETE FROM `gameobject` WHERE `id`=180403; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(954391, 180403, 0, 1, 1, -14439.3, 475.42, 15.2791, 3.68503, 0, 0, 0.963311, -0.268388, 25, 0, 1); + +-- new event - Fishing Extravaganza Questgivers +-- Remove NPC and GO from any other event. +DELETE FROM `game_event_creature` WHERE `guid` IN (954687,954688,954689); +DELETE FROM `game_event_gameobject`WHERE `guid` = 954391; +-- Create Event +DELETE FROM `game_event` WHERE `entry` = 35; -- this cause drop event "Edge of Madness, Gri'lek" from ytdb ! +INSERT INTO `game_event` (`entry`, `start_time`, `end_time`, `occurence`, `length`, `holiday`, `description`) VALUES +(35, '2009-03-29 14:00:00', '2020-12-31 00:00:00', 10080, 180, 0, 'Fishing Extravaganza Questgivers'); +-- Add NPCs to Event +DELETE FROM `game_event_creature` WHERE abs(`event`) = 35; +INSERT INTO `game_event_creature` (`guid`, `event`) VALUES +(954687,35), +(954688,35), +(954689,35); +-- Add Soapbox to Event +DELETE FROM `game_event_gameobject` WHERE abs(`event`) = 35; +INSERT INTO `game_event_gameobject` (`guid`, `event`) VALUES +(954391,35); +-- Remove Quests from normal DB: +DELETE FROM `creature_questrelation` WHERE quest IN (8193,8194,8225,8224,8221); +-- Add Quests to Event +-- Riggle Bassbait Quest: Master Angler +-- Jang Quest: Apprentice Angler +-- Fishbot 5000 Quest: Rare Fish - Brownell's Blue Striped Racer +-- Fishbot 5000 Quest: Rare Fish - Dezian Queenfish +-- Fishbot 5000 Quest: Rare Fish - Keefer's Angelfish +DELETE FROM `game_event_quest` WHERE `event` = 35; +INSERT INTO `game_event_quest` (`quest`,`event`) VALUES +(8193,35), +(8194,35), +(8225,35), +(8224,35), +(8221,35); diff --git a/sql_mr/mr00001_mangos_teleguy.sql b/sql_mr/mr00001_mangos_teleguy.sql new file mode 100644 index 0000000000..0244a10189 --- /dev/null +++ b/sql_mr/mr00001_mangos_teleguy.sql @@ -0,0 +1,3 @@ +DELETE FROM creature_template WHERE entry=99001; +INSERT INTO creature_template (Entry, Name, SubName, IconName, MinLevel, MaxLevel, DifficultyEntry1, DifficultyEntry2, DifficultyEntry3, ModelId1, ModelId2, ModelId3, ModelId4, FactionAlliance, FactionHorde, Scale, Family, CreatureType, InhabitType, RegenerateStats, RacialLeader, NpcFlags, UnitFlags, DynamicFlags, ExtraFlags, CreatureTypeFlags, SpeedWalk, SpeedRun, UnitClass, Rank, Expansion, HealthMultiplier, PowerMultiplier, DamageMultiplier, DamageVariance, ArmorMultiplier, ExperienceMultiplier, MinLevelHealth, MaxLevelHealth, MinLevelMana, MaxLevelMana, MinMeleeDmg, MaxMeleeDmg, MinRangedDmg, MaxRangedDmg, Armor, MeleeAttackPower, RangedAttackPower, MeleeBaseAttackTime, RangedBaseAttackTime, DamageSchool, MinLootGold, MaxLootGold, LootId, PickpocketLootId, SkinningLootId, KillCredit1, KillCredit2, QuestItem1, QuestItem2, QuestItem3, QuestItem4, QuestItem5, QuestItem6, MechanicImmuneMask, ResistanceHoly, ResistanceFire, ResistanceNature, ResistanceFrost, ResistanceShadow, ResistanceArcane, PetSpellDataId, MovementType, MovementTemplateId, TrainerType, TrainerSpell, TrainerClass, TrainerRace, TrainerTemplateId, VendorTemplateId, EquipmentTemplateId, VehicleTemplateId, GossipMenuId, AIName, ScriptName) VALUES +('99001', 'Slappy McFry', 'The Teleport Guy', null, '59', '61', '0', '0', '0', '18', '0', '18', '0', '35', '35', '1', '0', '7', '3', '3', '0', '1', '0', '0', '0', '0', '1.48', '1.14286', '2', '0', '-1', '1', '1', '1.4', '1', '1', '1', '6700', '24000', '5598', '5875', '98', '147', '78', '118', '4049', '37', '30', '1400', '1400', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '', 'mob_teleguy'); diff --git a/sql_mr/mr00001_mangos_the_violet_hold.sql b/sql_mr/mr00001_mangos_the_violet_hold.sql new file mode 100644 index 0000000000..5bd61b4f99 --- /dev/null +++ b/sql_mr/mr00001_mangos_the_violet_hold.sql @@ -0,0 +1,29 @@ +-- -------------- +-- VIOLET HOLD - +-- -------------- + +UPDATE `creature_template` SET `ScriptName`='boss_moragg' WHERE entry=29316; +UPDATE `creature_template` SET `ScriptName`='mob_ichor_globule' WHERE entry=29321; +UPDATE `creature_template` SET `ScriptName`='boss_xevozz' WHERE entry=29266; +UPDATE `creature_template` SET `ScriptName`='mob_ethereal_sphere' WHERE entry=29271; +UPDATE `creature_template` SET `ScriptName`='boss_lavanthor' WHERE entry=29312; +UPDATE `creature_template` SET `ScriptName`='boss_zuramat'WHERE entry=29314; +UPDATE `creature_template` SET `ScriptName`='mob_zuramat_sentry' WHERE entry=29364; +UPDATE `creature_template` SET `ScriptName`='boss_cyanigosa' WHERE entry=31134; +UPDATE `creature_template` SET `ScriptName`='npc_azure_saboteur', AIName='' WHERE entry=31079; +UPDATE `creature_template` SET `ScriptName`='mob_vh_dragons', AIName='' WHERE entry IN (30666,30668,30667,32191,30660,30695,30663,30661,30664,30662); + +UPDATE `creature_template` SET `FactionAlliance` = 16, `FactionHorde` = 16 WHERE `entry` = 29364; +UPDATE `creature_template` SET `FactionAlliance` = 16, `FactionHorde` = 16 WHERE `entry` = 31518; +UPDATE `creature_template` SET `AIName`='' WHERE `entry` IN (29395); + +-- triggers +UPDATE `creature_template` SET ExtraFlags = ExtraFlags | 128 WHERE entry IN (30857,30883,29326,30896); + +DELETE FROM `spell_script_target` WHERE entry = 59474; +INSERT IGNORE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(59474, 1, 31511); + +-- immune masks (charm, fear, root, silence, sleep, snare, stun, freeze, knockout, polymorph, banish, shackle, horror, sapped) +UPDATE `creature_template` SET MechanicImmuneMask = MechanicImmuneMask |1|16|64|256|512|1024|2048|4096|8192|65536|131072|524288|8388608|536870912 +WHERE `entry` IN (29315,29395,29316,29313,29321,29266,29271,29312,29314,31134,31511,31514,31509,31508,31512,31507,31510,31515,31513,31506); diff --git a/sql_mr/mr00001_mangos_trial_of_the_champion.sql b/sql_mr/mr00001_mangos_trial_of_the_champion.sql new file mode 100644 index 0000000000..68154fb12a --- /dev/null +++ b/sql_mr/mr00001_mangos_trial_of_the_champion.sql @@ -0,0 +1,27 @@ +-- instance +UPDATE instance_template SET ScriptName = 'instance_trial_of_the_champion' WHERE map = 650; + +-- announcers +UPDATE `creature_template` SET `ScriptName` = 'npc_toc5_announcer' WHERE `entry` IN (35004, 35005); + +-- grand champions +UPDATE creature_template SET `ScriptName` = 'mob_toc5_warrior' WHERE entry IN (34705, 35572); +UPDATE creature_template SET `ScriptName` = 'mob_toc5_mage' WHERE entry IN (34702, 35569); +UPDATE creature_template SET `ScriptName` = 'mob_toc5_shaman' WHERE entry IN (34701, 35571); +UPDATE creature_template SET `ScriptName` = 'mob_toc5_hunter' WHERE entry IN (34657, 35570); +UPDATE creature_template SET `ScriptName` = 'mob_toc5_rogue' WHERE entry IN (34703, 35617); + +-- argent challenge +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` = 'mob_toc5_memory' WHERE entry IN (35052, 35041, 35033, 35046, 35043, 35047, 35044, 35039, 35034, 35049, 35030, 34942, 35050, 35042, 35045, 35037, 35031, 35038, 35029, 35048, 35032, 35028, 35040, 35036, 35051); + +-- black knight +UPDATE creature_template SET `ScriptName` = 'mob_toc5_risen_ghoul' WHERE `entry` IN (35545, 35564); +UPDATE creature_template SET `ScriptName` = 'boss_black_knight' WHERE entry = 35451; + +-- free spells for creatures +DELETE FROM `creature_template_spells` WHERE `entry` IN +(34705,34702,34701,34657,34703,35572,35569,35571,35570,35617,35119,34928,35451,35545,35564,35004,35005,35052,35041,35033,35046,35043,35047,35044,35039,35034,35049,35030,34942,35050,35042,35045,35037,35031,35038,35029,35048,35032,35028,35040,35036,35051); +DELETE FROM `creature_template_spells` WHERE `entry` IN +(12002,12001,12000,12003,12004,12010,12484,12485,12447,12454,12441,12438,12453,12443,12437,12445,12725,12452,12486,12442,12482,12440,12483,12451,12456,12449,12455,12450,12487,12446,12011,12012,12436,12005,12007,12006,12009,12008); diff --git a/sql_mr/mr00001_scriptdev2_arena_honor.sql b/sql_mr/mr00001_scriptdev2_arena_honor.sql new file mode 100644 index 0000000000..7bb2a4afd6 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_arena_honor.sql @@ -0,0 +1,14 @@ +-- npc arena-honor exchange + +DELETE FROM script_texts WHERE entry in (-1001007, -1001008); +INSERT INTO script_texts (entry,content_loc8, content_default, sound, type, language, emote, comment) VALUES +('-1001007','Недостаточно ХонорПойнтов!','Your not has enough HonorPoints!','0','0','0','0','Unsuccesfull - honorpoint.'), +('-1001008','Недостаточно АренаПойнтов!','Your not has enough AranaPoints!','0','0','0','0','Unsuccesfull - arenapoint.'); + +-- Gossips +DELETE FROM `gossip_texts` WHERE `entry` BETWEEN -3000773 AND -3000770; +INSERT INTO `gossip_texts` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`, `comment`) VALUES +('-3000770', "Exchange 100 ArenaPoints to 2000 HonorPoints", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Обменять 100 АренаПойнтов на 2000 ХонорПойнтов", "npc_arena_honor gossip 1"), +('-3000771', "Exchange 1000 ArenaPoints to 20000 HonorPoints", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Обменять 1000 АренаПойнтов на 20000 ХонорПойнтов", "npc_arena_honor gossip 2"), +('-3000772', "Exchange 1000 HonorPoints to 50 ArenaPoints", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Обменять 1000 ХонорПойнтов на 50 АренаПойнтов", "npc_arena_honor gossip 3"), +('-3000773', "Exchange 10000 HonorPoints to 500 ArenaPoints", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Обменять 10000 ХонорПойнтов на 500 АренаПойнтов", "npc_arena_honor gossip 4"); diff --git a/sql_mr/mr00001_scriptdev2_draktharon.sql b/sql_mr/mr00001_scriptdev2_draktharon.sql new file mode 100644 index 0000000000..3b293c6a27 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_draktharon.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry in (-1600020, -1600021); +INSERT INTO script_texts (`entry`,`content_default`,`sound`,`type`,`language`,`comment`) values +(-1600020,'King Dred raises his talon menacingly!',0,5,0,'King Dred Talon'), +(-1600021,'King Dred calls for a raptor!',0,5,0,'King Dred Call for Raptor'); diff --git a/sql_mr/mr00001_scriptdev2_fishing_extravaganza.sql b/sql_mr/mr00001_scriptdev2_fishing_extravaganza.sql new file mode 100644 index 0000000000..a033054e44 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_fishing_extravaganza.sql @@ -0,0 +1,6 @@ +-- add ai text for riggle +DELETE FROM `script_texts` WHERE `entry` IN (-1510356,-1510357,-1510358); +INSERT INTO `script_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`emote`,`comment`) VALUES +(-1510356, 'Let the Fishing Tournament BEGIN!', 0, 6, 0, 0, 'riggle SAY_START'), +(-1510357, 'We have a winner! $N is the Master Angler!', 0, 6, 0, 0, 'riggle SAY_WINNER'), +(-1510358, 'And the Tastyfish have gone for the week! I will remain for another hour to allow you to turn in your fish!', 0, 6, 0, 0, 'riggle SAY_END'); diff --git a/sql_mr/mr00001_scriptdev2_obsidian_sanctum.sql b/sql_mr/mr00001_scriptdev2_obsidian_sanctum.sql new file mode 100644 index 0000000000..474bf40ef1 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_obsidian_sanctum.sql @@ -0,0 +1,47 @@ +-- Execute only if you want ruRu locales. The following should be converted to UPDATES +/*DELETE FROM `script_texts` WHERE `entry` BETWEEN -1615042 AND -1615000; +INSERT INTO `script_texts` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`, `sound`, `type`, `language`, `emote`, `comment`) VALUES +(-1615042, '%s begins to open a Twilight Portal!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '%s начинает открывать Врата Сумерек!', 0, 5, 0, 0, 'sartharion drake WHISPER_OPEN_PORTAL'), +(-1615041, 'A Vesperon Disciple appears in the Twilight!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Ученик Весперон появляется в Сумерках!', 0, 5, 0, 0, 'shadron WHISPER_VESPERON_DICIPLE'), +(-1615040, 'Unlike, I have many talents.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'В отличии от вас, я кое что умею.', 14138, 1, 0, 0, 'vesperon SAY_VESPERON_SPECIAL_2'), +(-1615039, 'Aren''t you tricky...I have a few tricks of my own...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'С вами не просто... Но и со мной не легко...', 14137, 1, 0, 0, 'vesperon SAY_VESPERON_SPECIAL_1'), +(-1615038, 'Father was right about you, Sartharion...You are a weakling!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Отец был прав насчет тебя, Сртарион... Ты слаб!', 14139, 1, 0, 0, 'vesperon SAY_VESPERON_RESPOND'), +(-1615037, 'I will pick my teeth with your bones!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я буду ковыряться в зубах вашими костями!', 14136, 1, 0, 0, 'vesperon SAY_VESPERON_BREATH'), +(-1615036, 'I still have some...fight..in...me...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я все еще... могу... драться...', 14140, 1, 0, 0, 'vesperon SAY_VESPERON_DEATH'), +(-1615035, 'Was that the best you can do?', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'И это все, что ты можешь сделать?', 14135, 1, 0, 0, 'vesperon SAY_VESPERON_SLAY_2'), +(-1615034, 'The least you could do is put up a fight...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Все, что тебе удалось, это затеять драку...', 14134, 1, 0, 0, 'vesperon SAY_VESPERON_SLAY_1'), +(-1615033, 'You pose no threat, lesser beings...give me your worst!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вы безобидны, ничтожные создания... покажите мне, на что вы способны!', 14133, 1, 0, 0, 'vesperon SAY_VESPERON_AGGRO'), +(-1615032, 'The lava surrounding %s churns!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Потомство Весперона появляется в Сумерках!', 0, 5, 0, 0, 'sartharion WHISPER_LAVA_CHURN'), +(-1615031, 'This is why we call you lesser beeings.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вот поэтому мы и называем вас низшими созданиями.', 14097, 1, 0, 0, 'sartharion SAY_SARTHARION_SLAY_3'), +(-1615030, 'You are the grave disadvantage.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Тебе смертельно не повезло.', 14096, 1, 0, 0, 'sartharion SAY_SARTHARION_SLAY_2'), +(-1615029, 'You will make a fine meal for the hatchlings.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Из тебя выйдет хорошая закуска для детенышей.', 14094, 1, 0, 0, 'sartharion SAY_SARTHARION_SLAY_1'), +(-1615028, 'All will be reduced to ash!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'От вас останется всего лишь горстка пепла!', 14102, 1, 0, 0, 'sartharion SAY_SARTHARION_SPECIAL_4'), +(-1615027, 'How much heat can you take?', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Посмотрим, как вы переносите жару!', 14101, 1, 0, 0, 'sartharion SAY_SARTHARION_SPECIAL_3'), +(-1615026, 'Your charred bones will litter the floor!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Ваши обугленные кости завалят весь пол!', 14100, 1, 0, 0, 'sartharion SAY_SARTHARION_SPECIAL_2'), +(-1615025, 'Such flammable little insects....', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Мелкая мошка хорошо горит...', 14099, 1, 0, 0, 'sartharion SAY_SARTHARION_SPECIAL_1'), +(-1615024, 'Such is the price... of failure...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Такова цена... неудачи...', 14107, 1, 0, 0, 'sartharion SAY_SARTHARION_DEATH'), +(-1615023, 'Vesperon! The clutch is in danger! Assist me!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Весперон! Кладка в опасности! Помоги мне!', 14104, 1, 0, 0, 'sartharion SAY_SARTHARION_CALL_VESPERON'), +(-1615022, 'Tenebron! The eggs are yours to protect as well!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Тенеброн! Ты тоже должна защищать яйца!', 14106, 1, 0, 0, 'sartharion SAY_SARTHARION_CALL_TENEBRON'), +(-1615021, 'Shadron! Come to me, all is at risk!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Шадрон! На помощь! Все на кону!', 14105, 1, 0, 0, 'sartharion SARTHARION_CALL_SHADRON'), +(-1615020, 'Burn, you miserable wretches!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Гори, злосчастный сброд!', 14098, 1, 0, 0, 'sartharion SAY_SARTHARION_BREATH'), +(-1615019, 'This pathetic siege ends NOW!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Это смехотворное сражение закончиться СЕЙЧАС ЖЕ!', 14103, 1, 0, 0, 'sartharion SAY_SARTHARION_BERSERK'), +(-1615018, 'It is my charge to watch over these eggs. I will see you burn before any harm comes to them!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Моя обязанность - оберегать эти яйца. И вы сгорите прежде, чем хоть пальцем дотронетесь их.', 14093, 1, 0, 0, 'sartharion SAY_SARTHARION_AGGRO'), +(-1615017, '%s begins to hatch eggs in the twilight!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '%s начинает высиживать яйца в сумерках!', 0, 5, 0, 0, 'tenebron WHISPER_HATCH_EGGS'), +(-1615016, 'I am no mere dragon! You will find I am much, much, more...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я не простой дракон! Увидите, совсем, совсем, не простой...', 14127, 1, 0, 0, 'tenebron SAY_TENEBRON_SPECIAL_2'), +(-1615015, 'Arrogant little creatures! To challenge powers you do not yet understand...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Самонадеянные мелкие твари! Вы бросаете вызов силам, от понимания которых, вы еще далеки!', 14126, 1, 0, 0, 'tenebron SAY_TENEBRON_SPECIAL_1'), +(-1615014, 'It is amusing to watch you struggle. Very well, witness how it is done.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Занятно наблюдать, как ты сражаешься. Хорошо, смотри, как надо это делать.', 14128, 1, 0, 0, 'tenebron SAY_TENEBRON_RESPOND'), +(-1615013, 'To darkness I condemn you...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Приговариваю вас к тьме...', 14125, 1, 0, 0, 'tenebron SAY_TENEBRON_BREATH'), +(-1615012, 'I should not... have held back...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Не надо было... вмешиваться...', 14129, 1, 0, 0, 'tenebron SAY_TENEBRON_DEATH'), +(-1615011, 'Typical... Just as I was having fun.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Как обычно... Только я вошла во вкус.', 14124, 1, 0, 0, 'tenebron SAY_TENEBRON_SLAY_2'), +(-1615010, 'No contest.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Не интересно.', 14123, 1, 0, 0, 'tenebron SAY_TENEBRON_SLAY_1'), +(-1615009, 'You have no place here. Your place is among the departed.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вам здесь не место. Ваше место - среди усопших.', 14122, 1, 0, 0, 'tenebron SAY_TENEBRON_AGGRO'), +(-1615008, 'A Shadron Disciple appears in the Twilight!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Ученик Шадрон появляется в Сумерках!', 0, 5, 0, 0, 'shadron WHISPER_SHADRON_DICIPLE'), +(-1615007, 'On your knees!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'На колени!', 14116, 1, 0, 0, 'shadron SAY_SHADRON_SPECIAL_2'), +(-1615006, 'Father tought me well!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Отец не зря учил меня!', 14115, 1, 0, 0, 'shadron SAY_SHADRON_SPECIAL_1'), +(-1615005, 'I will take pity on you Sartharion, just this once.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я пожалею тебя Сартарион, но только в этот раз.', 14117, 1, 0, 0, 'shadron SAY_SHADRON_RESPOND'), +(-1615004, 'You are easily bested! ', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вас легко провести!', 14114, 1, 0, 0, 'shadron SAY_SHADRON_BREATH'), +(-1615003, 'We...are superior! How could this...be...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Мы... выше всех! Как это... возможно...', 14118, 1, 0, 0, 'shadron SAY_SHADRON_DEATH'), +(-1615002, 'Such mediocre resistance!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Какое слабое сопротивление!', 14113, 1, 0, 0, 'shadron SAY_SHADRON_SLAY_2'), +(-1615001, 'You are insignificant!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Ты ничтожество!', 14112, 1, 0, 0, 'shadron SAY_SHADRON_SLAY_1'), +(-1615000, 'I fear nothing! Least of all you!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я не боюсь ничего! Тем более вас!', 14111, 1, 0, 0, 'shadron SAY_SHADRON_AGGRO'); +*/ \ No newline at end of file diff --git a/sql_mr/mr00001_scriptdev2_oculus.sql b/sql_mr/mr00001_scriptdev2_oculus.sql new file mode 100644 index 0000000000..3372d54bf6 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_oculus.sql @@ -0,0 +1,65 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1578043 AND -1578031; +INSERT INTO script_texts (entry,content_default, content_loc8, sound, type, language, emote, comment) VALUES +-- Drakos the Interrogator +(-1578031,'The prisoners shall not go free. The word of Malygos is law!','Узники не вырвутся на волю. Слово Малигоса - закон!',13594,1,0,0,'SAY_AGGRO'), +(-1578032,'A fitting punishment!','Заслуженное наказание!',13602,1,0,0,'SAY_KILL_1'), +(-1578033,'Sentence: executed!','Приговор приведен в исполнение!',13603,1,0,0,'SAY_KILL_2'), +(-1578034,'Another casualty of war!','Еще одна жертва войны!',13604,1,0,0,'SAY_KILL_3'), +(-1578035,'The war... goes on.','Война... продолжается.',13605,1,0,0,'SAY_DEATH'), +(-1578036,'It is too late to run!','Поздно убегать!',13598,1,0,0,'SAY_PULL_1'), +(-1578037,'Gather \'round!','Станьте в круг!',13599,1,0,0,'SAY_PULL_2'), +(-1578038,'None shall escape!','Не кто не уйдет живым!',13600,1,0,0,'SAY_PULL_3'), +(-1578039,'I condemn you to death!','Я приговариваю вас к смерти!',13601,1,0,0,'SAY_PULL_4'), +(-1578040,'Tremble, worms!','Трепещите, черви!',13595,1,0,0,'SAY_STOMP_1'), +(-1578041,'I will crush you!','Я раздавлю вас!',13596,1,0,0,'SAY_STOMP_2'), +(-1578042,'Can you fly?','Вы умеете летать?',13597,1,0,0,'SAY_STOMP_3'), +(-1578043,'Intruders, your victory will be short-lived. I am Commander Varos Cloudstrider. My drakes control the skies and protest this conduit. I will see to it personally that the Oculus does not fall into your hands!','Чужаки, ваш триумф будет не долгим. Я командир Варос Заоблачный странник. Мои драконы обозревают небеса и защищают это место. Я позабочусь, чтобы Окулус не достался вам!',13648,1,0,0,'SAY_VAROS_SPAWN'); + +-- The following script_text are not removed to keep ruRU locales. If someone is interested in, convert the following to updates for base_scriptdev2_full.sql. From -1578000 to ... +/*-- From Lanc (originally from TC) +REPLACE into `script_texts` (entry, content_default, content_loc8, sound, type, language, emote, comment) VALUES +-- Drakos the Interrogator +(-1578000,'The prisoners shall not go free. The word of Malygos is law!','Узники не вырвутся на волю. Слово Малигоса - закон!',13594,1,0,0,'SAY_AGGRO'), +(-1578001,'A fitting punishment!','Заслуженное наказание!',13602,1,0,0,'SAY_KILL_1'), +(-1578002,'Sentence: executed!','Приговор приведен в исполнение!',13603,1,0,0,'SAY_KILL_2'), +(-1578003,'Another casualty of war!','Еще одна жертва войны!',13604,1,0,0,'SAY_KILL_3'), +(-1578004,'The war... goes on.','Война... продолжается.',13605,1,0,0,'SAY_DEATH'), +(-1578005,'It is too late to run!','Поздно убегать!',13598,1,0,0,'SAY_PULL_1'), +(-1578006,'Gather \'round!','Станьте в круг!',13599,1,0,0,'SAY_PULL_2'), +(-1578007,'None shall escape!','Не кто не уйдет живым!',13600,1,0,0,'SAY_PULL_3'), +(-1578008,'I condemn you to death!','Я приговариваю вас к смерти!',13601,1,0,0,'SAY_PULL_4'), +(-1578009,'Tremble, worms!','Трепещите, черви!',13595,1,0,0,'SAY_STOMP_1'), +(-1578010,'I will crush you!','Я раздавлю вас!',13596,1,0,0,'SAY_STOMP_2'), +(-1578011,'Can you fly?','Вы умеете летать?',13597,1,0,0,'SAY_STOMP_3'), +-- Urom +(-1578012,'Poor blind fools!','Несчастные слепые глупцы!',13638,1,0,0,'SAY_AGGRO'), +(-1578013,'If only you understood!','Если бы вы только могли понять!',13641,1,0,0,'SAY_KILL_1'), +(-1578014,'Now do you see? Do you?!','Ну что, теперь тебе понятно? Или нет?!',13642,1,0,0,'SAY_KILL_2'), +(-1578015,'Unfortunate, but necessary.','Сожелею, это было необходимо.',13643,1,0,0,'SAY_KILL_3'), +(-1578016,'Everything I\'ve done... has been for Azeroth...','Все что я делал... было во имя Азерота...',13644,1,0,0,'SAY_DEATH'), +(-1578017,'A taste... just a small taste... of the Spell-Weaver\'s power!','Тень... лиш бледная тень... подленного могущества Хранителя магии!',13639,1,0,0,'SAY_EXPLOSION_1'), +(-1578018,'So much unstable energy... but worth the risk to destroy you!','Много неустойчивой энергии... но чтобы уничтожить вас, я готов рискнуть!',13640,1,0,0,'SAY_EXPLOSION_2'), +(-1578019,'What do we have here... those would defy the Spell-Weaver? Those without foresight or understanding. How could I make you see? Malygos is saving the world from itself! Bah! You are hardly worth my time!','Так, что у нас тут... ааа вы пришли сразится с Хранителем магии? Это вы то лишенные предвидиния и понимания. Как мне заставить вас прозреть? Малигос спасает мир от самого мира! Эх! На вас жаль тратить время!',13635,1,0,0,'SAY_SUMMON_1'), +(-1578020,'Clearly my pets failed. Perhaps another demonstration is in order.','Моих слуг постигла неудача. Возможно потребуется еще одно предупреждение.',13636,1,0,0,'SAY_SUMMON_2'), +(-1578021,'Still you fight. Still you cling to misguided principles. If you survive, you\'ll find me in the center ring.','Вы все еще сражаетесь. Все еще цепляетесь за свои ложные убеждения. Если выживите, встретимся в центральном кругу.',13637,1,0,0,'SAY_SUMMON_3'), +-- Varos +(-1578022,'There will be no mercy!','Пощады не будет!',13649,1,0,0,'SAY_AGGRO'), +(-1578023,'Oculus ours!','Окулус наш!',13654,1,0,0,'SAY_KILL_1'), +(-1578024,'I warned you!','Тебя предупреждали!',13653,1,0,0,'SAY_KILL_2'), +(-1578025,'They are... too strong! Underestimated their... fortitude.','Они... слишком сильны! Я недооценил... их мужество.',13655,1,0,0,'SAY_DEATH'), +(-1578026,'Blast them! Destroy them!','Взорвать их! Изничтожить!',13650,1,0,0,'SAY_STRIKE_1'), +(-1578027,'Take no prisoners! Attack!','Пленных не брать! В Атаку!',13651,1,0,0,'SAY_STRIKE_2'), +(-1578028,'Strike now! Obliterate them!','Нанесите удар! Уничтожте их!',13652,1,0,0,'SAY_STRIKE_3'), +(-1578029,'Intruders, your victory will be short-lived. I am Commander Varos Cloudstrider. My drakes control the skies and protest this conduit. I will see to it personally that the Oculus does not fall into your hands!','Чужаки, ваш триумф будет не долгим. Я командир Варос Заоблачный странник. Мои драконы обозревают небеса и защищают это место. Я позабочусь, чтобы Окулус не достался вам!',13648,1,0,0,'SAY_VAROS_SPAWN'), +-- Eregos +(-1578030,'You brash interlopers are out of your element! I will ground you!','Нахальные невежды, вы все в небесах летаете! Сейчас я вас заземлю!',13623,1,0,0,'SAY_AGGRO'), +(-1578031,'It\'s a long way down...','Как больно падать...',13628,1,0,0,'SAY_KILL_1'), +(-1578032,'Back to the earth with you!','Вернемся на землю!',13629,1,0,0,'SAY_KILL_2'), +(-1578033,'Enjoy the fall!','Наслаждайся полетом!',13630,1,0,0,'SAY_KILL_3'), +(-1578034,'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,'SAY_DEATH'), +(-1578035,'We command the arcane! It shall not be used against us.','Мы повелеваем тайной магией! Она не будет использована против нас.',13626,1,0,0,'SAY_ARCANE_SHIELD'), +(-1578036,'It is trivial to extinguish your fire!','Как легко погасить ваш огонь!',13627,1,0,0,'SAY_FIRE_SHIELD'), +(-1578037,'No magic of nature will help you now!','Никакая магия природы теперь вас не спасет!',13625,1,0,0,'SAY_NATURE_SHIELD'), +(-1578038,'Such insolence... such arrogance... must be PUNISHED!','Какая заносчивость... какая чандливость... вы заслуживаете КАРЫ!',13624,1,0,0,'SAY_FRENZY'), +(-1578039,'Simpletons! You cannot comprehend the forces you have set in motion. The ley line conduit will not be disrupted! Your defeat shall be absolute!','Простаки! Вам и неведомо какие силы вы привели в действие. Поток энергии не прервется! Вас ждет полный разгром!',13622,1,0,0,'SAY_SPAWN'); +*/ \ No newline at end of file diff --git a/sql_mr/mr00001_scriptdev2_ruby_sanctum.sql b/sql_mr/mr00001_scriptdev2_ruby_sanctum.sql new file mode 100644 index 0000000000..4302648da8 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_ruby_sanctum.sql @@ -0,0 +1,56 @@ + +-- The following queries are INCORRECT. Must create UPDATES with ruRU locales and insert in base_scriptdev2_full entries of Ruby Sanctum +/* +-- sound / text +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1666405 AND -1666000; +-- xerestrasza +INSERT INTO `script_texts` (`entry`, `content_default`, `content_loc8`, `sound`, `type`, `language`, `emote`, `comment`) VALUES +('-1666000','Help! I am trapped within this tree! I require aid!','Спасите! Я под этим деревом. Мне нужна помощь!','17490','6','0','0','SAY_XERESTRASZA_YELL_1'), +('-1666001','Thank you! I could have not held out for much longer. A terrible thing has happened here.','Спасибо! Без вас я бы долго не продержалась... Здесь произошли страшные события...','17491','0','0','0','SAY_XERESTRASZA_YELL_2'), +('-1666002','We believed that the Sanctum was well fortified, but we were not prepareted for the nature of this assault.','Святилище считалось неприступным, но до сих пор оно не подвергалось такому штурму...','17492','0','0','0','SAY_XERESTRASZA_SAY_1'), +('-1666003','The Black Dragonkin materialized from thin air, and set upon us before we could react.','Черные драконы явились из ниоткуда. Мы даже не успели понять что происходит...','17493','0','0','0','SAY_XERESTRASZA_SAY_2'), +('-1666004','We did not stand a chance. As my brethren perished around me, I managed to retreat hear and bar the entrance.','Силы были неравны, мои братья гибли один за другим. А я спряталась здесь и запечатала вход.','17494','0','0','0','SAY_XERESTRASZA_SAY_3'), +('-1666005','They slaughtered us with cold efficiency, but the true focus of their interest seemed to be the eggs kept here in the sanctum.','Нас убивали с расчетливой жестокостью, но основной целью врага была кладка яиц в святилище.','17495','0','0','0','SAY_XERESTRASZA_SAY_4'), +('-1666006','The commander of the forces on the ground here is a cruel brute named Zarithrian. But I fear there are greater powers at work.',' Атакой руководил кровожадный Заритриан, но, боюсь, тут замешано и более могущественное зло.','17496','0','0','0','SAY_XERESTRASZA_SAY_5'), +('-1666007','In their initial assault I caught a glimpse of their true leader, a fearsome full-grown Twilight Dragon.','В самом начале я ощутила присутствие их настоящего лидера - огромного сумеречного дракона.','17497','0','0','0','SAY_XERESTRASZA_SAY_6'), +('-1666008','I know not the extent of their plans heroes, but I know this: they cannot be allowed to succeed!','Герои, я не знаю чего добиваются эти захватчики. Одно я знаю точно - их нужно остановить!','17498','0','0','0','SAY_XERESTRASZA_SAY_7'), + +-- Halion +('-1666100','Meddlesome insects, you\'re too late! The Ruby Sanctum is lost.','Назойливая мошкара! Вы опоздали. Рубиновое святилище пало!','17499','6','0','0','SAY_HALION_SPAWN'), +('-1666101','Your world teeters on the brink of annihilation. You will all bear witness to the coming of a new age of destruction!','Этот мир вот-вот соскользнет в бездну. Вам выпала честь узреть начало эры РАЗРУШЕНИЯ!','17500','6','0','0','SAY_HALION_AGGRO'), +('-1666102','Another hero falls.','Сколько еще таких героев?','17501','6','0','0','SAY_HALION_SLAY_1'), +('-1666103','Ha Ha Ha!','','17502','6','0','0','SAY_HALION_SLAY_2'), +('-1666104','Relish this victory mortals, for it will be your last. This world will burn with the Master\'s return!','Это ваша последняя победа. Насладитесь сполна ее вкусом. Ибо когда вернется мой господин, этот мир сгинет в огне!','17503','6','0','0','SAY_HALION_DEATH'), +('-1666105','Not good enough!','Надоело!','17504','6','0','0','SAY_HALION_BERSERK'), +('-1666106','The heavens burn!','Небеса в огне!','17505','6','0','0','SAY_HALION_SPECIAL_1'), +('-1666107','Beware the shadow!','','17506','6','0','0','SAY_HALION_SPECIAL_2'), +('-1666108','You will find only suffering within the realm of Twilight. Enter if you dare.','Вы найдете только тьму в мире Сумерек. Входите, если посмеете.','17507','6','0','0','SAY_HALION_PHASE_2'), +('-1666109','I am the light AND the darkness! Cower mortals before the Herald of Deathwing!','Я есть свет и я есть тьма! Трепещите, ничтожные, перед посланником Смертокрыла!','17508','6','0','0','SAY_HALION_PHASE_3'), +('-1666110','The orbining spheres pulse with dark energy!','Во вращающихся сферах пульсирует темная энергия!','0','3','0','0',''), +('-1666111','Your companions\' effort force Halion further into the physical realm!','Ваши союзники протолкнули Халиона дальше в физический мир!','0','3','0','0',''), +('-1666112','Your companions\' effort force Halion further into the twilight realm!','Ваши союзники протолкнули Халиона дальше в реальный мир!','0','3','0','0',''), +('-1666113','Находясь в покое в одном из миров, Халион восстанавливает жизненные силы.','Находясь в покое в одном из миров, Халион восстанавливает жизненные силы.','0','3','0','0',''), + +-- Zarthrian +('-1666200','Alexstrasza has chosen capable allies. A pity that I must end you!','Алекстраза выбрала достойных союзников... Жаль, что придется ПРИКОНЧИТЬ ВАС!','17512','6','0','0','SAY_ZARITHRIAN_AGGRO'), +('-1666201','You thought you stood a chance?','Глупо было и надеяться!','17513','6','0','0','SAY_ZARITHRIAN_SLAY_1'), +('-1666202','It\'s for the best.','Все только к лучшему!','17514','6','0','0','SAY_ZARITHRIAN_SLAY_2'), +('-1666203','Halion! I\'m...aah!','ХАЛИОН! Я...','17515','6','0','0','SAY_ZARITHRIAN_DEATH'), +('-1666204','Turn them to ash, minions!','Слуги! Обратите их в пепел!','17516','6','0','0','SAY_ZARITHRIAN_SPECIAL_1'), + +-- baltharus +('-1666300','Ah, the entertainment has arrived...','А-а-а, цирк приехал.','17520','6','0','0','SAY_BALTHARUS_AGGRO'), +('-1666301','Baltharus leaves no survivors!','Балтар не оставляет живых!','17521','6','0','0','SAY_BALTHARUS_SLAY_1'), +('-1666302','This world has enough heroes!','В мире хватает героев и без тебя...','17522','6','0','0','SAY_BALTHARUS_SLAY_2'), +('-1666303','I...didn\'t see that coming...','Как… это могло произойти?..','17523','1','0','0','SAY_BALTHARUS_DEATH'), +('-1666304','Twice the pain and half the fun!','Вдвое сильнее страдание.','17524','6','0','0','SAY_BALTHARUS_SPECIAL_1'), +('-1666305','Your power wanes, ancient one! Soon, you will join your friends!','Твоя сила на исходе, Древнейшая! Скоро ты присоединишься к своим друзьям!','17525','6','0','0','SAY_BALTHARUS_YELL'), + +-- saviana +('-1666400','You will suffer for this intrusion...','Ваш-ш-ши муки с-cтанут платой за это вторжение!','17528','6','0','0','SAY_SAVIANA_AGGRO'), +('-1666401','As it should be!','Так и должно быть!','17529','6','0','0','SAY_SAVIANA_SLAY_1'), +('-1666402','Halion will be pleased...','Халион будет доволен!','17530','6','0','0','SAY_SAVIANA_SLAY_2'), +('-1666403','','О...','17531','6','0','0','SAY_SAVIANA_DEATH'), +('-1666404','Burn in the master\'s flame!','Горите в огне хозяина!','17532','6','0','0','SAY_SAVIANA_SPECIAL_1'), +('-1666405','','|3-3(%s) впадает в исступление!','0','3','0','0',''); +*/ \ No newline at end of file diff --git a/sql_mr/mr00001_scriptdev2_trial_of_crusader.sql b/sql_mr/mr00001_scriptdev2_trial_of_crusader.sql new file mode 100644 index 0000000000..e61c02ef50 --- /dev/null +++ b/sql_mr/mr00001_scriptdev2_trial_of_crusader.sql @@ -0,0 +1,554 @@ +-- TOC original texts/sounds (thanks to griffonheart) +-- english translation by Cristy +-- reworked by rsa + +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1649085 AND -1649076; +INSERT INTO `script_texts` (`comment`,`sound`, `entry`,`content_loc8`,`type`,`language`,`emote`,`content_default`) VALUES +-- Northrend beast emotes +('34796','0','-1649076','Мои рабы! Уничтожьте врага!','3','0','0','My slaves! Destroy the enemy!'), +('34799','0','-1649077','После гибели товарища %s приходит в ярость!','3','0','0','After the death of sister %s goes berserk!'), +('34797','0','-1649078','%s глядит на |3-3($n) и испускает гортанный вой!','3','0','0','%S looks at |3-3($n) and emits a guttural howl!'), +('34797','0','-1649079','%s врезается в стену Колизея и теряет ориентацию!','3','0','0','%S crashes into a wall of the Colosseum and lose focus!'), +-- Jaraxxus +('34780','0','-1649080','%s создает |cFF00FF00Вулкан инферналов!|r','3','0','0','%S creates |cFF00FF00Vulkan Infernals!|R'), +('34780','0','-1649081','%s создает врата Пустоты!','3','0','0','%S creates the gates of the Void!'), +('34780','0','-1649082','$n $gподвергся:подверглась; |cFF00FFFFИспепелению плоти!|r Исцелите $gего:ее;!','3','0','0','$N $gpodvergsya:been; |cFF00FFFFIspepeleniyu flesh!|R Heal $gego:it;!'), -- EMOTE_INCINERATE_FLESH +-- Twin Valkyr +('34497','0','-1649083','%s начинает читать заклинание|cFFFFFFFFСветлая воронка!|r Переключение к |cFFFFFFFFСветлой|r сущности!','3','0','0','%S begins to read a spell |cFFFFFFFFSvetlaya funnel!|R switch to |cFFFFFFFFSvetloy|r essence!'), +('34497','0','-1649084','%s начинает читать заклинание Договор близнецов!','3','0','0','%S begins to read the spell Treaty twins!'), +('34496','0','-1649085','%s начинает читать заклинание |cFF9932CDТемная воронка!|r Переключение к |cFF9932CDТемной|r сущности!','3','0','0','%S begins to read a spell |cFF9932CDTemnaya funnel!|R switch to |cFF9932CDTemnoy|r essence!'); + +-- The following queries are now deprecated. Must be converted to UPDATES to save ruRU locale info, but using scriptdev2 script_texts ids. +/* +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1713799 AND -1713499; +INSERT INTO `script_texts` +(`comment`,`sound`, `entry`,`content_loc8`,`type`,`language`,`emote`,`content_default`) VALUES +('34996','16036','-1713500','Добро пожаловать, герои! Вы услышали призыв Серебряного Авангарда и без колебаний откликнулись на него! В этом колизее вам предстоит сразиться с опаснейшими противниками. Те из вас, кто смогут пережить испытания, войдут в ряды Серебряного Авангарда, который направится в Цитадель Ледяной Короны.','6','0','0','Welcome champions, you have heard the call of the argent crusade and you have boldly answered. It is here in the crusaders coliseum that you will face your greatest challenges. Those of you who survive the rigors of the coliseum will join the Argent Crusade on its marsh to ice crown citadel.'), +('34996','16038','-1713501','Из самых глубоких и темных пещер Грозовой Гряды был призван Гормок Пронзающий Бивень! В бой, герои!','6','0','0','Hailing from the deepest, darkest carverns of the storm peaks, Gormok the Impaler! Battle on, heroes!'), +('34990','16069','-1713502','Твои чудовища не чета героям Альянса, Тирион!','6','0','0','Your beast will be no match for my champions Tirion!'), +('34995','16026','-1713702','Я видел и более достойных соперников в багровом круге. Ты напрасно тратишь наше время, паладин.','6','0','0','Your beast will be no match for my champions Tirion!'), +('34796','0','-1713601','Мои рабы! Уничтожьте врага!','3','0','0','My slaves! Destroy the enemy!'), +('34996','16039','-1713503','Приготовьтесь к схватке с близнецами-чудовищами, Кислотной Утробой и Жуткой Чешуей!','6','0','0','Steel yourselves, heroes, for the twin terrors Acidmaw and Dreadscale. Enter the arena!'), +('34799','0','-1713504','После гибели товарища %s приходит в ярость!','3','0','0','After the death of sister %s goes berserk!'), +('34996','16040','-1713505','В воздухе повеяло ледяным дыханием следующего бойца: на арену выходит Ледяной Рев! Сражайтесь или погибните, чемпионы!','6','0','0','The air freezes with the introduction of our next combatant, Icehowl! Kill or be killed, champions!'), +('34797','0','-1713506','%s глядит на |3-3($n) и испускает гортанный вой!','3','0','0','%S looks at |3-3($n) and emits a guttural howl!'), +('34797','0','-1713507','%s врезается в стену Колизея и теряет ориентацию!','3','0','0','%S crashes into a wall of the Colosseum and lose focus!'), +('34797','0','-1713508','|3-3(%s) охватывает кипящая ярость, и он растаптывает всех на своем пути!','3','0','0','|3-3(%s) covers boiling rage, and he tramples all in its path!'), +('34996','16041','-1713509','Все чудовища повержены!','6','0','0','All the monsters defeated!'), +('34996','16042','-1713709','Прискорбно. Как яростно они не бились, чудовища Нордскола оказались сильнее. Почтим память павших героев минутой молчания.','6','0','0',''), +('34996','16043','-1713510','Сейчас великий чернокнижник Вилфред Непопамс призовет вашего нового противника. Готовьтесь к бою!','6','0','0','Grand Warlock Wilfred Fizzlebang will summon forth your next challenge. Stand by for his entry!'), +('35458','16268','-1713511','Благодарю, Верховный лорд. А теперь, смельчаки, я приступаю к ритуалу призыва. Когда я закончу, появится грозный демон!','6','0','0','Thank you, Highlord! Now challengers, I will begin the ritual of summoning! When I am done, a fearsome Doomguard will appear!'), +('35458','16269','-1713512','Готовьтесь к забвению!','6','0','0','Prepare for oblivion!'), +('35458','16270','-1713513','АГА! Получилось! Трепещи перед всевластным Вилфредом Непопамсом, мастером призыва! Ты покорен мне, демон!','6','0','0','Ah ha! Behold the absolute power of Wilfred Fizzlebang, master summoner! You are bound to ME, demon!'), +('34780','16143','-1713514','Ничтожный гном! Тебя погубит твоя самоуверенность!','6','0','0','Trifling gnome, your arrogance will be your undoing!'), +('35458','16271','-1713515','Тут я главный!','6','0','0','But I am in charge here-'), +('35458','0','-1713715','Ну вот, опять я облажался...','6','0','0','Agonized Scream!!!'), +('34996','16044','-1713516','Быстрей, герои, расправьтесь с повелителем демонов, прежде чем он откроет портал в свое темное царство!','6','0','0','Quickly, heroes! Destroy the demon lord before it can open a portal to its twisted demonic realm!'), +('34780','16144','-1713517','Перед вами Джараксус, эредарский повелитель Пылающего Легиона!','6','0','0','You face Jaraxxus, eredar lord of the Burning Legion!'), +('34780','0','-1713518','На вас направлено |cFFFF0000Пламя Легиона!|r','3','0','0','You have been sent |cFFFF0000Plamya Legion!|R'), +('34780','0','-1713519','%s создает врата Пустоты!','3','0','0','%S creates the gates of the Void!'), +('34780','0','-1713520','%s создает |cFF00FF00Вулкан инферналов!|r','3','0','0','%S creates |cFF00FF00Vulkan Infernals!|R'), +('34780','16150','-1713521','Явись, сестра! Господин зовет!','6','0','0','Come forth, sister! Your master calls!'), +('34780','0','-1713522','$n $gподвергся:подверглась; |cFF00FFFFИспепелению плоти!|r Исцелите $gего:ее;!','3','0','0','$N $gpodvergsya:been; |cFF00FFFFIspepeleniyu flesh!|R Heal $gego:it;!'), +('34780','16149','-1713523','ПЛОТЬ ОТ КОСТИ!','6','0','0','FLESH FROM BONE!'), +('34780','16151','-1713524','ИНФЕРНАЛ!','6','0','0','INFERNO!'), +('34780','16147','-1713525','Мое место займут другие. Ваш мир обречен...','6','0','0','Another will take my place. Your world is doomed.'), +('34996','16045','-1713526','Гибель Вилфреда Непопамса весьма трагична и должна послужить уроком тем, кто смеет беспечно играть с темной магией. К счастью, вы победили демона, и теперь вас ждет новый противник.','6','0','0','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.'), +('34995','16021','-1713527','Подлые собаки Альянса! Вы выпустили повелителя демонов на воинов Орды? Ваша смерть будет быстрой!','6','0','0','Treacherous Alliance dogs! You summon a demon lord against warriors of the Horde!? Your deaths will be swift!'), +('34990','16064','-1713528','Альянсу не нужна помощь повелителя демонов, чтобы справиться с ордынским отродьем, пес!','6','0','0','The Alliance doesnt need the help of a demon lord to deal with Horde filth. Come, pig!'), +('34996','16046','-1713529','Тише! Успокойтесь! Никакого заговора здесь нет. Чернокнижник заигрался и поплатился за это. Турнир продолжается!','6','0','0','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!'), +('34996','16047','-1713530','В следующем бою вы встретитесь с могучими рыцарями Серебряного Авангарда! Лишь победив их, вы заслужите достойную награду.','6','0','0','The next battle will be against the Argent Crusades most powerful knights! Only by defeating them will you be deemed worthy...'), +('34995','16023','-1713531','Орда требует справедливости! Мы вызываем Альянс на бой! Позволь нам встать на место твоих рыцарей, паладин. Мы покажем этим псам, как оскорблять Орду!','6','0','0','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!'), +('34995','16066','-1713731','Они хотели запятнать честь Альянса, они пытались нас оклеветать! Я требую справедливости! Тириорн, позволь моим чемпионам сражаться вместо твоих рыцарей. Мы бросаем вызов Орде!','6','0','0','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!'), +('34996','16048','-1713532','Хорошо. Да будет так. Сражайтесь с честью!','','0','0','Very well, I will allow it. Fight with honor!'), +('34995','16022','-1713533','Не щадите никого, герои Орды! ЛОК-ТАР ОГАР!','6','0','0','Show them no mercy, Horde champions! LOK-TAR OGAR!'), +('34995','16065','-1713733','Сражайтесь во славу Альянса, герои! Во имя вашего короля!','6','0','0','Fight for the glory of the Alliance, heroes! Honor your king and your people!'), +('34990','16067','-1713534','СЛАВА АЛЬЯНСУ!','6','0','0','GLORY OF THE ALLIANCE!'), +('34990','16024','-1713734','Это было лишь пробой того, что ждёт нас в будущем. За Орду!','6','0','0','LOK-TAR OGAR!'), +('34996','16049','-1713535','Пустая и горькая победа. После сегодняшних потерь мы стали слабее как целое. Кто еще, кроме Короля-лича, выиграет от подобной глупости? Пали великие воины. И ради чего? Истинная опасность еще впереди - нас ждет битва с Королем-личом.','6','0','0','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.'), +('34996','16050','-1713536','Лишь сплотившись, вы сможете пройти последнее испытание. Из глубин Ледяной Короны навстречу вам подымаются две могучие воительницы Плети: жуткие валькирии, крылатые вестницы Короля-лича!','6','0','0','Only by working together will you overcome the final challenge. From the depths of Icecrown come two of the Scourges most powerful lieutenants: fearsome valkyr, winged harbingers of the Lich King!'), +('34996','16037','-1713537','Пусть состязания начнутся!','6','0','0','Let the games begin!'), +('34497','0','-1713538','%s начинает читать заклинание|cFFFFFFFFСветлая воронка!|r Переключение к |cFFFFFFFFСветлой|r сущности!','3','0','0','%S begins to read a spell |cFFFFFFFFSvetlaya funnel!|R switch to |cFFFFFFFFSvetloy|r essence!'), +('34497','0','-1713539','%s начинает читать заклинание Договор близнецов!','3','0','0','%S begins to read the spell Treaty twins!'), +('34496','0','-1713540','%s начинает читать заклинание |cFF9932CDТемная воронка!|r Переключение к |cFF9932CDТемной|r сущности!','3','0','0','%S begins to read a spell |cFF9932CDTemnaya funnel!|R switch to |cFF9932CDTemnoy|r essence!'), +('34497','16272','-1713541','Во имя темного повелителя. Во имя Короля-лича. Вы. Умрете.','6','0','0','In the name of our dark master. For the Lich King. You. Will. Die.'), +('34496','16272','-1713741','Во имя светлого повелителя. Во имя Короля-лича. Вы. Умрете.','6','0','0','In the name of our dark master. For the Lich King. You. Will. Die.'), +('34496','16279','-1713542','Да поглотит вас Свет!','6','0','0','Let the light consume you!'), +('34496','16277','-1713543','Пустое место!','6','0','0','Empty place!'), +('34497','16276','-1713544','Тебя оценили и признали ничтожеством.','6','0','0','You appreciated and acknowledged nothing.'), +('34497','16274','-1713545','ХАОС!','3','0','0','CHAOS!'), +('34496','16278','-1713546','Да поглотит вас Тьма!','6','0','0','Let the dark consume you!'), +('34496','16275','-1713547','Плеть не остановить...','6','0','0','The Scourge cannot be stopped...'), +('34990','16068','-1713548','Против Альянса не выстоять даже самым сильным прислужникам Короля-лича! Все славьте наших героев!','6','0','0','Against the Alliance can not stand even the most powerful henchmen of the Lich King! All glorify our heroes!'), +('34995','16025','-1713748','Ты все еще сомневаешься в могуществе Орды, паладин? Мы примем любой вызов!','6','0','0','Against the Horde does not withstand even the most powerful henchmen of the Lich King! All glorify our heroes!'), +('34996','16051','-1713549','Король-лич понес тяжелую потерю! Вы проявили себя как бесстрашные герои Серебряного Авангарда! Мы вместе нанесем удар по Цитадели Ледяной Короны и разнесем в клочья остатки Плети! Нет такого испытания, которое мы бы не могли пройти сообща!','6','0','0','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!'), +('16980','16321','-1713550','Будет тебе такое испытание, Фордринг.','6','0','0','You will have your challenge, Fordring.'), +('34996','16052','-1713551','Артас! Нас гораздо больше! Сложи Ледяную Скорбь, и я подарю тебе заслуженную смерть.','6','0','0','Arthas! You are hopelessly outnumbered! Lay down Frostmourne and I will grant you a just death.'), +('35877','16322','-1713552','Нерубианцы воздвигли целую империю под льдами Нордскола. Империю, на которой вы так бездумно построили свои дома. МОЮ ИМПЕРИЮ.','6','0','0','The Nerubians built an empire beneath the frozen wastes of Northrend. An empire that you so foolishly built your structures upon. MY EMPIRE.'), +('16980','16323','-1713553','Души твоих павших чемпионов будут принадлежать мне, Фордринг.','6','0','0','The souls of your fallen champions will be mine, Fordring.'), +('34564','16235','-1713554','А вот и гости заявились, как и обещал господин.','6','0','0','Ahhh... Our guests arrived, just as the master promised.'), +('34564','16234','-1713555','Это место станет вашей могилой!','3','0','0','This place will serve as your tomb!'), +('34564','16240','-1713556','Ауум на-л ак-к-к-к, ишшш. Вставайте, слуги мои. Время пожирать...','6','0','0','Auum na-l ak-k-k-k, isshhh. Rise, minions. Devour...'), +('34564','0','-1713557','%s зарывается в землю!','3','0','0','%S buries itself in the earth!'), +('34660','0','-1713558','Шипы %s преследуют $n!','3','0','0','%s spikes pursuing $n!'), +('34564','0','-1713559','%s вылезает на поверхность!','3','0','0','%S getting out of the ground!'), +('34564','16241','-1713560','Стая поглотит вас!','6','0','0','The swarm shall overtake you!'), +('34564','0','-1713561','%s выпускает рой жуков-трупоедов, чтобы восстановить здоровье!','3','0','0','%S produces a swarm of beetles Peon to restore your health!'), +('34564','16236','-1713562','Ф-лаккх шир!','6','0','0','F-lakkh shir!'), +('34564','16237','-1713563','Еще одна душа накормит хозяина.','6','0','0','Another soul to sate the host.'), +('34564','16238','-1713564','Я подвел тебя, господин...','6','0','0','I have failed you, master...'), +('36095','0','-1713565','Чемпионы, вы прошли испытание великого крестоносца! Знайте, что только самые сильные искатели приключений могли рассчитывать завершить это испытание.','6','0','0','Champions, you are alive! Not only have you defeated every challenge of the Trial of the Crusader, but thwarted Arthas directly! Your skill and cunning will prove to be a powerful weapon against the Scourge. Well done! Allow one of my mages to transport you back to the surface!'), +('36095','0','-1713566','Позвольте вручить вам эти сундуки в качестве заслуженной награды, и пусть его содержимое послужит вам верой и правдой в походе против Артаса в самом центре Цитадели Ледяной Короны!','6','0','0','Let me hand you the chests as a reward, and let its contents will serve you faithfully in the campaign against Arthas in the heart of the Icecrown Citadel!'); +*/ + +-- Trial of the crusader spelltable +DELETE FROM `boss_spell_table` WHERE `entry` IN (34496,34497,34564,34605,34607,34780,34784,34796,34797,34799, 34800, 34813, 34815, 34826, 35144, 35176, 34606, 34660); + +-- Eydis Darkbane +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34496, 64238, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34496, 65768, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34496, 65874, 0, 0, 0, 15000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34496, 65876, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34496, 65879, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34496, 65916, 0, 0, 0, 15000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34496, 66058, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34496, 66069, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(34496, 67282, 0, 0, 0, 8000, 0, 6000, 0, 12000, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(34496, 34628, 45000, 45000, 1, 1, 2, 2, 10, 100, 0, 11); + +-- Fjola Lightbane +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34497, 64238, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34497, 65766, 67270, 67271, 67272, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34497, 65858, 0, 0, 0, 15000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34497, 65875, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34497, 65879, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34497, 65916, 0, 0, 0, 15000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34497, 66046, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34497, 66075, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(34497, 67297, 0, 0, 0, 8000, 0, 6000, 0, 0, 12000, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(34497, 34630, 45000, 45000, 1, 1, 2, 2, 10, 100, 0, 11); + +-- AnubArak +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34564, 26662, 26662, 26662, 26662, 600000, 600000, 600000, 600000, 600000, 600000, 600000, 600000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34564, 34605, 0, 0, 0, 90000, 0, 0, 0, 90000, 0, 0, 0, 0, 0, 0, 0, 20.0, 100.0, 0, 0, 0, 0, 9, 1, 0, 0, NULL), +(34564, 34660, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 5.0, 10.0, 0, 0, 0, 0, 9, 1, 0, 0, NULL), +(34564, 34606, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 0, 0, 0, 0, 10.0, 100.0, 0, 0, 0, 0, 9, 1, 0, 0, NULL), +(34564, 34607, 0, 0, 0, 70000, 0, 0, 0, 90000, 0, 0, 0, 0, 0, 0, 0, 20.0, 100.0, 0, 0, 0, 0, 9, 1, 0, 0, NULL), +(34564, 53421, 53421, 53421, 53421, 45000, 45000, 45000, 45000, 60000, 60000, 60000, 60000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, NULL), +(34564, 66169, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34564, 66012, 66012, 66012, 66012, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34564, 66013, 67700, 68509, 68510, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34564, 66339, 66339, 66339, 66339, 5000, 5000, 5000, 5000, 10000, 10000, 10000, 10000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 0, NULL), +(34564, 67574, 0, 0, 0, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 0, NULL), +(34564, 66118, 67630, 68646, 68647, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34564, 66240, 0, 0, 0, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34564, 66125, 0, 0, 0, 10000, 0, 0, 0, 10000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34564, 67730, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL); + +-- Anub'arak scarab +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34605, 66092, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34605, 67861, 0, 0, 0, 5000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL); + +-- Cold sphere +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34606, 66193, 67855, 67856, 67857, 5000, 0, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL); + +-- Anub'arak spike +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34660, 67574, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34660, 66193, 67855, 67856, 67857, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34660, 65920, 65921, 65922, 65923, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Nerubian Borrower +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34607, 66129, 66129, 66129, 66129, 10000, 10000, 10000, 10000, 20000, 20000, 20000, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34607, 67322, 67322, 67322, 67322, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, NULL), +(34607, 67847, 67847, 67847, 67847, 5000, 5000, 5000, 5000, 20000, 20000, 20000, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL); + +-- Jaraxxus +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34780, 26662, 26662, 26662, 26662, 600000, 600000, 600000, 600000, 600000, 600000, 600000, 600000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34780, 66197, 68123, 68124, 68125, 30000, 30000, 30000, 30000, 45000, 45000, 45000, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34780, 66237, 67049, 67050, 67051, 40000, 40000, 40000, 40000, 90000, 90000, 40000, 90000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34780, 66242, 67060, 67060, 67060, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34780, 66264, 66264, 68405, 68405, 60000, 60000, 60000, 60000, 60000, 60000, 60000, 60000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 1, 0, NULL), +(34780, 66528, 66528, 67029, 67029, 15000, 15000, 15000, 15000, 25000, 25000, 25000, 25000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34780, 66532, 66963, 66964, 66965, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34780, 67108, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34780, 66255, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34780, 34825, 0, 0, 0, 60000, 0, 0, 0, 60000, 0, 0, 0, 0, 0, 0, 0, 20.0, 80.0, 0, 0, 0, 0, 10, 0, 0, 0, NULL), +(34780, 34813, 0, 0, 0, 60000, 0, 0, 0, 60000, 0, 0, 0, 0, 0, 0, 0, 20.0, 60.0, 0, 0, 0, 0, 10, 0, 0, 0, NULL); + +-- NPC Legion flame +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34784, 66199, 68127, 68126, 68128, 30000, 30000, 30000, 30000, 45000, 45000, 45000, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL); + +-- Gormok +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34796, 34800, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 20.0, 80.0, 0, 0, 0, 0, 9, 0, 0, 0, NULL), +(34796, 66331, 67477, 67478, 67479, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34796, 66636, 0, 0, 0, 15000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1, 0, NULL), +(34796, 67648, 0, 0, 0, 15000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Icehowl +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34797, 66683, 67660, 67661, 67662, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34797, 66689, 67650, 67651, 67652, 25000, 25000, 25000, 25000, 40000, 40000, 40000, 40000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34797, 66734, 0, 0, 0, 4000, 4000, 3000, 3000, 4000, 4000, 3000, 3000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34797, 66770, 67654, 67655, 67656, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(34797, 66758, 0, 0, 0, 15000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34797, 68667, 0, 0, 0, 8000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 200.0, 0, 0, 0, 0, 0, 12, 0, 1, 0, NULL), +(34797, 66759, 0, 0, 0, 300000, 0, 0, 0, 300000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34797, 67345, 67663, 67664, 67665, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL); + +-- Dreadscale +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34799, 53421, 0, 0, 0, 40000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34799, 66794, 67644, 67645, 67646, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34799, 66796, 67632, 67633, 67634, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34799, 66821, 66821, 66821, 66821, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34799, 66879, 67624, 67625, 67626, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34799, 66902, 67627, 67628, 67629, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(34799, 66883, 67641, 67642, 67643, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(34799, 35176, 0, 0, 0, 30000, 30000, 45000, 60000, 30000, 30000, 45000, 60000, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 11, 0, 0, 0, NULL), +(34799, 68335, 68335, 68335, 68335, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Snobold vassal +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34800, 66313, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34800, 66317, 0, 0, 0, 10000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34800, 66318, 0, 0, 0, 10000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(34800, 66406, 0, 0, 0, 10000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, NULL), +(34800, 66407, 0, 0, 0, 10000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(34800, 66408, 0, 0, 0, 10000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(34800, 66636, 0, 0, 0, 15000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 1, 0, NULL); + +-- Infernal volcano +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34813, 66255, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(34813, 66258, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, NULL); + +-- Fel infernal +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34815, 66494, 66494, 66494, 66494, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34815, 67047, 67047, 67047, 67047, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Mistress of pain +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(34826, 66316, 66316, 66316, 66316, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(34826, 67098, 67098, 67098, 67098, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL); + +-- Acidmaw +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(35144, 53421, 0, 0, 0, 40000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, NULL), +(35144, 66794, 67644, 67645, 67646, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(35144, 66819, 66819, 66819, 66819, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(35144, 66824, 67612, 67613, 67614, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(35144, 66880, 67606, 67607, 67608, 15000, 15000, 15000, 15000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(35144, 66901, 0, 0, 0, 15000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(35144, 66883, 67641, 67642, 67643, 20000, 20000, 20000, 20000, 30000, 30000, 30000, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL), +(35144, 35176, 0, 0, 0, 30000, 30000, 45000, 60000, 30000, 30000, 45000, 60000, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 11, 0, 0, 0, NULL), +(35144, 68335, 68335, 68335, 68335, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Slime pool +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(35176, 63084, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, NULL), +(35176, 66882, 0, 0, 0, 500, 0, 0, 0, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Retro Paladins +DELETE FROM `boss_spell_table` WHERE `entry` IN (34471,34456); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34471, 66011, 0, 180000, 180000, 3), +(34471, 66003, 0, 6000, 18000, 3), +(34471, 66010, 0, 0, 3600001, 1), +(34471, 66006, 0, 10000, 10000, 3), +(34471, 66007, 0, 40000, 40000, 3), +(34471, 66009, 0, 300000, 300000, 1), +(34471, 66005, 68018, 8000, 15000, 3), +(34471, 66008, 0, 60000, 60000, 4), +(34471, 66004, 68021, 10000, 15000, 1); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34456, 66011, 0, 180000, 180000, 3), +(34456, 66003, 0, 6000, 18000, 3), +(34456, 66010, 0, 0, 3600001, 1), +(34456, 66006, 0, 10000, 10000, 3), +(34456, 66007, 0, 40000, 40000, 3), +(34456, 66009, 0, 300000, 300000, 1), +(34456, 66005, 68018, 8000, 15000, 3), +(34456, 66008, 0, 60000, 60000, 4), +(34456, 66004, 68021, 10000, 15000, 1); + +-- Pet's +DELETE FROM `boss_spell_table` WHERE `entry` IN (35465,35610); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(35465, 67518, 0, 15000, 30000, 3), +(35465, 67519, 0, 15000, 30000, 3); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(35610, 67793, 67980, 67981, 67982, 5000, 10000, 3); + +-- Druids +DELETE FROM `boss_spell_table` WHERE `entry` IN (34460,34451); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34460, 66093, 67957, 5000, 15000, 14), +(34460, 66066, 67965, 10000, 20000, 14), +(34460, 66067, 67968, 10000, 20000, 14), +(34460, 66065, 67971, 10000, 20000, 14), +(34460, 66086, 67974, 40000, 90000, 1), +(34460, 65860, 0, 45000, 90000, 1), +(34460, 66068, 0, 15000, 30000, 6), +(34460, 66071, 0, 40000, 80000, 1); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34451, 66093, 67957, 10000, 20000, 14), +(34451, 66066, 67965, 10000, 20000, 14), +(34451, 66067, 67968, 10000, 20000, 14), +(34451, 66065, 67971, 10000, 20000, 14), +(34451, 66086, 67974, 40000, 90000, 1), +(34451, 65860, 0, 45000, 90000, 1), +(34451, 66068, 0, 15000, 30000, 6), +(34451, 66071, 0, 40000, 80000, 1); + +-- Warriors +DELETE FROM `boss_spell_table` WHERE `entry` IN (34475,34453); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34475, 65947, 0, 20000, 30000, 1), +(34475, 65930, 0, 10000, 60000, 3), +(34475, 65926, 0, 6000, 25000, 3), +(34475, 68764, 0, 3000, 25000, 3), +(34475, 65935, 0, 20000, 80000, 3), +(34475, 65924, 0, 30000, 90000, 1), +(34475, 65936, 0, 5000, 25000, 3), +(34475, 65940, 0, 10000, 25000, 3), +(34475, 65932, 0, 30000, 60000, 1); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34453, 65947, 0, 20000, 30000, 1), +(34453, 65930, 0, 10000, 60000, 3), +(34453, 65926, 0, 6000, 25000, 3), +(34453, 68764, 0, 3000, 25000, 3), +(34453, 65935, 0, 20000, 80000, 3), +(34453, 65924, 0, 30000, 90000, 1), +(34453, 65936, 0, 5000, 25000, 3), +(34453, 65940, 0, 10000, 25000, 3), +(34453, 65932, 0, 30000, 60000, 1); + +-- Mage +DELETE FROM `boss_spell_table` WHERE `entry` IN (34468,34449); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34468, 65799, 67995, 3000, 10000, 3), +(34468, 65791, 67998, 5000, 15000, 3), +(34468, 65800, 68001, 5000, 15000, 3), +(34468, 65793, 0, 7000, 25000, 1), +(34468, 65807, 68004, 5000, 15000, 4), +(34468, 65790, 0, 5000, 15000, 6), +(34468, 65792, 0, 7000, 15000, 1), +(34468, 65802, 0, 0, 3600001, 1), +(34468, 65801, 0, 15000, 40000, 4); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34449, 65799, 67995, 3000, 10000, 3), +(34449, 65791, 67998, 5000, 15000, 3), +(34449, 65800, 68001, 5000, 15000, 3), +(34449, 65793, 0, 7000, 25000, 1), +(34449, 65807, 68004, 5000, 15000, 4), +(34449, 65790, 0, 5000, 15000, 6), +(34449, 65792, 0, 7000, 15000, 1), +(34449, 65802, 0, 0, 3600001, 1), +(34449, 65801, 0, 15000, 40000, 4); + +-- Shaman +DELETE FROM `boss_spell_table` WHERE `entry` IN (34463,34455); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34463, 66055, 68115, 5000, 15000, 14), +(34463, 66053, 68118, 5000, 15000, 14), +(34463, 66056, 0, 5000, 15000, 14), +(34463, 65983, 0, 30000, 60000, 1), +(34463, 65980, 0, 5000, 15000, 6), +(34463, 66054, 0, 10000, 40000, 4), +(34463, 66063, 0, 5000, 15000, 14), +(34463, 65973, 68100, 5000, 15000, 4); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34455, 66055, 68115, 5000, 15000, 14), +(34455, 66053, 68118, 5000, 15000, 14), +(34455, 66056, 0, 5000, 15000, 14), +(34455, 65983, 0, 30000, 60000, 1), +(34455, 65980, 0, 5000, 15000, 6), +(34455, 66054, 0, 10000, 40000, 4), +(34455, 66063, 0, 5000, 15000, 14), +(34455, 65973, 68100, 5000, 15000, 4); + +-- Enh shaman +DELETE FROM `boss_spell_table` WHERE `entry` IN (34470,34444); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34470, 65973, 0, 5000, 8000, 4), +(34470, 65974, 0, 5000, 8000, 3), +(34470, 65983, 0, 25000, 600000, 1), +(34470, 65970, 0, 5000, 90000, 3); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34444, 65973, 0, 5000, 8000, 4), +(34444, 65974, 0, 5000, 8000, 3), +(34444, 65983, 0, 25000, 600000, 1), +(34444, 65970, 0, 5000, 90000, 3); + +-- Hunter +DELETE FROM `boss_spell_table` WHERE `entry` IN (34467,34448); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34467, 65583, 67978, 3000, 8000, 3), +(34467, 65871, 0, 20000, 120000, 1), +(34467, 65869, 0, 12000, 20000, 1), +(34467, 65866, 67984, 3000, 8000, 3), +(34467, 65880, 0, 12000, 30000, 1), +(34467, 65868, 67989, 4000, 8000, 3), +(34467, 65867, 0, 4000, 8000, 3), +(34467, 66207, 0, 4000, 8000, 3), +(34467, 65877, 0, 7000, 60000, 4); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34448, 65583, 67978, 3000, 8000, 3), +(34448, 65871, 0, 20000, 120000, 1), +(34448, 65869, 0, 12000, 20000, 1), +(34448, 65866, 67984, 3000, 8000, 3), +(34448, 65880, 0, 12000, 30000, 1), +(34448, 65868, 67989, 4000, 8000, 3), +(34448, 65867, 0, 4000, 8000, 3), +(34448, 66207, 0, 4000, 8000, 3), +(34448, 65877, 0, 7000, 60000, 4); + +-- Rogue +DELETE FROM `boss_spell_table` WHERE `entry` IN (34472,34454); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34472, 65955, 0, 8000, 10000, 3), +(34472, 65956, 0, 12000, 120000, 1), +(34472, 65960, 0, 7000, 8000, 6), +(34472, 65961, 0, 20000, 120000, 1), +(34472, 66178, 0, 10000, 8000, 3), +(34472, 65954, 0, 5000, 8000, 3), +(34472, 65957, 68095, 15000, 20000, 3); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34454, 65955, 0, 8000, 10000, 3), +(34454, 65956, 0, 12000, 120000, 1), +(34454, 65960, 0, 7000, 8000, 6), +(34454, 65961, 0, 20000, 120000, 1), +(34454, 66178, 0, 10000, 8000, 3), +(34454, 65954, 0, 5000, 8000, 3), +(34454, 65957, 68095, 15000, 20000, 3); + +-- Priest +DELETE FROM `boss_spell_table` WHERE `entry` IN (34466,34447); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34466, 66177, 68035, 3000, 8000, 14), +(34466, 66099, 68032, 3000, 8000, 14), +(34466, 66104, 68023, 3000, 8000, 14), +(34466, 66100, 68026, 3000, 8000, 4), +(34466, 65546, 0, 3000, 8000, 6), +(34466, 65543, 0, 5000, 25000, 1); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34447, 66177, 68035, 3000, 8000, 14), +(34447, 66099, 68032, 3000, 8000, 14), +(34447, 66104, 68023, 3000, 8000, 14), +(34447, 66100, 68026, 3000, 8000, 4), +(34447, 65546, 0, 3000, 8000, 6), +(34447, 65543, 0, 5000, 25000, 1); + +-- Shadow priest +DELETE FROM `boss_spell_table` WHERE `entry` IN (34473,34441); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34473, 65542, 0, 8000, 15000, 6), +(34473, 65490, 68091, 3000, 8000, 4), +(34473, 65541, 68088, 3000, 8000, 4), +(34473, 65488, 68042, 3000, 8000, 3), +(34473, 65492, 68038, 3000, 8000, 3), +(34473, 65545, 0, 3000, 8000, 3), +(34473, 65544, 0, 1000, 180000, 1), +(34473, 65546, 0, 3000, 8000, 4), +(34473, 65543, 0, 8000, 24000, 1), +(34473, 16592, 0, 3000, 8000, 1); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34441, 65542, 0, 8000, 15000, 6), +(34441, 65490, 68091, 3000, 8000, 4), +(34441, 65541, 68088, 3000, 8000, 4), +(34441, 65488, 68042, 3000, 8000, 3), +(34441, 65492, 68038, 3000, 8000, 3), +(34441, 65545, 0, 3000, 8000, 3), +(34441, 65544, 0, 1000, 180000, 1), +(34441, 65546, 0, 3000, 8000, 4), +(34441, 65543, 0, 8000, 24000, 1), +(34441, 16592, 0, 3000, 8000, 1); + +-- Death knight +DELETE FROM `boss_spell_table` WHERE `entry` IN (34461,34458); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34461, 66020, 0, 5000, 15000, 3), +(34461, 66019, 67930, 5000, 15000, 3), +(34461, 66017, 0, 5000, 15000, 3), +(34461, 66047, 67936, 5000, 15000, 3), +(34461, 66023, 0, 5000, 90000, 1), +(34461, 66021, 67939, 8000, 12000, 3), +(34461, 66018, 0, 10000, 90000, 6); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34458, 66020, 0, 5000, 15000, 3), +(34458, 66019, 67930, 5000, 15000, 3), +(34458, 66017, 0, 5000, 15000, 3), +(34458, 66047, 67936, 5000, 15000, 3), +(34458, 66023, 0, 5000, 90000, 1), +(34458, 66021, 67939, 8000, 12000, 3), +(34458, 66018, 0, 10000, 90000, 6); + +-- Paladin +DELETE FROM `boss_spell_table` WHERE `entry` IN (34465,34445); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34465, 68757, 0, 25000, 40000, 6), +(34465, 66010, 0, 0, 3600001, 14), +(34465, 66116, 0, 5000, 15000, 14), +(34465, 66113, 68008, 5000, 10000, 14), +(34465, 66112, 68011, 5000, 15000, 14), +(34465, 66009, 0, 0, 3600001, 6), +(34465, 66114, 68015, 6000, 15000, 14), +(34465, 66613, 0, 5000, 15000, 4); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34445, 68757, 0, 25000, 40000, 6), +(34445, 66010, 0, 0, 3600001, 14), +(34445, 66116, 0, 5000, 15000, 14), +(34445, 66113, 68008, 5000, 10000, 14), +(34445, 66112, 68011, 5000, 15000, 14), +(34445, 66009, 0, 0, 3600001, 6), +(34445, 66114, 68015, 6000, 15000, 14), +(34445, 66613, 0, 5000, 15000, 4); + +-- Boomkin (druid in moonkin form) +DELETE FROM `boss_spell_table` WHERE `entry` IN (34469,34459); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34469, 65859, 0, 5000, 40000, 4), +(34469, 65857, 0, 5000, 40000, 3), +(34469, 65863, 0, 10000, 40000, 4), +(34469, 65861, 0, 25000, 40000, 3), +(34469, 65855, 67942, 25000, 40000, 4), +(34469, 65856, 67945, 5000, 40000, 3), +(34469, 65854, 67948, 25000, 40000, 3), +(34469, 65860, 0, 5000, 120000, 1), +(34469, 65862, 67952, 25000, 40000, 3); + +-- Warlock +DELETE FROM `boss_spell_table` WHERE `entry` IN (34474,34450); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34474, 65816, 68146, 15000, 30000, 1), +(34474, 65810, 68134, 15000, 30000, 4), +(34474, 65814, 68137, 15000, 30000, 4), +(34474, 65815, 0, 15000, 30000, 4), +(34474, 65809, 0, 4000, 15000, 4), +(34474, 65819, 68149, 15000, 30000, 3), +(34474, 65821, 68152, 3000, 10000, 3), +(34474, 65812, 68155, 2000, 10000, 4); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_H10`, `timerMin_N10`, `timerMax_N10`, `CastType`) VALUES +(34450, 65816, 68146, 15000, 30000, 1), +(34450, 65810, 68134, 15000, 30000, 4), +(34450, 65814, 68137, 15000, 30000, 4), +(34450, 65815, 0, 15000, 30000, 4), +(34450, 65809, 0, 4000, 15000, 4), +(34450, 65819, 68149, 15000, 30000, 3), +(34450, 65821, 68152, 3000, 10000, 3), +(34450, 65812, 68155, 2000, 10000, 4); diff --git a/sql_mr/mr00071_mangos_Instance_Nexus.sql b/sql_mr/mr00071_mangos_Instance_Nexus.sql new file mode 100644 index 0000000000..8e31ff3dc6 --- /dev/null +++ b/sql_mr/mr00071_mangos_Instance_Nexus.sql @@ -0,0 +1,9 @@ +-- Instance Nexus + +-- set Breath Casters to flying (dummy NPCs near Keristrasza) +UPDATE creature_template SET InhabitType = 7 WHERE entry = 27048; + +UPDATE `creature_template` SET `ScriptName` = 'mob_crystal_spike' WHERE `entry` = '27099'; +UPDATE `creature_template` SET `ScriptName` = 'mob_crystalline_tangler' WHERE `entry` = '32665'; +UPDATE `creature_template` SET `ScriptName` = 'boss_commander_kolurg' WHERE `entry` = 26798; +UPDATE `creature_template` SET `ScriptName` = 'boss_commander_stoutbeard' WHERE `entry` = 26796; diff --git a/sql_mr/mr00075_mangos_FactionLeaders.sql b/sql_mr/mr00075_mangos_FactionLeaders.sql new file mode 100644 index 0000000000..80e1141dfe --- /dev/null +++ b/sql_mr/mr00075_mangos_FactionLeaders.sql @@ -0,0 +1,11 @@ +UPDATE `creature_template` SET `ScriptName`='boss_king_magni_bronzebreard' WHERE `entry`=2784; +UPDATE `creature_template` SET `ScriptName`='boss_high_tinker_mekkatorque' WHERE `entry`=7937; +UPDATE `creature_template` SET `ScriptName`='boss_lorthemar_theron' WHERE `entry`=16802; +UPDATE `creature_template` SET `ScriptName`='boss_king_varian_wrynn' WHERE `entry`=29611; +UPDATE `creature_template` SET `ScriptName`='boss_lady_jaina_proudmoore' WHERE `entry`=4968; +UPDATE `creature_template` SET `ScriptName`='boss_prophet_velen' WHERE `entry`=17468; +UPDATE `creature_template` SET `ScriptName`='boss_voljin' WHERE `entry`=10540; +UPDATE `creature_template` SET `ScriptName`='boss_tyrande_whisperwind' WHERE `entry`=7999; +UPDATE `creature_template` SET `ScriptName`='boss_fandral_staghelm' WHERE `entry`=3516; +UPDATE `creature_template` SET `ScriptName` = 'generic_creature' WHERE `entry` = 16801; +UPDATE `spell_target_position` SET `target_map` = 1, `target_position_x` = -3992.637, `target_position_y` = -4717.926, `target_position_z` = 11.006, `target_orientation` = 0.7 WHERE `id` = 20682; diff --git a/sql_mr/mr00165_mangos_instance_the_shattered_halls.sql b/sql_mr/mr00165_mangos_instance_the_shattered_halls.sql new file mode 100644 index 0000000000..ef07093459 --- /dev/null +++ b/sql_mr/mr00165_mangos_instance_the_shattered_halls.sql @@ -0,0 +1,4 @@ +-- Instance The Shattered Halls + +-- Shattered Hand Executioner +UPDATE `creature_template` SET `UnitFlags` = 3 WHERE `entry` = 20585; -- adding not attackable flag, removed by script on boss death diff --git a/sql_mr/mr00224_scriptdev2_the_violet_hold.sql b/sql_mr/mr00224_scriptdev2_the_violet_hold.sql new file mode 100644 index 0000000000..cf94f25cdd --- /dev/null +++ b/sql_mr/mr00224_scriptdev2_the_violet_hold.sql @@ -0,0 +1,51 @@ +-- -1 608 000 VIOLET HOLD +DELETE FROM `script_texts` WHERE entry BETWEEN -1608071 AND -1608029; +INSERT IGNORE INTO `script_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`) VALUES +-- Erekem +(-1608066, '...', 14222, 1, 0, 'erekem SAY_SLAY_1'), +(-1608067, 'Precious life ... wasted.', 14223, 1, 0, 'erekem SAY_SLAY_2'), +(-1608068, 'Only strong ... survive.', 14224, 1, 0, 'erekem SAY_SLAY_3'), +-- Ichoron +(-1608069, 'I... am fury... unrestrained!', 14239, 1, 0, 'ichoron SAY_SPAWN'), +-- Xevozz +(-1608070, 'It seems my freedom must be bought with blood...', 14499, 1, 0, 'xevozz SAY_AGGRO'), +(-1608071, 'Nothing personal.', 14504, 1, 0, 'xevozz SAY_SLAY_1'), +(-1608029, 'Business concluded.', 14505, 1, 0, 'xevozz SAY_SLAY_2'), +(-1608030, 'Profit!', 14506, 1, 0, 'xevozz SAY_SLAY_3'), +(-1608031, 'This is an... unrecoverable... loss.', 14507, 1, 0, 'xevozz SAY_DEATH'), +(-1608033, 'It would seem that a renegotiation is in order.', 14503, 1, 0, 'xevozz SAY_CHARGED'), +(-1608034, 'The air teems with latent energy... quite the harvest!', 14501, 1, 0, 'xevozz SAY_REPEAT_SUMMON_1'), +(-1608035, 'Plentiful, exploitable resources... primed for acquisition!', 14502, 1, 0, 'xevozz SAY_REPEAT_SUMMON_2'), +(-1608036, 'Intriguing... a high quantity of arcane energy is near. Time for some prospecting...', 14500, 1, 0, 'xevozz SAY_SUMMON_ENERGY'), +-- Zuramat +(-1608037, 'Eradicate.', 13996, 1, 0, 'zuramat SAY_AGGRO'), +(-1608038, 'More... energy.', 13999, 1, 0, 'zuramat SAY_SLAY_1'), +(-1608039, 'Relinquish.', 14000, 1, 0, 'zuramat SAY_SLAY_2'), +(-1608040, 'Fall... to shadow.', 14001, 1, 0, 'zuramat SAY_SLAY_3'), +(-1608041, 'Disperse.', 14002, 1, 0, 'zuramat SAY_DEATH'), +(-1608043, 'Know... my... pain.', 13997, 1, 0, 'zuramat SAY_SHIELD'), +(-1608044, 'Gaze... into the void.', 13998, 1, 0, 'zuramat SAY_WHISPER'), +-- Cyanigosa +(-1608045,'A valiant defense, but this city must be razed. I will fulfill Malygos wishes myself!', 13946, 1, 0,'A_VH_Cyanigosa_Spawn'), +(-1608046,'We finish this now, champions of Kirin Tor!',13947,1,0,'A_VH_Cyanigosa_Aggro'), +(-1608047,'Shiver and die!',13948,1,0,'A_VH_Cyanigosa_BreathAttack'), +(-1608048,'The world has forgotten what true magic is! Let this be a reminder!',13949,1,0,'A_VH_Cyanigosa_SpecialAttack01'), +(-1608049,'Who among you can withstand my power?',13950,1,0,'A_VH_Cyanigosa_SpecialAttack02'), +(-1608050,'Am I interrupting?',13951,1,0,'A_VH_Cyanigosa_Disruption'), +(-1608051,'I will end the Kirin Tor!',13952,1,0,'A_VH_Cyanigosa_Slay01'), +(-1608052,'Dalaran will fall!',13953,1,0,'A_VH_Cyanigosa_Slay02'), +(-1608053,'So ends your defiance of the Spell-Weaver!',13954,1,0,'A_VH_Cyanigosa_Slay03'), +(-1608054,'Perhaps... we have... underestimated... you.',13955,1,0,'A_VH_Cyanigosa_Death01'), +-- Azures +(-1608055,'The Kirin Tor must be stopped!',0,0,0,'AZURE_SAY_AGGRO_1'), +(-1608056,'Dalaran must fall!',0,0,0,'AZURE_SAY_AGGRO_2'), +(-1608057,'The Nexus War will not be stopped!',0,0,0,'AZURE_SAY_AGGRO_3'), +(-1608058,'For the Spellweaver!',0,0,0,'AZURE_SAY_AGGRO_4'), +(-1608059,'The destruction of Dalaran is inevitable!',0,1,0,'Portal Keeper/Guardian AGGRO_1'), +(-1608060,'The portal has stabilized! Attack!',0,1,0,'Portal Keeper/Guardian AGGRO_2'), +(-1608064,'The way into Dalaran has been opened!',0,1,0,'Portal Guardian AGGRO_3'), +(-1608061,'More portals will take this one\'s place!',0,1,0,'Portal Keeper/Guardian DEATH_1'), +(-1608062,'Why do you defend the Kirin Tor...',0,1,0,'Portal Keeper/Guardian DEATH_2'), +(-1608063,'My death will not stop the invasion!',0,1,0,'Portal Keeper/Guardian DEATH_2'), +(-1608065,'Destroy all who stand against us!',0,0,0,'Azure Captain AGGRO_1'); + diff --git a/sql_mr/mr00249_mangos_alterac_valley.sql b/sql_mr/mr00249_mangos_alterac_valley.sql new file mode 100644 index 0000000000..654999df70 --- /dev/null +++ b/sql_mr/mr00249_mangos_alterac_valley.sql @@ -0,0 +1,388 @@ +-- Alterac Valley: Stats (by lanc) (may YTDB is more correct now) +UPDATE `creature_template` SET `PickpocketLootId` = 11946, `EquipmentTemplateId` = 2153 WHERE `entry` = 37283; +UPDATE `creature_template` SET `PickpocketLootId` = 11948 WHERE `entry` = 31818; +UPDATE `creature_template` SET `PickpocketLootId` = 11948 WHERE `entry` = 37444; +UPDATE `creature_template` SET `EquipmentTemplateId` = 325 WHERE `entry` = 37243; +UPDATE `creature_template` SET `EquipmentTemplateId` = 2156 WHERE `entry` = 37412; +UPDATE `creature_template` SET `EquipmentTemplateId` = 2158 WHERE `entry` = 37300; +UPDATE `creature_template` SET `EquipmentTemplateId` = 2161 WHERE `entry` = 37415; +UPDATE `creature_template` SET `EquipmentTemplateId` = 170 WHERE `entry` = 37410; +UPDATE `creature_template` SET `EquipmentTemplateId` = 954 WHERE `entry` = 37297; +UPDATE `creature_template` SET `EquipmentTemplateId` = 2178 WHERE `entry` IN (37285, 37287, 37327, 37407); +UPDATE `creature_template` SET `EquipmentTemplateId` = 2179 WHERE `entry` IN (37291, 37326, 37435, 37468); + +-- MOVEMENT + +UPDATE creature SET MovementType = 2 WHERE guid IN (150135, 150132, 150133, 150131, 150139, 150130, 150100, 150097, 150090, 150091, 150101, 150093, 150095, 150129, 150128, 150094, 150092, 150096, 150089, 150099, 150098); + +-- Stormpike Guardsman +DELETE FROM creature_movement WHERE id = 150097; +INSERT INTO creature_movement VALUES +(150097, 1, 740.939, -478.112, 85.143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.88545, 0, 0), +(150097, 2, 717.895, -472.077, 74.577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.88545, 0, 0), +(150097, 3, 707.233, -465.281, 67.9093, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.48631, 0, 0), +(150097, 4, 701.863, -454.545, 63.8615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.03078, 0, 0), +(150097, 5, 697.745, -424.072, 63.348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.70877, 0, 0), +(150097, 6, 671.764, -409.299, 66.804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.66715, 0, 0), +(150097, 7, 655.093, -402.306, 67.9035, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.55798, 0, 0), +(150097, 8, 628.274, -382.858, 67.7545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.50953, 0, 0), +(150097, 9, 581.684, -391.884, 65.2107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.41666, 0, 0), +(150097, 10, 546.879, -396.505, 52.9005, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.28708, 0, 0), +(150097, 11, 487.458, -430.63, 36.839, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.67586, 0, 0), +(150097, 12, 459.763, -434.832, 32.0776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.13786, 0, 0), +(150097, 13, 487.458, -430.63, 36.839, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.67586, 0, 0), +(150097, 14, 546.879, -396.505, 52.9005, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.28708, 0, 0), +(150097, 15, 581.684, -391.884, 65.2107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.41666, 0, 0), +(150097, 16, 628.274, -382.858, 67.7545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.50953, 0, 0), +(150097, 17, 655.093, -402.306, 67.9035, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.55798, 0, 0), +(150097, 18, 671.764, -409.299, 66.804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.66715, 0, 0), +(150097, 19, 697.745, -424.072, 63.348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.70877, 0, 0), +(150097, 20, 701.863, -454.545, 63.8615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.03078, 0, 0), +(150097, 21, 707.233, -465.281, 67.9093, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.48631, 0, 0), +(150097, 22, 717.895, -472.077, 74.577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.88545, 0, 0), +(150097, 23, 740.939, -478.112, 85.143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.88545, 0, 0); + +DELETE FROM creature_movement WHERE id = 150100; +INSERT INTO creature_movement VALUES +(150100, 1, 740.261, -480.154, 85.0366, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.86974, 0, 0), +(150100, 2, 716.512, -474.191, 74.2183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.60258, 0, 0), +(150100, 3, 704.456, -466.858, 67.605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.11874, 0, 0), +(150100, 4, 699.04, -455.634, 63.8726, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.90531, 0, 0), +(150100, 5, 695.474, -425.224, 63.1943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.85034, 0, 0), +(150100, 6, 670.747, -411.279, 66.8755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.66715, 0, 0), +(150100, 7, 653.495, -403.745, 67.8676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.27131, 0, 0), +(150100, 8, 626.721, -384.801, 67.468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.56451, 0, 0), +(150100, 9, 580.034, -395.325, 64.4244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.28708, 0, 0), +(150100, 10, 548.187, -399.874, 52.9756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.42453, 0, 0), +(150100, 11, 488.046, -433.701, 37.1277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.3617, 0, 0), +(150100, 12, 459.504, -437.071, 32.2797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.11077, 0, 0), +(150100, 13, 488.046, -433.701, 37.1277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.3617, 0, 0), +(150100, 14, 548.187, -399.874, 52.9756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.42453, 0, 0), +(150100, 15, 580.034, -395.325, 64.4244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.28708, 0, 0), +(150100, 16, 626.721, -384.801, 67.468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.56451, 0, 0), +(150100, 17, 653.495, -403.745, 67.8676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.27131, 0, 0), +(150100, 18, 670.747, -411.279, 66.8755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.66715, 0, 0), +(150100, 19, 695.474, -425.224, 63.1943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.85034, 0, 0), +(150100, 20, 699.04, -455.634, 63.8726, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.90531, 0, 0), +(150100, 21, 704.456, -466.858, 67.605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.11874, 0, 0), +(150100, 22, 716.512, -474.191, 74.2183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.60258, 0, 0), +(150100, 23, 740.261, -480.154, 85.0366, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.86974, 0, 0); + +DELETE FROM creature_movement WHERE id = 150090; +INSERT INTO creature_movement VALUES +(150090, 1, 459.763, -434.832, 32.0776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.21248, 0, 0), +(150090, 2, 487.824, -431.091, 36.9258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.321996, 0, 0), +(150090, 3, 547.195, -396.696, 52.9658, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.337704, 0, 0), +(150090, 4, 579.835, -392.66, 64.7979, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.196326, 0, 0), +(150090, 5, 628.186, -383.207, 67.6938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.03184, 0, 0), +(150090, 6, 655.253, -402.118, 67.9072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.78051, 0, 0), +(150090, 7, 672.065, -409.314, 66.7835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.8512, 0, 0), +(150090, 8, 697.794, -424.703, 63.2374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.30166, 0, 0), +(150090, 9, 702.036, -453.75, 63.7331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.98828, 0, 0), +(150090, 10, 707.613, -465.478, 68.1059, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.3219, 0, 0), +(150090, 11, 718.312, -472.268, 74.8416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.90077, 0, 0), +(150090, 12, 741.106, -478.418, 85.2153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.0225, 0, 0); + +DELETE FROM creature_movement WHERE id = 150091; +INSERT INTO creature_movement VALUES +(150091, 1, 459.504, -437.071, 32.2797, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.04834, 0, 0), +(150091, 2, 488.53, -433.858, 37.2377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.357343, 0, 0), +(150091, 3, 548.33, -400.154, 53.0222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.345561, 0, 0), +(150091, 4, 580.237, -396.715, 64.4967, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.073811, 0, 0), +(150091, 5, 626.866, -385.295, 67.4286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.18892, 0, 0), +(150091, 6, 653.77, -404.067, 67.859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.69805, 0, 0), +(150091, 7, 670.956, -411.437, 66.8527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.83941, 0, 0), +(150091, 8, 695.852, -425.867, 63.0925, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.75302, 0, 0), +(150091, 9, 698.64, -455.618, 63.8672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.95585, 0, 0), +(150091, 10, 704.549, -466.658, 67.5728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.32914, 0, 0), +(150091, 11, 716.605, -474.283, 74.2881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.81294, 0, 0), +(150091, 12, 740.406, -480.439, 85.1497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.01854, 0, 0); + +DELETE FROM creature_movement WHERE id = 150093; +INSERT INTO creature_movement VALUES +(150093, 1, 408.326, -401.773, 1.99924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.29066, 0, 0), +(150093, 2, 443.914, -439.315, 30.2186, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.24746, 0, 0), +(150093, 3, 444.226, -479.454, 49.5636, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.51704, 0, 0), +(150093, 4, 424.107, -507.015, 66.3738, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.67413, 0, 0), +(150093, 5, 444.226, -479.454, 49.5636, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.51704, 0, 0), +(150093, 6, 443.914, -439.315, 30.2186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.24746, 0, 0), +(150093, 7, 408.326, -401.773, 1.99924, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.29066, 0, 0); + +DELETE FROM creature_movement WHERE id = 150101; +INSERT INTO creature_movement VALUES +(150101, 1, 410.821, -400.14, 1.63831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.20034, 0, 0), +(150101, 2, 446.745, -438.881, 30.5422, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.98828, 0, 0), +(150101, 3, 446.427, -480.592, 50.0273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.27751, 0, 0), +(150101, 4, 425.572, -508.917, 66.5385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.767, 0, 0), +(150101, 5, 446.427, -480.592, 50.0273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.27751, 0, 0), +(150101, 6, 446.745, -438.881, 30.5422, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.98828, 0, 0), +(150101, 7, 410.821, -400.14, 1.63831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.20034, 0, 0); + +DELETE FROM creature_movement WHERE id = 150092; +INSERT INTO creature_movement VALUES +(150092, 1, 141.609, -393.495, 42.5139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.77505, 0, 0), +(150092, 2, 191.492, -410.704, 43.2766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.97533, 0, 0), +(150092, 3, 229.857, -420.678, 38.7887, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12063, 0, 0), +(150092, 4, 253.305, -414.613, 32.2917, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.575711, 0, 0), +(150092, 5, 269.730, -400.311, 18.2004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.765741, 0, 0), +(150092, 6, 296.502, -383.499, 2.29761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007066, 0, 0), +(150092, 7, 364.671, -392.546, -0.397865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.13003, 0, 0), +(150092, 8, 395.037, -394.245, -1.07366, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.204197, 0, 0), +(150092, 9, 364.671, -392.546, -0.397865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.13003, 0, 0), +(150092, 10, 296.502, -383.499, 2.29761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007066, 0, 0), +(150092, 11, 269.730, -400.311, 18.2004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.765741, 0, 0), +(150092, 12, 253.305, -414.613, 32.2917, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.575711, 0, 0), +(150092, 13, 229.857, -420.678, 38.7887, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12063, 0, 0), +(150092, 14, 191.492, -410.704, 43.2766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.97533, 0, 0), +(150092, 15, 141.609, -393.495, 42.5139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.77505, 0, 0); + +DELETE FROM creature_movement WHERE id = 150094; +INSERT INTO creature_movement VALUES +(150094, 1, 142.625, -391.717, 42.409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.87086, 0, 0), +(150094, 2, 192.61, -407.343, 42.9072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.98081, 0, 0), +(150094, 3, 229.769, -417.536, 38.8132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007855, 0, 0), +(150094, 4, 251.029, -410.95, 32.4934, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.439824, 0, 0), +(150094, 5, 268.200, -397.573, 17.881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.816800, 0, 0), +(150094, 6, 296.344, -380.701, 2.44755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.365208, 0, 0), +(150094, 7, 366.913, -389.781, -0.107719, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.03186, 0, 0), +(150094, 8, 394.527, -389.305, -1.24385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.120222, 0, 0), +(150094, 9, 366.913, -389.781, -0.107719, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.03186, 0, 0), +(150094, 10, 296.344, -380.701, 2.44755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.365208, 0, 0), +(150094, 11, 268.200, -397.573, 17.881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.816800, 0, 0), +(150094, 12, 251.029, -410.95, 32.4934, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.439824, 0, 0), +(150094, 13, 229.769, -417.536, 38.8132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007855, 0, 0), +(150094, 14, 192.61, -407.343, 42.9072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.98081, 0, 0), +(150094, 15, 142.625, -391.717, 42.409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.87086, 0, 0); + +DELETE FROM creature_movement WHERE id = 150089; +INSERT INTO creature_movement VALUES +(150089, 1, 415.098, -383.298, -1.24282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.313356, 0, 0), +(150089, 2, 462.558, -373.039, -1.06623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.329849, 0, 0), +(150089, 3, 492.565, -344.508, -1.22761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.636818, 0, 0), +(150089, 4, 523.497, -325.474, -0.239782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.384828, 0, 0), +(150089, 5, 543.961, -322.116, 7.04419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.06708, 0, 0), +(150089, 6, 579.436, -332.652, 28.4993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.7867, 0, 0), +(150089, 7, 606.808, -337.777, 30.1949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.27206, 0, 0), +(150089, 8, 630.057, -316.3, 30.1336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.08057, 0, 0), +(150089, 9, 637.128, -274.198, 30.1825, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.51253, 0, 0), +(150089, 10, 630.057, -316.3, 30.1336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.08057, 0, 0), +(150089, 11, 606.808, -337.777, 30.1949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.27206, 0, 0), +(150089, 12, 579.436, -332.652, 28.4993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.7867, 0, 0), +(150089, 13, 543.961, -322.116, 7.04419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.06708, 0, 0), +(150089, 14, 523.497, -325.474, -0.239782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.384828, 0, 0), +(150089, 15, 492.565, -344.508, -1.22761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.636818, 0, 0), +(150089, 16, 462.558, -373.039, -1.06623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.329849, 0, 0), +(150089, 17, 415.098, -383.298, -1.24282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.313356, 0, 0); + +DELETE FROM creature_movement WHERE id = 150096; +INSERT INTO creature_movement VALUES +(150096, 1, 414.518, -380.779, -1.24282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17277, 0, 0), +(150096, 2, 461.761, -370.435, -1.24382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.203985, 0, 0), +(150096, 3, 490.848, -342.185, -1.12543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.636818, 0, 0), +(150096, 4, 523.487, -324.067, -0.320581, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.081462, 0, 0), +(150096, 5, 543.567, -320.155, 6.76823, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.67193, 0, 0), +(150096, 6, 580.331, -330.599, 28.7799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.84796, 0, 0), +(150096, 7, 605.618, -335.583, 30.4627, 450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.18567, 0, 0), +(150096, 8, 628.389, -315.196, 30.1336, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.774273, 0, 0), +(150096, 9, 635.332, -274.043, 30.151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.67354, 0, 0), +(150096, 10, 628.389, -315.196, 30.1336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.774273, 0, 0), +(150096, 11, 605.618, -335.583, 30.4627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.18567, 0, 0), +(150096, 12, 580.331, -330.599, 28.7799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.84796, 0, 0), +(150096, 13, 543.567, -320.155, 6.76823, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.67193, 0, 0), +(150096, 14, 523.487, -324.067, -0.320581, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.081462, 0, 0), +(150096, 15, 490.848, -342.185, -1.12543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.636818, 0, 0), +(150096, 16, 461.761, -370.435, -1.24382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.203985, 0, 0), +(150096, 17, 414.518, -380.779, -1.24282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17277, 0, 0); + +DELETE FROM creature_movement WHERE id = 150099; +INSERT INTO creature_movement VALUES +(150099, 1, 635.698, -270.97, 30.1292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.60261, 0, 0), +(150099, 2, 628.079, -314.841, 30.1336, 600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.93973, 0, 0), +(150099, 3, 605.703, -335.316, 30.4921, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.91479, 0, 0), +(150099, 4, 580.552, -330.767, 28.8608, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.79159, 0, 0), +(150099, 5, 543.726, -320.113, 6.8534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.1568, 0, 0), +(150099, 6, 523.149, -323.842, -0.410956, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.54164, 0, 0), +(150099, 7, 491.125, -342.124, -1.11999, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.91471, 0, 0), +(150099, 8, 461.613, -370.41, -1.24379, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.66731, 0, 0), +(150099, 9, 414.386, -380.946, -1.24384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.44026, 0, 0), +(150099, 10, 461.613, -370.41, -1.24379, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.66731, 0, 0), +(150099, 11, 491.125, -342.124, -1.11999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.91471, 0, 0), +(150099, 12, 523.149, -323.842, -0.410956, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.54164, 0, 0), +(150099, 13, 543.726, -320.113, 6.8534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.1568, 0, 0), +(150099, 14, 580.552, -330.767, 28.8608, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.79159, 0, 0), +(150099, 15, 605.703, -335.316, 30.4921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.91479, 0, 0), +(150099, 16, 628.079, -314.841, 30.1336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.93973, 0, 0), +(150099, 17, 635.698, -270.97, 30.1292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.60261, 0, 0); + +DELETE FROM creature_movement WHERE id = 150098; +INSERT INTO creature_movement VALUES +(150098, 1, 638.477, -271.16, 30.2074, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.71652, 0, 0), +(150098, 2, 630.132, -316.6, 30.1349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.73948, 0, 0), +(150098, 3, 607.208, -337.493, 30.1978, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.06247, 0, 0), +(150098, 4, 580.059, -332.454, 28.7155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.8119, 0, 0), +(150098, 5, 544.086, -322.083, 7.11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.94542, 0, 0), +(150098, 6, 523.608, -325.321, -0.220814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.39309, 0, 0), +(150098, 7, 492.91, -344.147, -1.22704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.92256, 0, 0), +(150098, 8, 462.796, -372.436, -1.10479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.51023, 0, 0), +(150098, 9, 415.424, -383.387, -1.24384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.56913, 0, 0), +(150098, 10, 462.796, -372.436, -1.10479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.51023, 0, 0), +(150098, 11, 492.91, -344.147, -1.22704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.92256, 0, 0), +(150098, 12, 523.608, -325.321, -0.220814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.39309, 0, 0), +(150098, 13, 544.086, -322.083, 7.11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.94542, 0, 0), +(150098, 14, 580.059, -332.454, 28.7155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.8119, 0, 0), +(150098, 15, 607.208, -337.493, 30.1978, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.06247, 0, 0), +(150098, 16, 630.132, -316.6, 30.1349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.73948, 0, 0), +(150098, 17, 638.477, -271.16, 30.2074, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.71652, 0, 0); + +-- Owls & Battleguards +-- Stormpike Batteguard (with owls at the gate) (inside) +DELETE FROM creature_movement WHERE id = 150139; +INSERT INTO creature_movement VALUES +(150139, 1, 805.184, -494.274, 99.9536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12793, 0, 0), +(150139, 2, 833.077, -497.517, 99.5546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12793, 0, 0), +(150139, 3, 856.245, -501.143, 96.3042, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12793, 0, 0), +(150139, 4, 874.391, -492.179, 96.563, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.420446, 0, 0), +(150139, 5, 885.043, -509.126, 96.749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.23022, 0, 0), +(150139, 6, 914.457, -516.141, 94.0969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.09809, 0, 0), +(150139, 7, 934.569, -512.72, 93.6356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.562114, 0, 0), +(150139, 8, 914.457, -516.141, 94.0969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.09809, 0, 0), +(150139, 9, 885.043, -509.126, 96.749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.23022, 0, 0), +(150139, 10, 874.391, -492.179, 96.563, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.420446, 0, 0), +(150139, 11, 856.245, -501.143, 96.3042, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12793, 0, 0), +(150139, 12, 833.077, -497.517, 99.5546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12793, 0, 0), +(150139, 13, 805.184, -494.274, 99.9536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.12793, 0, 0); + +-- Stormpike Batteguard (with owls at the portal) (inside) +DELETE FROM creature_movement WHERE id = 150135; +INSERT INTO creature_movement VALUES +(150135, 1, 934.557, -512.395, 93.6308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.46809, 0, 0), +(150135, 2, 913.361, -515.883, 94.1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.04301, 0, 0), +(150135, 3, 884.547, -508.993, 96.7161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.85097, 0, 0), +(150135, 4, 874.063, -492.077, 96.56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.17946, 0, 0), +(150135, 5, 856.379, -500.86, 96.2985, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.656, 0, 0), +(150135, 6, 832.661, -497.338, 99.6367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.86824, 0, 0), +(150135, 7, 804.982, -494.262, 99.9406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.97674, 0, 0), +(150135, 8, 832.661, -497.338, 99.6367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.86824, 0, 0), +(150135, 9, 856.379, -500.86, 96.2985, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.656, 0, 0), +(150135, 10, 874.063, -492.077, 96.56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.17946, 0, 0), +(150135, 11, 884.547, -508.993, 96.7161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.85097, 0, 0), +(150135, 12, 913.361, -515.883, 94.1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.04301, 0, 0), +(150135, 13, 934.557, -512.395, 93.6308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.46809, 0, 0); + +-- Stormpike Owl (with guard at the gate) (inside) +DELETE FROM creature_movement WHERE id = 150130; +INSERT INTO creature_movement VALUES +(150130, 1, 805.777, -491.145, 100.066, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.22427, 0, 0), +(150130, 2, 832.623, -495.061, 99.9326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.13395, 0, 0), +(150130, 3, 856.046, -498.303, 96.4667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.87477, 0, 0), +(150130, 4, 874.936, -490.813, 96.5369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.39961, 0, 0), +(150130, 5, 885.222, -507.547, 96.8083, 800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.44672, 0, 0), +(150130, 6, 914.056, -514.092, 94.1168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.95722, 0, 0), +(150130, 7, 933.881, -510.408, 93.7115, 650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.757873, 0, 0), +(150130, 8, 914.056, -514.092, 94.1168, 900, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.95722, 0, 0), +(150130, 9, 885.222, -507.547, 96.8083, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.44672, 0, 0), +(150130, 10, 874.936, -490.813, 96.5369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.39961, 0, 0), +(150130, 11, 856.046, -498.303, 96.4667, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.87477, 0, 0), +(150130, 12, 832.623, -495.061, 99.9326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.13395, 0, 0), +(150130, 13, 805.777, -491.145, 100.066, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.22427, 0, 0); + +DELETE FROM creature_movement WHERE id = 150131; +INSERT INTO creature_movement VALUES +(150131, 1, 805.739, -497.472, 100.082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.062801, 0, 0), +(150131, 2, 832.259, -499.633, 99.4396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.14964, 0, 0), +(150131, 3, 856.072, -503.151, 96.2192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.098139, 0, 0), +(150131, 4, 872.407, -493.119, 96.5751, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.486912, 0, 0), +(150131, 5, 883.095, -510.27, 96.7952, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.59592, 0, 0), +(150131, 6, 912.72, -518.171, 94.1306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.21245, 0, 0), +(150131, 7, 934.545, -515.304, 93.676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.757852, 0, 0), +(150131, 8, 912.72, -518.171, 94.1306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.21245, 0, 0), +(150131, 9, 883.095, -510.27, 96.7952, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.59592, 0, 0), +(150131, 10, 872.407, -493.119, 96.5751, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.486912, 0, 0), +(150131, 11, 856.072, -503.151, 96.2192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.098139, 0, 0), +(150131, 12, 832.259, -499.633, 99.4396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.14964, 0, 0), +(150131, 13, 805.739, -497.472, 100.082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.062801, 0, 0); + +-- Stormpike Owl (with guard at the portal) (inside) +DELETE FROM creature_movement WHERE id = 150132; +INSERT INTO creature_movement VALUES +(150132, 1, 933.206, -510.991, 93.6726, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.62728, 0, 0), +(150132, 2, 913.451, -512.984, 94.1176, 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.01859, 0, 0), +(150132, 3, 885.755, -507.158, 96.8603, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.76334, 0, 0), +(150132, 4, 873.486, -490.438, 96.5269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.84883, 0, 0), +(150132, 5, 855.572, -499.047, 96.3765, 850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.51089, 0, 0), +(150132, 6, 832.773, -494.84, 99.9349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.12996, 0, 0), +(150132, 7, 804.467, -492.047, 99.9589, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.04812, 0, 0), +(150132, 8, 832.773, -494.84, 99.9349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.12996, 0, 0), +(150132, 9, 855.572, -499.047, 96.3765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.51089, 0, 0), +(150132, 10, 873.486, -490.438, 96.5269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.84883, 0, 0), +(150132, 11, 885.755, -507.158, 96.8603, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.76334, 0, 0), +(150132, 12, 913.451, -512.984, 94.1176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.01859, 0, 0), +(150132, 13, 933.206, -510.991, 93.6726, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.62728, 0, 0); + +DELETE FROM creature_movement WHERE id = 150133; +INSERT INTO creature_movement VALUES +(150133, 1, 935.529, -514.174, 93.7126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.67819, 0, 0), +(150133, 2, 912.428, -517.091, 94.1815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.94385, 0, 0), +(150133, 3, 882.2, -509.039, 96.6888, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.28942, 0, 0), +(150133, 4, 873.821, -493.884, 96.5937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.32083, 0, 0), +(150133, 5, 855.63, -502.782, 96.2429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.99252, 0, 0), +(150133, 6, 831.959, -499.144, 99.5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.9611, 0, 0), +(150133, 7, 803.852, -495.966, 99.9156, 300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.95387, 0, 0), +(150133, 8, 831.959, -499.144, 99.5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.9611, 0, 0), +(150133, 9, 855.63, -502.782, 96.2429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.99252, 0, 0), +(150133, 10, 873.821, -493.884, 96.5937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.32083, 0, 0), +(150133, 11, 882.2, -509.039, 96.6888, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.28942, 0, 0), +(150133, 12, 912.428, -517.091, 94.1815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.94385, 0, 0), +(150133, 13, 935.529, -514.174, 93.7126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.67819, 0, 0); + +-- Stormpike Batteguard (with owls on road) +DELETE FROM creature_movement WHERE id = 150095; +INSERT INTO creature_movement VALUES +(150095, 1, 394.125, -391.658, -1.24385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.16121, 0, 0), +(150095, 2, 372.264, -392.303, -0.461327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.03555, 0, 0), +(150095, 3, 305.513, -380.999, 0.189983, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.19263, 0, 0), +(150095, 4, 281.879, -387.997, 7.5677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.62852, 0, 0), +(150095, 5, 251.963, -413.568, 32.5684, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.83665, 0, 0), +(150095, 6, 227.322, -418.744, 39.1048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.21244, 0, 0), +(150095, 7, 141.642, -393.005, 42.4682, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.71745, 0, 0), +(150095, 8, 227.322, -418.744, 39.1048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.21244, 0, 0), +(150095, 9, 251.963, -413.568, 32.5684, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.83665, 0, 0), +(150095, 10, 281.879, -387.997, 7.5677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.62852, 0, 0), +(150095, 11, 305.513, -380.999, 0.189983, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.19263, 0, 0), +(150095, 12, 372.264, -392.303, -0.461327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.03555, 0, 0), +(150095, 13, 394.125, -391.658, -1.24385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.16121, 0, 0); + +-- Stormpike Owl (with guard on road) +DELETE FROM creature_movement WHERE id = 150128; +INSERT INTO creature_movement VALUES +(150128, 1, 393.981, -389.373, -1.24385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.32289, 0, 0), +(150128, 2, 372.66, -390.494, -0.353593, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.24199, 0, 0), +(150128, 3, 304.86, -379.432, 0.409832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.29148, 0, 0), +(150128, 4, 280.455, -386.222, 7.69883, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.64883, 0, 0), +(150128, 5, 250.705, -411.64, 32.7513, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.59778, 0, 0), +(150128, 6, 227.282, -416.73, 39.2124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.85479, 0, 0), +(150128, 7, 142.816, -391.591, 42.424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.55713, 0, 0), +(150128, 8, 227.282, -416.73, 39.2124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.85479, 0, 0), +(150128, 9, 250.705, -411.64, 32.7513, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.59778, 0, 0), +(150128, 10, 280.455, -386.222, 7.69883, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.64883, 0, 0), +(150128, 11, 304.86, -379.432, 0.409832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.29148, 0, 0), +(150128, 12, 372.66, -390.494, -0.353593, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.24199, 0, 0), +(150128, 13, 393.981, -389.373, -1.24385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.32289, 0, 0); + +DELETE FROM creature_movement WHERE id = 150129; +INSERT INTO creature_movement VALUES +(150129, 1, 394.327, -394.871, -1.03191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.23258, 0, 0), +(150129, 2, 371.606, -393.877, -0.495769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.80847, 0, 0), +(150129, 3, 305.275, -382.779, 0.168686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.00874, 0, 0), +(150129, 4, 282.644, -389.078, 7.58356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.59779, 0, 0), +(150129, 5, 252.351, -415.209, 32.8219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.47762, 0, 0), +(150129, 6, 226.657, -420.262, 39.1988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.80375, 0, 0), +(150129, 7, 140.372, -394.476, 42.6076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.51786, 0, 0), +(150129, 8, 226.657, -420.262, 39.1988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.80375, 0, 0), +(150129, 9, 252.351, -415.209, 32.8219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.47762, 0, 0), +(150129, 10, 282.644, -389.078, 7.58356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.59779, 0, 0), +(150129, 11, 305.275, -382.779, 0.168686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.00874, 0, 0), +(150129, 12, 371.606, -393.877, -0.495769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.80847, 0, 0), +(150129, 13, 394.327, -394.871, -1.03191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.23258, 0, 0); + +UPDATE `creature_template` SET `MinLevelHealth` = 4100 WHERE `entry` = 14284; diff --git a/sql_mr/mr00249_mangos_arena_honor.sql b/sql_mr/mr00249_mangos_arena_honor.sql new file mode 100644 index 0000000000..288636df60 --- /dev/null +++ b/sql_mr/mr00249_mangos_arena_honor.sql @@ -0,0 +1,4 @@ +-- npc arena-honor exchange +DELETE FROM creature_template WHERE entry = 7; +INSERT INTO creature_template (Entry, Name, SubName, IconName, MinLevel, MaxLevel, DifficultyEntry1, DifficultyEntry2, DifficultyEntry3, ModelId1, ModelId2, ModelId3, ModelId4, FactionAlliance, FactionHorde, Scale, Family, CreatureType, InhabitType, RegenerateStats, RacialLeader, NpcFlags, UnitFlags, DynamicFlags, ExtraFlags, CreatureTypeFlags, SpeedWalk, SpeedRun, UnitClass, Rank, Expansion, HealthMultiplier, PowerMultiplier, DamageMultiplier, DamageVariance, ArmorMultiplier, ExperienceMultiplier, MinLevelHealth, MaxLevelHealth, MinLevelMana, MaxLevelMana, MinMeleeDmg, MaxMeleeDmg, MinRangedDmg, MaxRangedDmg, Armor, MeleeAttackPower, RangedAttackPower, MeleeBaseAttackTime, RangedBaseAttackTime, DamageSchool, MinLootGold, MaxLootGold, LootId, PickpocketLootId, SkinningLootId, KillCredit1, KillCredit2, QuestItem1, QuestItem2, QuestItem3, QuestItem4, QuestItem5, QuestItem6, MechanicImmuneMask, ResistanceHoly, ResistanceFire, ResistanceNature, ResistanceFrost, ResistanceShadow, ResistanceArcane, PetSpellDataId, MovementType, MovementTemplateId, TrainerType, TrainerSpell, TrainerClass, TrainerRace, TrainerTemplateId, VendorTemplateId, EquipmentTemplateId, VehicleTemplateId, GossipMenuId, AIName, ScriptName) VALUES +('7', 'Besdoban Durnoye', 'Arena-Honor Exchange', null, '59', '61', '0', '0', '0', '17858', '0', '17858', '0', '35', '35', '1', '0', '7', '3', '3', '0', '1', '0', '0', '0', '0', '1.48', '1.14286', '2', '0', '-1', '0', '1', '1.4', '1', '1', '1', '6700', '24000', '5598', '5875', '91', '137', '73', '110', '4009', '34', '27', '1400', '1400', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '', 'npc_arena_honor'); diff --git a/sql_mr/mr00249_mangos_vault_of_archavon.sql b/sql_mr/mr00249_mangos_vault_of_archavon.sql new file mode 100644 index 0000000000..86d613b488 --- /dev/null +++ b/sql_mr/mr00249_mangos_vault_of_archavon.sql @@ -0,0 +1,13 @@ +UPDATE `creature_template` SET `ScriptName`='boss_archavon' WHERE `entry`=31125; +UPDATE `creature_template` SET `ScriptName`='boss_emalon' WHERE `entry`=33993; +UPDATE `creature_template` SET `ScriptName`='npc_tempest_minion' WHERE `entry`=33998; +UPDATE `creature_template` SET `ScriptName`='npc_tempest_warder' WHERE `entry`=34015; +UPDATE `creature_template` SET `ScriptName`='boss_koralon' WHERE `entry`=35013; +UPDATE `creature_template` SET `AIName`='', ScriptName='boss_toravon' WHERE `entry`=38433; +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=38433); + +UPDATE `instance_template` SET `ScriptName`='instance_vault_of_archavon' WHERE `map`=624; +DELETE FROM `spell_script_target` WHERE `entry` IN (72034,72096); -- this cause drop (72034, 1, 38439),(72034, 1, 38461),(72096, 1, 38439),(72096, 1, 38461) from YTDB +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(72034,1,38433), +(72096,1,38433); diff --git a/sql_mr/mr00249_scriptdev2_eye_of_eternity.sql b/sql_mr/mr00249_scriptdev2_eye_of_eternity.sql new file mode 100644 index 0000000000..bf02571c69 --- /dev/null +++ b/sql_mr/mr00249_scriptdev2_eye_of_eternity.sql @@ -0,0 +1,41 @@ +-- Eye of Eternity +-- russian translation from lanc +/* +DELETE FROM `script_texts` where `entry` between -1616035 and -1616000; +REPLACE INTO `script_texts` (entry, content_default, content_loc1, content_loc2, content_loc3, content_loc4, content_loc5, content_loc6, content_loc7, content_loc8, sound, type, language, emote, comment) VALUES +(-1616000, 'Lesser beings, intruding here! A shame that your excess courage does not compensate for your stupidity!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Низшие создания, вторгшиеся сюда! Как жаль что ваш ум не так силен как ваша храбрость!', '14512', '1', '0', '1', NULL), +(-1616001, 'None but the blue dragonflight are welcome here! Perhaps this is the work of Alexstrasza? Well then, she has sent you to your deaths.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Никому кроме синих драконов не позволено находится здесь! Возможно, это происки Алекстразы? Что ж, значит она послала вас на верную смерть.', '14513', '1', '0', '1', NULL), +(-1616002, 'What could you hope to accomplish, to storm brazenly into my domain? To employ MAGIC? Against ME? ', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'А что вы планировали, беспардонно ворваться в мои владения? Использовать МАГИЮ? Против МЕНЯ?', '14514', '1', '0', '457', NULL), +(-1616003, 'I am without limits here... the rules of your cherished reality do not apply... In this realm, I am in control...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Здесь меня ничто не ограничивает... Законы вашей драгоценной реальности тут неприменимы... В этом мире Я главный...', '14515', '1', '0', '1', NULL), +(-1616004, 'I give you one chance. Pledge fealty to me, and perhaps I won''t slaughter you for your insolence!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я дам вам шанс. Присягните на верность мне и, может быть, я не уничтожу вас за вашу наглость!', '14516', '1', '0', '1', NULL), +(-1616005, 'My patience has reached its limit, I WILL BE RID OF YOU!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Мое терпение лопнуло, ПОРА ОТ ВАС ИЗБАВИТЬСЯ!', '14517', '1', '0', '1', NULL), +(-1616006, 'Watch helplessly as your hopes are swept away...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Смотрите беспомощно, как утекают ваши надежды...', '14525', '1', '0', '1', NULL), +(-1616007, 'I AM UNSTOPPABLE!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'МЕНЯ НЕ ОСТАНОВИТЬ!', '14533', '1', '0', '1', NULL), +(-1616008, 'Your stupidity has finally caught up to you!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Ну вот ты и встретился со своей глупостью!', '14519', '1', '0', '1', NULL), +(-1616009, 'More artifacts to confiscate...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Еще один экспонат для моей коллекции...', '14520', '1', '0', '1', NULL), +(-1616010, ' How very... naive...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Мха! Ха! Ха! Ха!Ха! Ха! Так... наивно...', '14521', '1', '0', '1', NULL), +(-1616012, '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!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я надеялся быстро с вами покончить, но вы оказались более... живучими, чем я ожидал. Тем не менее, все ваши попытки тщетны, это вы безрассудные, беспечные, смертные, вы виноваты в этой войне! Я сделаю то что я должен сделать... Если это потребует вашего полного уничтожения... ДА БУДЕТ ТАК!', '14522', '1', '0', '1', NULL), +(-1616013, 'Few have experienced the pain I will now inflict upon you!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Немногие испытывали боль, подобной той, что я сейчас причиню вам!', '14523', '1', '0', '1', NULL), +(-1616014, 'YOU WILL NOT SUCCEED WHILE I DRAW BREATH!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '', '14518', '1', '0', '1', NULL), +(-1616015, 'Malygos takes a deep breath...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '', '0', '3', '0', '1', NULL), +(-1616016, 'I will teach you IGNORANT children just how little you know of magic...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я покажу вам, МАЛОГРАМОТНЫМ детям, как мало вы знаете о магии...', '14524', '1', '0', '1', NULL), +(-1616017, 'ENOUGH! If you intend to reclaim Azeroth magic, then you shall have it...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Хватит! Раз вы хотите магии Азерота, то вы ее получите...', '14529', '1', '0', '1', NULL), +(-1616018, 'Now your benefactors make their appearance...But they are too late. The powers contained here are sufficient to destroy the world ten times over! What do you think they will do to you?', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вот и ваши благодетели появились... Но слишком поздно. Сил находящихся здесь хватит чтобы разрушить этот мир десять раз подряд! А что вы думаете они сделают с вами?', '14530', '1', '0', '1', NULL), +(-1616019, 'SUBMIT!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'СДАВАЙТЕСЬ!', '14531', '1', '0', '1', NULL), +(-1616020, 'Your energy will be put to good use!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Твою энергию используют по назначению!', '14526', '1', '0', '1', NULL), +(-1616021, 'I AM THE SPELL-WEAVER! My power is INFINITE!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Я ХРАНИТЕЛЬ МАГИИ! Моя сила БЕЗГРАНИЧНА!', '14527', '1', '0', '1', NULL), +(-1616022, 'Your spirit will linger here forever!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Твой дух будет вечно скитаться здесь!', '14528', '1', '0', '1', NULL), +(-1616023, 'Alexstrasza! Another of your brood falls!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Алекстраза! Еще один из твоих пал!', '14534', '1', '0', '1', NULL), +(-1616024, 'Little more then gnats!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Чуть больше комара!', '14535', '1', '0', '1', NULL), +(-1616025, 'Your red allies will share your fate...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Твоих красных союзников ждет таже участь...', '14536', '1', '0', '1', NULL), +(-1616026, 'The powers at work here exceed anything you could possibly imagine!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вам не хватит воображения, чтобы оценить мощь сил, задействованных здесь!', '14532', '1', '0', '1', NULL), +(-1616027, 'Still standing? Not for long...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Еще на ногах? Ненадолго...', '14537', '1', '0', '1', NULL), +(-1616028, 'Your cause is lost!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Вы проиграли!', '14538', '1', '0', '1', NULL), +(-1616029, 'Your fragile mind will be shattered!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Ваш хрупкий разум будет сокрушен!', '14539', '1', '0', '1', NULL), +(-1616030, 'UNTHINKABLE! The mortals will destroy... e-everything... my sister... what have you-', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'НЕВЕРОЯТНО! Смертные разрушат... Все... Сестра моя... Что ты...', '14540', '1', '0', '1', NULL), +(-1616031, 'I did what I had to, brother. You gave me no alternative.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '', '14406', '1', '0', '1', NULL), +(-1616032, 'And so ends the Nexus War.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Война Нексуса окончена.', '14407', '1', '0', '1', NULL), +(-1616033, '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 mightiest has fallen.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Итоги войны черезмерно печалят меня, но разрушения и колоссальные потери жизней должны были быть остановлены. Несмотря на последние прегрешения Малигоса, Я буду оплакивать его. Когда-то он был заступником, защитником. Сегодня пал один из сильнейших этого мира!', '14408', '1', '0', '1', NULL), +(-1616034, '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.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Красные драконы возьмут на себя бремя заживления ран Азерота. Возвращайтесь домой к своим людям и отдохните. Будущее несет вам новые испытания, и вы должны быть готовы к ним. Жизнь... Продолжается.', '14409', '1', '0', '1', NULL), +(-1616035, 'A Power Spark forms from a nearby rift!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '', '0', '3', '0', '1', NULL); +*/ \ No newline at end of file diff --git a/sql_mr/mr00262_scriptdev2_culling_of_stratholme.sql b/sql_mr/mr00262_scriptdev2_culling_of_stratholme.sql new file mode 100644 index 0000000000..4a6cf4fa47 --- /dev/null +++ b/sql_mr/mr00262_scriptdev2_culling_of_stratholme.sql @@ -0,0 +1,217 @@ +REPLACE INTO script_texts (entry, content_default, content_loc8, sound, type, language, emote, comment) VALUES +-- TAVERN EVENT +(-1597270, 'Hey! Stop rooting around down there in my cellar! Clear out!', 'Эй! А ну, хорош рыться в моей кладовке! Проваливайте!', 0,0,0,1, '34587'), +(-1597271, 'This whole situation seems a bit paranoid, don\'t you think?', 'По-моему, все это сильно смахивает на паранойю, вы не находите?', 0,0,0,25, '34587'), +(-1597272, 'Orders are orders, if prince says jump...', 'Приказ есть приказ. Если принц говорит прыгать...', 0,0,0,1, '34587'), +(-1597273, 'It\'s a strange order, you can not deny Suspicious food? Under that definition, you should arrest the chef Michael!', 'Странный приказ, что верно, то верно. Подозрительная пища? Тогда уж и Белфаста арестовывайте!', 0,0,0,1, '34587'), +(-1597274, 'I HEARD THAT! No more ale for you! Not a drop!', 'Я ВСЕ СЛЫШАЛ! Больше эля ты не получишь! Ни капли!', 0,0,0,25, '34587'), +(-1597275, 'Enough, Michael. Business is hurting enough with this scare as it is. We can use every copper.', 'Довольно, Майкл. Наши дела и так страдают из-за этой угрозы. Сейчас каждый медяк на счету.', 0,0,0,274, '34587'), +(-1597276, 'The soldiers are doing important work. The safely of the people is more important, now, if you\'re interested in your customers living to spend another day.', 'Солдаты заняты очень важным делом, Мал. Если ты хочешь, чтобы твои покупатели дожили до завтрашнего дня - надо обеспечить их безопасность.', 0,0,0,1, '34587'), +(-1597277, 'I can\'t argue with that.', 'С этим не поспоришь.', 0,0,0,1, '34587'), +(-1597278, 'Don\'t worry too much. By the time I went off duty, we had not found a scrap of befouled grain here.', 'Не стоит так сильно волноваться. К тому времени, как я сдал пост, мы не нашли здесь и следа этого мерзского зерна.', 0,0,0,274, '34587'), +(-1597279, 'Thank the Light for that.', 'Скажи спасибо Свету.', 0,0,0,1, '34587'), +-- ROGER EVENT +(-1597280, 'Wait, what\'s that smell?', 'Стоп, что за вонь?', 0,0,0,1, '34587'), +(-1597281, 'Can\'t be me, I took a bath 3 days ago!', 'Это не от меня, я мылся 3 дня назад!', 0,0,0,1, '34587'), +(-1597282, 'Oh, close call. It\'s just the grain here.', 'О, это всего лишь зерно.', 0,0,0,1, '34587'), +(-1597283, 'Wait a second. Grain isn\'t supposed to smell like THAT! I better go find a guard.', 'Погоди. Зерно не может ТАК вонять! Я лучше пойду поищу стражника.', 0,0,0,1, '34587'), +-- MORIGAN EVENT +(-1597284, 'You don\'t mind me checking out your merchandise for signs of tampering, do you?', 'Вы же не возражаете, чтобы я проверил ваши товары?', 0,0,0,1, '34587'), +(-1597285, 'No, sir.', 'Нет, сэр.', 0,0,0,1, '34587'), +(-1597286, 'Wait, what is it? Youve been holding out on me, Perelli!', 'Подождите-ка, что это? Ты скрывал это от меня, Перелли!', 0,0,0,0, '34587'), +(-1597287, 'What are you talking about, Sergeant?', 'О чем вы говорите, сержант?', 0,0,0,1, '34587'), +(-1597288, 'I am confiscating this suspicious grain, Perelli. We were looking for signs of tampered food, and it would be in your best interest to stay put while Prince Arthas checks this out.', 'Я конфискую это подозрительное зерно, Перелли. Мы искали признаки подозрительной еды, и было бы в твоих лучших интересах оставаться на месте, пока принц Артас разбирается в происходящем.', 0,0,0,1, '34587'), +(-1597289, 'You have to belive me, I am innocent!', 'Вы должны верить мне, я не виновен!', 0,0,0,20, '34587'), +(-1597290, 'Well see about that. Perelli. Well see about that.', 'Это мы посмотрим, Перелли. Это мы посмотрим.', 0,0,0,1, '34587'), +-- JENA EVENT +(-1597291, 'Martha. I am out of flour for bread. You wouldn\'t happen to have any grain from that recent, would you?', 'Марта, я не нашла у себя муки для выпечки хлеба. Вы не одолжите мне зерна?', 0,0,0,1, '34587'), +(-1597292, 'Oh hello, Jena. Of Course you can borrow some grain. Help yourself.', 'О, привет Джена. Конечно я одолжу вам зерна. Возьмите сами.', 0,0,0,1, '34587'), +(-1597293, 'Thanks. Martha! I owe you one.', 'Спасибо. Марта! Я твоя должница.', 0,0,0,1, '34587'), +(-1597294, 'Martha, somethings wrong with this grain! Some of the Princes soldiers were looking for this. Im going to go look for one.', 'Марта, с этим зерном что-то не так! Солдаты Принца что-то говорили о нем. Пойду-ка поищу кого-нибудь из них.', 0,0,0,1, '34587'), +(-1597295, 'Oh, my.', 'Боже мой.', 0,0,0,1, '34587'), +-- MALCOLM EVENT +(-1597296, 'Looks like a storms coming in, Scruffy...', 'Похоже на приближающуюся бурю, Лохмач...', 0,0,0,0, '34587'), +(-1597297, 'Whats wrong, pal?', 'Что случилось, друг?', 0,0,0,1, '34587'), +(-1597298, 'What did you find, boy?', 'Что ты нашел, парень?', 0,0,0,0, '34587'), +(-1597299, 'This is no good, Scruffy. Stay here and guard the house. I need to go find a soldier.', 'Выглядит плохо, Лохмач. Стой тут и охраняй дом, а я пока сбегаю - поищу солдат.', 0,0,0,0, '34587'), +-- BARTLEBY EVENT +(-1597300, 'I knew I should have secured the wagon lock better when I was in Andorhal.', 'Надо было получше запереть фургон в Андорале.', 0,0,0,1, '34587'), +(-1597301, 'This grain shipmend has been nothing but trouble!', 'От этого зерна пока одни лишь хлопоты!', 0,0,0,1, '34587'), +(-1597302, 'Well, guess I should load everything back into the cart.', 'Ну, наверное, мне нужно сложить все обратно в телегу.', 0,0,0,0, '34587'), +(-1597303, 'Oh, come on! My cart broke, my horse throws a shoe, and now the cargo goes bad!', 'О, черт! Моя телега сломалась, моя лошадь потеряла подкову, а теперь еще и с грузом проблемы!', 0,0,0,1, '34587'), +(-1597304, 'I guess I\'ll go find the authorites. If I\'m lucky theyll tell me it\'s the plague and that were all to die!', 'Похоже, мне придется идти искать представителей закона. Если мне повезет, они скажут, что это чума и что скоро мы все умрем!', 0,0,0,1, '34587'), +-- ARTHAS INTRO EVENT +(-1594071, 'Glad you could make it, Uther.', 'Я рад, что ты пришел, Утер!', 12828,0,0,1, '34587'), +(-1594072, 'Watch your tone with me boy. You may be the prince, but I am still your superior as a paladin!', 'Следи за своим тоном, юноша. Хоть ты и принц, но, как паладин, ты все еще находишься под моим командованием.', 12839,0,0,25, '34587'), +(-1594073, 'As if I could forget. Listen, Uther, there\'s something about the plague you should know...', 'Как будто я не помню. Послушай, Утер, я должен рассказать тебе кое-что про чуму...', 12829,0,0,0, '34587'), +(-1594074, 'Oh, no. Were too late. These people have all been infected! They may look fine now, but it\'s just a matter of time before they turn into the undead!', 'О нет. Мы опоздали. Все эти люди заражены чумой! Сейчас это еще незаметно, но скоро все они превратятся в нежить!', 12830,0,0,1, '34587'), +(-1594075, 'What?', 'Что?', 12840,0,0,5, '34587'), +(-1594076, 'This entire city must be purged.', 'Весь город должен быть очищен.', 12831,0,0,1, '34587'), +(-1594077, 'How can you even consider that? There\'s got to be some other way.', 'Как ты мог даже подумать об этом?! Должен быть какой-то другой путь!', 12841,0,0,1, '34587'), +(-1594078, 'Damn it, Uther! As your future king, I order you to purge this city!', 'Проклятие, Утер! Как будущий король, я приказываю тебе очистить этот город!', 12832,1,0,5, '34587'), +(-1594079, 'You are not my king yet, boy! Nor would I obey that command even if you were!', 'Пока ты еще не король, юноша. Но этот приказ я не выполнил бы, будь ты хоть трижды королем!', 12842,1,0,22, '34587'), +(-1594080, 'Then I must consider this an act of treason.', 'Тогда я буду расценивать это как измену.', 12833,0,0,0, '34587'), +(-1594081, 'Treason? Have you lost your mind, Arthas?', 'Измену? Ты совсем лишился рассудка, Артас?', 12843,0,0,5, '34587'), +(-1594082, 'Have I? Lord Uther, by my right of succession and the sovereignty of my crown, I hereby relieve you of your command and suspend your paladins from service.', 'Неужели? Лорд Утер, властью, данной мне по праву наследования, я отстраняю вас от командования и освобождаю от службы ваших паладинов.', 12834,0,0,1, '34587'), +(-1594083, 'Arthas! You cant just...', 'Артас! Ты не можешь так просто...', 12837,0,0,1, '34587'), +(-1594084, 'It\'s done! those of you who have the will to save this land, follow me! The rest of you... get out of my sight!', 'Это уже сделано! Те из вас, кто действительно хочет спасти эту землю - за мной! Остальные - прочь с глаз моих!', 12835,0,0,0, '34587'), +(-1594085, 'You\'ve just crossed a terrible threshold, Arthas!', 'Ты пересек опасную черту, Артас.', 12844,0,0,25, '34587'), +(-1594086, 'Jaina?', 'Джайна?', 12836,0,0,1, '34587'), +(-1594087, 'Im sorry Arthas. I can\'t watch you do this.', 'Прости, Артас. Я не могу на это смотреть.', 12838,0,0,1, '34587'), +(-1594088, 'Take position here and I will lead a small force inside Stratholme to begin the culling. We must contain and purge the infected for the sake of all of Lordaeron!', 'Займите позицию, а я поведу небольшой отряд в Стратхольм и начну очищение. Мы должны изолировать и уничтожить зараженных жителей ради всего Лордерона!', 14327,1,0,1, '34587'), +-- ARTHAS ENTER IN THE CITY +(-1594089, 'Everyone looks ready. Remember, these people are all infected with the plague and will die soon. We must purge Stratholme to protect the remainder of Lordaeron from the Scourge. Lets go!', 'Похоже, все готовы. Помните, эти люди заражены чумой и скоро умрут. Мы должны очистить Стратхольм и защитить Лордерон от Плети. Вперед.', 14293,0,0,1, '26499'), +(-1594090, 'Prince Arthas, may the light be praised. Many people in the town have begun to fall seriously ill. Can you help us?', 'Принц Артас, слава Свету! Многие горожане серьезно больны. Можете ли вы помочь нам?', 0,0,0,1, '26499'), +(-1594091, 'I can help you only with a clean death.', 'Я могу помочь вам лишь быстрой смертью.', 14294,0,0,0, '26499'), +(-1594092, 'What? This cant be!', 'Что? Этого не может быть!', 0,0,0,0, '26499'), +(-1594093, 'Oh... My g...', 'О... Мой б...', 0,0,0,0, '26499'), +(-1594094, 'This is begining!', 'Это было только начало.', 14295,0,0,1, '26499'), +(-1594095, 'Yes, this is the beginning. I\'ve been waiting for you, young prince. I am Mal\'Ganis.', 'Да, это начало. Я ждал тебя, юный принц. Я Мал\'Ганис.', 14410,0,0,1, '26499'), +(-1594096, 'As you can see, your people are now mine. I will now turn this city, household by household, until the flame of life has been snuffed out forever.', 'Как видишь, твои люди отныне принадлежат мне. Дом за домом я порабощу этот город, и огонь жизни угаснет здесь навсегда...',14411,0,0,1, '26499'), +(-1594097, 'I will not allow this, Mal\'Ganis. Better these people will die from my hand, than become your slaves after death.', 'Я не допущу этого, Мал\'Ганис! Лучше эти люди погибнут от моей руки, чем станут твоими рабами после смерти!',14296,0,0,5, '26499'), +(-1594098, 'Mal\'Ganis will send his Scourge henchmen to meet us. Skilled warriors and mages go and destroy enemies. I will lead the remaining troops in the purification of Stratholme from infection.', 'Мал\'Ганис отправит своих прислужников из Плети навстречу нам. Опытные воины и маги, ступайте и уничтожьте врагов. Я возглавлю оставшиеся войска в деле очищения Стратхольма от заразы.',14885,0,0,1, '26499'), +-- MEATHOOK +(-1594110, 'Play time!', 'Поиграем!',13428,0,0,0, '26499'), +(-1594111, 'New toys!', 'Новые игрушки!',13429,1,0,0, '26499'), +(-1594112, 'This not fun...', 'Это не смешно...',13433,1,0,0, '26499'), +(-1594113, 'Boring...', 'Скучно...',13430,1,0,0, '26499'), +(-1594114, 'Why you stop moving?', 'Почему ты не двигаться?',13431,1,0,0, '26499'), # ! +(-1594115, 'Get up! Me not done!', 'Вставай! Я не закончил!',13432,1,0,0, '26499'), # ! +-- SALRAMM +(-1594129, 'You are too late, champion of Lordaeron. The dead shall have their day.', 'Слишком поздно, герой Лордерона! Пришло время мертвых.',0,1,0,0, '26499'), +(-1594130, 'Ah, the entertainment has arrived!', 'А, развлечемся!',0,1,0,0, '26499'), +(-1594131, 'You only advance... the master\'s plan...', 'Вы всего лишь часть плана хозяина...',0,1,0,0, '26499'), +(-1594132, 'The fun is just beginning!', 'Веселье только начинается!',0,1,0,0, '26499'), +(-1594133, 'Aah, quality materials!', 'Аааа, качественный материал...',0,1,0,0, '26499'), +(-1594134, 'Don\'t worry, I\'ll make good use of you.', 'Не волнуйся, я найду куда тебя приспособить...',0,1,0,0, '26499'), +(-1594135, 'I want a sample...', 'Мне нужен образец!',0,1,0,0, '26499'), +(-1594136, 'Such strength... it must be mine!', 'Столько силы... Она будет моей....',0,1,0,0, '26499'), +(-1594137, 'Your flesh betrays you.', 'Твоя плоть предает тебя!',0,1,0,0, '26499'), +(-1594138, 'Say hello to some friends of mine.', 'Познакомтесь с моими друзьями...',0,1,0,0, '26499'), +(-1594139, 'Come, citizen of Stratholme! Meet your saviors.', 'Жители Стратхольма, встречайте ваших спасителей...',0,1,0,0, '26499'), +(-1594140, 'BOOM! Hahahahah...', 'Бум... Ха-ха-ха-ха...',0,1,0,0, '26499'), +(-1594141, 'Blood... destruction... EXHILARATING!', 'Кровь... Разрушение... Восхитительно...',0,1,0,0, '26499'), +-- ARTHAS - HOUSE +(-1594142, 'Heroes, hurry up, we\'ll meet near town hall. We must fight with Mal\'Ganis on its territory!', 'Герои, поспешите, встретимся у городской ратуши. Мы должны сразиться с Мал\'Ганисом на его территории!',14297,1,0,0, '26499'), +(-1594143, 'Follow me, I know the way.', 'Идите за мной. Я знаю дорогу.',14298,0,0,1, '26499'), +(-1594144, 'Ah, You\'ve finaly arrived, Prince Arthas. You\'re here just in the nick of time.', 'О, вы наконец-то прибыли, принц Артас. Вы едва успели.',0,0,0,1, '26499'), +(-1594145, 'Yes! I\'m glad to get here before plague!', 'Да! Я рад, что смог добраться сюда раньше чумы.',14299,0,0,1, '26499'), +(-1594146, 'What kind of magic is this?', 'Что это за магия?',14300,0,0,0, '26499'), +(-1594147, 'Theres no need for you in understand Arthas. All you need to do is die!', 'Тебе и не надо этого понимать, Артас. Все, что от тебя требуется – это умереть.',0,0,0,11, '26499'), +(-1594148, 'Seems that Mal\'Ganis has something else except Scourge. Let\'s hurry.', 'Кажется у Мал\'Ганиса в распоряжении есть еще кое что кроме Плети. Давайте поспешим.',14301,0,0,0, '26499'), +(-1594149, 'Dark magic again... Be ready for all.', 'Снова черная магия... Будьте готовы ко всему!',14302,0,0,0, '26499'), +(-1594150, 'Come on.', 'Идем дальше.',14303,0,0,0, '26499'), +(-1594151, 'Be on the alert. We were surrounded.', 'Будьте начеку. Нас окружили.',14304,0,0,0, '26499'), +(-1594152, 'Mal\'Ganis doesn\'t want to make our life easier...', 'Мал\'Ганис не собирается облегчить нам жизнь.',14305,0,0,0, '26499'), +(-1594153, 'They are stubborn.', 'Они упрямы.',14306,0,0,0, '26499'), +(-1594154, 'What else will he put in my way?', 'Что еще он поставит у меня на пути?',14307,0,0,0, '26499'), +(-1594155, 'Prince Arthas Menethil, in this day mighty evil devoured your soul. Death, which you had to bring to others, today will come for you.', 'Принц Артас Менетил, в этот самый день могущественное зло поглотило твою душу. Смерть, которую ты должен был принести другим, сегодня придет за тобой.',13408,0,0,0, '26499'), +(-1594156, 'I do for Lordaeron that should, and words and deeds will not stop me.', 'Я делаю для Лордерона то, что должен, и никакие слова и поступки меня не остановят.',14309,0,0,5, '26499'), +(-1594157, 'Let\'s see, young prince...', 'Ну что ж, посмотрим, юный принц.',13409,0,0,0, '26499'), +-- Epoch +(-1594119, 'We\'ll see about that, young prince.', 'Поcмотрим, молодой принц.',13416,0,0,0, '26499'), +(-1594120, 'There is no future for you.', 'У тебя нет будущего...',13413,1,0,0, '26499'), +(-1594121, 'This is the hour of our greatest triumph!', 'Пробил час нашего величайшего триумфа..',13414,1,0,0, '26499'), +(-1594122, 'You were destined to fail.', 'Тебе было суждено потерпеть поражение...',13415,1,0,0, '26499'), +(-1594123, 'Tick tock, tick tock...', 'Тик-так... Тик-так...',13410,1,0,0, '26499'), +(-1594124, 'Not quick enough!', 'Слишком медленно...',13411,1,0,0, '26499'), +(-1594125, 'Let\'s get this over with.', 'Пора заканчивать...',13412,1,0,0, '26499'), +-- Street +(-1594158, 'It will take not much time.', 'Это займет совсем немного времени.',14310,0,0,0, '26499'), +(-1594159, 'Thanks Light, backdoor still works!', 'Слава Свету, что потайной ход еще работает.',14311,0,0,0, '26499'), +(-1594160, 'Let\'s pass through this area as soon as possible. If we do not perish from the undead, we can die from this fire.', 'Давайте пройдем этот участок как можно быстрее. Если мы не погибнем от нежити, то можем погибнуть от этого огня.',14312,0,0,0, '26499'), +(-1594161, 'Breather a little bit, but keep in mind, we will soon again in the path.', 'Отдышитесь немного. Но имейте в виду, нам скоро снова в путь.',14313,0,0,0, '26499'), +(-1594162, 'The rest is over, let\'s go. Mal\'Ganis waits.', 'Отдых окончен, надо идти. Мал\'Ганис ждет.',14314,0,0,0, '26499'), +(-1594163, 'Finally, we even like that lucky! The fire has not yet reached the commercial area. Mal\'Ganis should be in Square of Knights, which is not far from here. Tell me when you\'re ready to go.', 'Наконец нам хоть как-то повезло. Огонь еще не добрался до Торгового ряда. Мал\'Ганис должен быть на Площади рыцарей, которая находится недалеко отсюда. Скажите мне, как будете готовы идти дальше.',14315,0,0,0, '26499'), +(-1594164, 'Let\'s justice will be here.', 'Да свершится правосудие.',14316,0,0,0, '26499'), +-- malganis +(-1594170, 'This will be a fine test, Prince Arthas.', 'Это будет достойное испытание, принц Артас.',14413,1,0,0, '26499'), +(-1594171, 'All too easy.', 'Слишком просто...',14416,1,0,0, '26499'), +(-1594172, 'The dark lord is displeased with your interference.', 'Темный повелитель не доволен твоим вмешательством...',14417,1,0,0, '26499'), +(-1594173, 'It is Prince Arthas I want, not you.', 'Мне нужен Принц Артас, а не ты...',14418,1,0,0, '26499'), +(-1594174, 'Anak\'Keri...', 'Анак Кири...',14422,1,0,0, '26499'), +(-1594175, 'My onslaught will wash over the Lich King\'s forces...', 'Мой натиск сметет силы Короля-Лича...',14423,1,0,0, '26499'), +(-1594176, 'Your death is in vain, tiny mortal...', 'Твоя смерть была напрасна насекомое...',14424,1,0,0, '26499'), +(-1594177, 'Your time has come to an end!', 'Твое время вышло...',14425,1,0,0, '26499'), +(-1594178, '*Struggling sounds* I spent too much time in that weak little shell...', 'Аррррхххх... Я и так провел слишком много времени в этой слабой оболочке...',14426,1,0,0, '26499'), +(-1594179, 'I AM MAL\'GANIS! I AM ETERNAL!', 'Ирл Нарат... Я Мал\'Ганис.... Я вечен...',14427,1,0,0, '26499'), +(-1594180, 'You\'ll never defeat the Lich King without my forces! I\'ll have my revenge...on him, AND you...', 'Тебе никогда не победить короля - лича без моих войск! Я отомщу и тебе и ему...',14429,1,0,0, '26499'), +(-1594181, 'We\'re going to finish this right now, Mal\'Ganis!', 'Мы покончим с этим сейчас же, Мал\'Ганис. Один на один.',14317,0,0,0, '26499'), +(-1594182, 'Your journey has just begun, young prince. Gather your forces, and meet me in the arctic land of Northrend. It is there we shall settle the score between us. It is there that your true destiny will unfold.', 'Твое путешествие начинается, юный принц. Собирай свои войска и отправляйся в царство вечных снегов, в Нордскол. Там мы и уладим все наши дела, там ты узнаешь свою судьбу.',14412,0,0,0, '26499'), +(-1594183, '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,1,0,5, '26499'), +(-1594184, '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,5, '26499'), +(-1594185, 'Time out...', 'Отдохни!',14414,1,0,0, '26499'), +(-1594186, 'You seem tired.', 'Ты выглядишь усталым!',14415,1,0,0, '26499'), +(-1594187, 'ENOUGH! I waste my time here...I must gather my strength on the home world...', 'Я лишь зря трачу тут свое время. Мне нужно собраться силами в моем родном мире.',14428,1,0,0, '26499'); + +-- for official Sd2 --> DB clean up query +DELETE FROM gossip_texts WHERE entry BETWEEN -3595005 AND -3595000; + +DELETE FROM script_waypoint WHERE entry=26528; +DELETE FROM script_waypoint WHERE entry=26499; +INSERT INTO script_waypoint VALUES +-- Uther + (26528, 0, 1772.707,1263.927,138.867, 0, 'WP1'), + (26528, 1, 1810.249,1276.557,141.854, 0, 'WP2'), + (26528, 2, 1810.249,1276.557,141.854, 0, 'WP3'), + (26528, 3, 1851.476,1281.370,144.106, 0, 'WP4 - Arthas Move'), + (26528, 4, 1898.716,1288.757,143.461, 90000, 'WP5 - Pause Escort'), + (26528, 5, 1851.476,1281.370,144.106, 0, 'WP6'), + (26528, 6, 1794.357,1272.183,140.558, 0, 'WP7 - Uther Despawn'), +-- Arthas + (26499, 0, 1902.959,1295.127,143.388, 0, 'WP1'), + (26499, 1, 1916.657,1287.327,141.946, 0, 'WP2'), + (26499, 2, 1913.726,1287.407,141.927, 10000, 'WP3 - Dialog'), + (26499, 3, 1990.833,1293.391,145.467, 0, 'WP4'), + (26499, 4, 1997.003,1317.776,142.963, 0, 'WP5'), + (26499, 5, 2019.631,1326.084,142.929, 0, 'WP6'), + (26499, 6, 2026.469,1287.088,143.596, 0, 'WP7'), + (26499, 7, 2054.879,1287.505,142.422, 0, 'WP8'), + (26499, 8, 2050.660,1287.333,142.671, 0, 'WP9 - Pause Escort'), + (26499, 9, 2050.652,1287.382,142.672, 12000, 'WP10'), + (26499, 10, 2081.447,1287.770,141.324, 2000, 'wp11'), + (26499, 11, 2099.876,1280.210,138.550, 0, 'WP12'), + (26499, 12, 2120.757,1286.970,136.343, 0, 'WP13'), + (26499, 13, 2165.073,1279.338,133.400, 0, 'WP14'), + (26499, 14, 2186.441,1234.445,136.524, 0, 'WP15'), + (26499, 15, 2210.385,1207.550,136.259, 0, 'WP16'), + (26499, 16, 2243.594,1177.705,137.144, 0, 'WP17'), + (26499, 17, 2286.883,1177.262,137.631, 0, 'WP18'), + (26499, 18, 2320.374,1179.954,133.926, 0, 'WP19'), + (26499, 19, 2354.626,1192.099,130.535, 0, 'WP20'), + (26499, 20, 2363.374,1194.101,131.414, 0, 'WP21 - pause'), + (26499, 21, 2364.749,1194.660,131.672, 3000, 'WP22 - say'), + (26499, 22, 2390.256,1204.235,134.125, 0, 'WP21 - pause escort and start event'), #2500 2396.035 1206.942 134.038 + (26499, 23, 2442.023,1219.205,133.999, 0, 'WP22'), + (26499, 24, 2446.945,1192.559,148.100, 0, 'WP23'), + (26499, 25, 2443.161,1191.442,148.076, 5000, 'WP24 - summon portal'), + (26499, 26, 2428.901,1192.164,148.076, 0, 'WP25'), + (26499, 27, 2418.487,1196.059,148.076, 0, 'WP26'), + (26499, 28, 2401.221,1191.705,148.076, 0, 'WP27'), + (26499, 29, 2409.143,1157.000,148.190, 1000, 'WP28 - trap'), + (26499, 30, 2417.584,1121.026,148.082, 10000, 'WP29'), + (26499, 31, 2420.949,1119.944,148.075, 29000, 'WP30 - pause'), + (26499, 32, 2444.682,1111.705,148.076, 0, 'WP31 - Stop'), + + (26499, 33, 2457.133,1120.941,150.008, 0, 'House WP11'), + (26499, 34, 2459.694,1127.012,150.008, 0, 'House WP12'), + (26499, 35, 2469.617,1122.274,150.008, 0, 'House WP13'), + (26499, 36, 2470.437,1122.794,150.008, 3000, 'Open Shkaf'), + (26499, 37, 2471.662,1123.077,150.035, 3000, 'Shkaf Dialog'), + (26499, 38, 2483.183,1125.042,149.905, 0, 'Secret WP1'), + (26499, 39, 2487.867,1099.760,144.858, 0, 'Secret WP2'), + (26499, 40, 2498.270,1101.929,144.599, 0, 'Secret WP3'), + (26499, 41, 2492.114,1128.238,139.967, 0, 'Secret WP4'), + (26499, 42, 2500.286,1130.183,139.982, 0, 'Room WP1'), + (26499, 43, 2503.010,1119.241,139.978, 0, 'Room WP2'), + (26499, 44, 2517.820,1122.645,132.066, 0, 'Room WP3'), + (26499, 45, 2540.479,1129.061,130.868, 7000, 'Fire Street WP1'), + (26499, 46, 2568.619,1157.794,126.906, 0, 'Fire Street WP2'), + (26499, 47, 2556.074,1222.058,125.412, 0, 'Fire Street WP3'), + (26499, 48, 2521.531,1295.209,130.573, 20000, 'Fire Street WP4'), + (26499, 49, 2504.362,1348.667,132.944, 0, 'Fire Street WP5'), + (26499, 50, 2450.594,1431.544,131.361, 0, 'Fire Street WP6'), + (26499, 51, 2353.485,1404.839,128.531, 0, 'Stop Malganis'), + (26499, 52, 2329.882,1406.273,128.013, 0, 'wp'), + (26499, 53, 2300.415,1489.316,128.362, 0, 'wp stop'), + (26499, 54, 2329.882,1406.273,128.013, 0, 'wp'); diff --git a/sql_mr/mr00281_mangos_guards_data.sql b/sql_mr/mr00281_mangos_guards_data.sql new file mode 100644 index 0000000000..37e9da114f --- /dev/null +++ b/sql_mr/mr00281_mangos_guards_data.sql @@ -0,0 +1,31 @@ +-- -------------------------- +-- Guards around the worlds - +-- -------------------------- + +-- NEEDS MORE RESEARCH + +-- Cenarion hold infantry + -- adding attack spells to creature template +UPDATE `creature_template` SET `ExtraFlags` = 0 WHERE `entry` = 15184; +REPLACE INTO `creature_template_spells` SET `entry` = 15184, `spell1` = 18328, `spell2` = 19643, `spell3` = 15618; + +-- Bluff watcher ( thunderbluff ) +-- correcting guard spells +UPDATE `creature_template` SET `ExtraFlags` = 0 WHERE `entry` = 3084; +UPDATE `creature_template_spells` SET `spell1` = 40505, `spell2` = 12024, `spell3` = 23337 WHERE `entry` = 3084; + +-- orc guards +UPDATE `creature_template` SET `ExtraFlags` = 0 WHERE `entry` = 3296; +UPDATE `creature_template_spells` SET `spell2` = 40505 WHERE `entry` = 3296; + +-- Darn Guards +UPDATE `creature_template` SET `ExtraFlags` = 0 WHERE `entry` = 4262; +REPLACE INTO `creature_template_spells` SET `entry` = 4262, `spell1` = 40505, `spell2` = 8599; + +-- stormwind guards Guards +UPDATE `creature_template` SET `ExtraFlags` = 0 WHERE `entry` = 68; +REPLACE INTO `creature_template_spells` SET `entry` = 68, `spell1` = 40505, `spell2` = 8599; + +-- Undercity Guards +UPDATE `creature_template` SET `ExtraFlags` = 0 WHERE `entry` = 5624; +UPDATE `creature_template_spells` SET `spell1` = 59395, `spell2` = 7160 WHERE `entry` = 5624; diff --git a/sql_mr/mr00282_mangos_ankahet.sql b/sql_mr/mr00282_mangos_ankahet.sql new file mode 100644 index 0000000000..b88bff01e2 --- /dev/null +++ b/sql_mr/mr00282_mangos_ankahet.sql @@ -0,0 +1,114 @@ +-- ------------------- +-- Instance_Ahnkahet - +-- ------------------- + +-- ------------- +-- Elder Nadox - +-- ------------- + +UPDATE `creature_template` SET `FactionAlliance` = 16, `FactionHorde` = 16, `AIName` = '', `ScriptName` = 'mob_nadox_guardian' WHERE `entry` = 30176; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 30176; + +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 30178; +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=30178); +INSERT INTO `creature_ai_scripts` VALUES +(3017801, 30178, 0, 0, 100, 7, 0, 500, 25000, 40000, 11, 56354, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Ahn kahar Swarmer - Cast Sprint'); + +UPDATE `creature_template` SET `ScriptName` = '', `AIName`='' WHERE `entry` = 30172; +UPDATE `creature_template` SET `ScriptName` = '', `AIName`='' WHERE `entry` = 30173; + + +-- --------------- OLD STUFF ----------------------------------------------------------------------- + +UPDATE `creature_template` SET `ScriptName` = 'mob_flame_orb', `AIName`='' WHERE `entry`=30702; + +DELETE FROM `creature_template_addon` WHERE `entry` IN (30385, 31474); +INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `b2_0_sheath`, `b2_1_pvp_state`, `emote`, `moveflags`, `auras`) VALUES +(30385, 0, 8, 1, 0, 0, 0, ''), +(31474, 0, 8, 1, 0, 0, 0, ''); + +UPDATE `creature_template` SET `UnitFlags` = '0' WHERE `entry` IN (30114,31473); + +DELETE FROM `gameobject` WHERE `guid` = 600005; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(600005, 194394, 619, 2, 1, 371.842, -701.621, -16.1797, 5.67851, 0, 0, 0.297751, -0.954644, -10, 0, 1); + +UPDATE `creature_template` SET `UnitFlags` = 0 WHERE `entry` IN (30258, 30391, 30435); +UPDATE `creature_template` SET `MinMeleeDmg` = 488, `MaxMeleeDmg` = 648, `MeleeAttackPower` = 782, `DamageMultiplier` = 13 WHERE `entry` = 30258; + +-- - +-- Mushrooms +-- - + +DELETE FROM `creature` WHERE `map` = 619 AND `id` IN (30391); +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `DeathState`, `MovementType`) VALUES +(600047, 30391, 619, 2, 1, 0, 0, 358.386, -885.553, -76.1054, 3.06235, 30, 0, 0, 1, 0, 0, 0), +(600048, 30391, 619, 2, 1, 0, 0, 355.893, -871.712, -76.1473, 2.37356, 30, 0, 0, 1, 0, 0, 0), +(600049, 30391, 619, 2, 1, 0, 0, 350.343, -874.985, -76.7057, 3.40793, 30, 0, 0, 1, 0, 0, 0), +(600050, 30391, 619, 2, 1, 0, 0, 339.429, -875.16, -75.6668, 2.76233, 30, 0, 0, 1, 0, 0, 0), +(600051, 30391, 619, 2, 1, 0, 0, 333.095, -874.652, -73.8099, 3.95457, 30, 0, 0, 1, 0, 0, 0), +(600052, 30391, 619, 2, 1, 0, 0, 324.208, -878.923, -70.915, 3.95457, 30, 0, 0, 1, 0, 0, 0), +(600053, 30391, 619, 2, 1, 0, 0, 319.612, -893.614, -66.4438, 6.25892, 30, 0, 0, 1, 0, 0, 0), +(600054, 30391, 619, 2, 1, 0, 0, 335.775, -899.115, -76.1423, 0.282045, 30, 0, 0, 1, 0, 0, 0), +(600055, 30391, 619, 2, 1, 0, 0, 344.644, -898.122, -77.6435, 0.282045, 30, 0, 0, 1, 0, 0, 0), +(600056, 30391, 619, 2, 1, 0, 0, 353.341, -894.159, -77.208, 0.282045, 30, 0, 0, 1, 0, 0, 0), +(600057, 30391, 619, 2, 1, 0, 0, 363.279, -897.252, -79.5129, 0.282045, 30, 0, 0, 1, 0, 0, 0), +(600058, 30391, 619, 2, 1, 0, 0, 364.47, -903.557, -80.3345, 4.7651, 30, 0, 0, 1, 0, 0, 0), +(600059, 30391, 619, 2, 1, 0, 0, 366.219, -915.939, -82.5392, 5.04784, 30, 0, 0, 1, 0, 0, 0), +(600060, 30391, 619, 2, 1, 0, 0, 368.297, -920.562, -82.5588, 5.59919, 30, 0, 0, 1, 0, 0, 0), +(600061, 30391, 619, 2, 1, 0, 0, 381.647, -923.685, -82.4737, 0.190153, 30, 0, 0, 1, 0, 0, 0), +(600062, 30391, 619, 2, 1, 0, 0, 389.079, -916.929, -81.4451, 1.40831, 30, 0, 0, 1, 0, 0, 0), +(600063, 30391, 619, 2, 1, 0, 0, 386.916, -909.718, -79.9835, 1.40831, 30, 0, 0, 1, 0, 0, 0), +(600064, 30391, 619, 2, 1, 0, 0, 386.976, -898.374, -79.2561, 2.5652, 30, 0, 0, 1, 0, 0, 0), +(600065, 30391, 619, 2, 1, 0, 0, 390.349, -882.168, -76.0919, 1.56146, 30, 0, 0, 1, 0, 0, 0), +(600066, 30391, 619, 2, 1, 0, 0, 387.136, -871.625, -75.4158, 2.15051, 30, 0, 0, 1, 0, 0, 0), +(600067, 30391, 619, 2, 1, 0, 0, 378.056, -864.542, -73.8699, 3.01759, 30, 0, 0, 1, 0, 0, 0), +(600068, 30391, 619, 2, 1, 0, 0, 363.749, -858.04, -75.1185, 3.01759, 30, 0, 0, 1, 0, 0, 0), +(600069, 30391, 619, 2, 1, 0, 0, 352.564, -862.387, -74.7834, 3.01759, 30, 0, 0, 1, 0, 0, 0), +(600070, 30391, 619, 2, 1, 0, 0, 343.924, -860.44, -74.5909, 2.23533, 30, 0, 0, 1, 0, 0, 0), +(600071, 30391, 619, 2, 1, 0, 0, 339.94, -852.104, -74.3732, 0.995972, 30, 0, 0, 1, 0, 0, 0), +(600072, 30391, 619, 2, 1, 0, 0, 347.839, -848.228, -73.7097, 6.23065, 30, 0, 0, 1, 0, 0, 0), +(600073, 30391, 619, 2, 1, 0, 0, 324.306, -858.725, -75.0947, 3.68596, 30, 0, 0, 1, 0, 0, 0), +(600074, 30391, 619, 2, 1, 0, 0, 347.971, -882.318, -75.884, 3.55872, 30, 0, 0, 1, 0, 0, 0), +(600075, 30391, 619, 2, 1, 0, 0, 347.965, -889.829, -76.747, 3.55872, 30, 0, 0, 1, 0, 0, 0), +(600076, 30391, 619, 2, 1, 0, 0, 368.578, -877.354, -75.676, 1.46878, 30, 0, 0, 1, 0, 0, 0), +(600077, 30391, 619, 2, 1, 0, 0, 378.003, -852.353, -73.5427, 0.519235, 30, 0, 0, 1, 0, 0, 0), +(600078, 30391, 619, 2, 1, 0, 0, 361.828, -841.2, -70.86, 2.94298, 30, 0, 0, 1, 0, 0, 0), +(600079, 30391, 619, 2, 1, 0, 0, 346.972, -839.523, -73.5286, 2.94298, 30, 0, 0, 1, 0, 0, 0), +(600080, 30391, 619, 2, 1, 0, 0, 337.009, -843.074, -74.3865, 2.94298, 30, 0, 0, 1, 0, 0, 0), +(600081, 30391, 619, 2, 1, 0, 0, 330.036, -847.017, -74.318, 3.25321, 30, 0, 0, 1, 0, 0, 0), +(600082, 30391, 619, 2, 1, 0, 0, 328.839, -838.69, -72.921, 1.8929, 30, 0, 0, 1, 0, 0, 0), +(600083, 30391, 619, 2, 1, 0, 0, 322.452, -829.799, -73.5624, 2.6563, 30, 0, 0, 1, 0, 0, 0), +(600084, 30391, 619, 2, 1, 0, 0, 316.367, -822.016, -73.1033, 1.71618, 30, 0, 0, 1, 0, 0, 0), +(600085, 30391, 619, 2, 1, 0, 0, 320.592, -812.011, -73.8038, 0.957487, 30, 0, 0, 1, 0, 0, 0), +(600086, 30391, 619, 2, 1, 0, 0, 322.619, -803.898, -72.9384, 2.07668, 30, 0, 0, 1, 0, 0, 0), +(600087, 30391, 619, 2, 1, 0, 0, 331.481, -811.702, -72.9227, 5.46332, 30, 0, 0, 1, 0, 0, 0), +(600088, 30391, 619, 2, 1, 0, 0, 341.894, -826.849, -73.049, 5.46332, 30, 0, 0, 1, 0, 0, 0), +(600089, 30391, 619, 2, 1, 0, 0, 387.58, -856.341, -71.0935, 5.72486, 30, 0, 0, 1, 0, 0, 0), +(600090, 30391, 619, 2, 1, 0, 0, 401.977, -867.49, -73.3215, 5.27247, 30, 0, 0, 1, 0, 0, 0), +(600091, 30391, 619, 2, 1, 0, 0, 408.72, -872.115, -73.0256, 6.03823, 30, 0, 0, 1, 0, 0, 0), +(600092, 30391, 619, 2, 1, 0, 0, 416.438, -875.336, -70.4833, 5.08397, 30, 0, 0, 1, 0, 0, 0), +(600093, 30391, 619, 2, 1, 0, 0, 403.004, -895.527, -75.561, 5.60391, 30, 0, 0, 1, 0, 0, 0), +(600094, 30391, 619, 2, 1, 0, 0, 409.35, -902.562, -77.2837, 5.22927, 30, 0, 0, 1, 0, 0, 0), +(600095, 30391, 619, 2, 1, 0, 0, 414.538, -911.69, -79.8006, 5.22927, 30, 0, 0, 1, 0, 0, 0), +(600096, 30391, 619, 2, 1, 0, 0, 419.727, -920.818, -80.7403, 5.22927, 30, 0, 0, 1, 0, 0, 0), +(600097, 30391, 619, 2, 1, 0, 0, 428.151, -920.833, -79.0992, 0.892305, 30, 0, 0, 1, 0, 0, 0), +(600098, 30391, 619, 2, 1, 0, 0, 436.712, -911.759, -78.8367, 0.0605679, 30, 0, 0, 1, 0, 0, 0), +(600099, 30391, 619, 2, 1, 0, 0, 461.167, -910.276, -77.4777, 0.0605679, 30, 0, 0, 1, 0, 0, 0), +(600100, 30391, 619, 2, 1, 0, 0, 419.827, -930.386, -77.7951, 4.29465, 30, 0, 0, 1, 0, 0, 0), +(600101, 30391, 619, 2, 1, 0, 0, 418.017, -939.624, -80.2493, 4.29465, 30, 0, 0, 1, 0, 0, 0), +(600102, 30391, 619, 2, 1, 0, 0, 417.247, -948.532, -79.3315, 4.29465, 30, 0, 0, 1, 0, 0, 0), +(600103, 30391, 619, 2, 1, 0, 0, 409.236, -952.042, -80.6495, 4.29465, 30, 0, 0, 1, 0, 0, 0), +(600104, 30391, 619, 2, 1, 0, 0, 410.077, -959.059, -78.9977, 4.29465, 30, 0, 0, 1, 0, 0, 0), +(600105, 30391, 619, 2, 1, 0, 0, 403.871, -964.208, -77.8873, 4.29465, 30, 0, 0, 1, 0, 0, 0), +(600106, 30391, 619, 2, 1, 0, 0, 401.693, -970.428, -77.3012, 4.90255, 30, 0, 0, 1, 0, 0, 0), +(600107, 30391, 619, 2, 1, 0, 0, 402.379, -980.099, -75.4585, 4.60567, 30, 0, 0, 1, 0, 0, 0), +(600108, 30391, 619, 2, 1, 0, 0, 399.272, -984.535, -75.9494, 3.15425, 30, 0, 0, 1, 0, 0, 0), +(600109, 30391, 619, 2, 1, 0, 0, 380.102, -984.145, -74.2926, 2.13402, 30, 0, 0, 1, 0, 0, 0), +(600110, 30391, 619, 2, 1, 0, 0, 369.565, -973.481, -77.4914, 2.56756, 30, 0, 0, 1, 0, 0, 0), +(600111, 30391, 619, 2, 1, 0, 0, 360.748, -967.779, -79.832, 2.56756, 30, 0, 0, 1, 0, 0, 0), +(600112, 30391, 619, 2, 1, 0, 0, 350.138, -958.988, -79.4422, 2.16229, 30, 0, 0, 1, 0, 0, 0), +(600113, 30391, 619, 2, 1, 0, 0, 342.879, -944.352, -79.8533, 1.64157, 30, 0, 0, 1, 0, 0, 0); + +UPDATE `creature_template` SET `MinLevelHealth` = 1 WHERE `entry` = 30391; +UPDATE `creature_template` SET `MinLevelMana` = 0 WHERE `entry` = 29310; diff --git a/sql_mr/mr00295_mangos_SotA.sql b/sql_mr/mr00295_mangos_SotA.sql new file mode 100644 index 0000000000..503a1e0aec --- /dev/null +++ b/sql_mr/mr00295_mangos_SotA.sql @@ -0,0 +1,4 @@ +-- SotA +UPDATE creature_template SET ScriptName='npc_sa_vendor' WHERE entry IN (29260, 29262); +UPDATE gameobject_template SET ScriptName='go_sa_def_portal' WHERE entry = 191575; +UPDATE gameobject_template SET ScriptName='' WHERE entry IN (194086, 190753); diff --git a/sql_mr/mr00300_mangos_culling_of_stratholme.sql b/sql_mr/mr00300_mangos_culling_of_stratholme.sql new file mode 100644 index 0000000000..f29bdb50ae --- /dev/null +++ b/sql_mr/mr00300_mangos_culling_of_stratholme.sql @@ -0,0 +1,168 @@ +-- ------------------------------ +-- Instance CoS - +-- ------------------------------ + +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_mike' WHERE entry = 30571; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_chromi_start' WHERE entry=26527; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_roger' WHERE entry=27903; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_morigan' WHERE entry=27877; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = '' WHERE entry=30996; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_stratholme_crates' WHERE entry=27827; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_jena' WHERE entry=27885; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_malcolm' WHERE entry=27891; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_bartleby_cs' WHERE entry=27907; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_chromi_middle' WHERE entry=27915; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_uther' WHERE entry=26528; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_arthas' WHERE entry=26499; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_arthas_priest' WHERE entry IN (70004, 70005); +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_arthas_marine' WHERE entry IN (70000, 70001, 70002, 70003); +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_dark_conversion' WHERE entry IN (31127, 31126, 28167, 28169); +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_cs_gnoul' WHERE entry=28249; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_cs_necromancer' WHERE entry=28200; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_cs_field' WHERE entry=27734; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_cs_acolyte' WHERE entry=27731; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_cs_butcher' WHERE entry=27736; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_meathook' WHERE entry=26529; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_salramm' WHERE entry=26530; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_salramm_gnoul' WHERE entry=27733; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_lord_epoch' WHERE entry=26532; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_malganis' WHERE entry=26533; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_time_riftCS' WHERE entry=28409; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_infinite_corruptor' WHERE entry=32273; + +-- ACID CLEAN UP +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26499); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26529); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26499); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26530); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26532); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26533); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=27731); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=27734); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=27736); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=28200); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=28249); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=32273); + +-- Clean up ACID texts +DELETE FROM `creature_ai_texts` WHERE `entry`=-841; +DELETE FROM `creature_ai_texts` WHERE `entry`=-842; +DELETE FROM `creature_ai_texts` WHERE `entry`=-843; +DELETE FROM `creature_ai_texts` WHERE `entry`=-844; +DELETE FROM `creature_ai_texts` WHERE `entry`=-845; +DELETE FROM `creature_ai_texts` WHERE `entry`=-846; +DELETE FROM `creature_ai_texts` WHERE `entry`=-847; +DELETE FROM `creature_ai_texts` WHERE `entry`=-848; +DELETE FROM `creature_ai_texts` WHERE `entry`=-849; +DELETE FROM `creature_ai_texts` WHERE `entry`=-850; +DELETE FROM `creature_ai_texts` WHERE `entry`=-851; +DELETE FROM `creature_ai_texts` WHERE `entry`=-852; +DELETE FROM `creature_ai_texts` WHERE `entry`=-853; +DELETE FROM `creature_ai_texts` WHERE `entry`=-854; +DELETE FROM `creature_ai_texts` WHERE `entry`=-855; +DELETE FROM `creature_ai_texts` WHERE `entry`=-856; +DELETE FROM `creature_ai_texts` WHERE `entry`=-857; +DELETE FROM `creature_ai_texts` WHERE `entry`=-858; +DELETE FROM `creature_ai_texts` WHERE `entry`=-859; +DELETE FROM `creature_ai_texts` WHERE `entry`=-860; +DELETE FROM `creature_ai_texts` WHERE `entry`=-861; +DELETE FROM `creature_ai_texts` WHERE `entry`=-862; +DELETE FROM `creature_ai_texts` WHERE `entry`=-863; +DELETE FROM `creature_ai_texts` WHERE `entry`=-864; +DELETE FROM `creature_ai_texts` WHERE `entry`=-865; +DELETE FROM `creature_ai_texts` WHERE `entry`=-866; +DELETE FROM `creature_ai_texts` WHERE `entry`=-867; +DELETE FROM `creature_ai_texts` WHERE `entry`=-868; +DELETE FROM `creature_ai_texts` WHERE `entry`=-869; +DELETE FROM `creature_ai_texts` WHERE `entry`=-870; +DELETE FROM `creature_ai_texts` WHERE `entry`=-871; +DELETE FROM `creature_ai_texts` WHERE `entry`=-872; +DELETE FROM `creature_ai_texts` WHERE `entry`=-873; +DELETE FROM `creature_ai_texts` WHERE `entry`=-874; +DELETE FROM `creature_ai_texts` WHERE `entry`=-875; +DELETE FROM `creature_ai_texts` WHERE `entry`=-876; + +-- Quest fix ( if you already had quest done should be able to do it again you can in off blizz ... soo) +-- Xploitable +-- UPDATE `quest_template` SET `SpecialFlags` = 1 WHERE `entry` = 13151; +-- UPDATE `quest_template` SET `SpecialFlags` = 1 WHERE `entry` = 13149; + +-- remove already spawned third chromi for summon after mal ganis is dead +DELETE FROM `creature` WHERE `id`=30997; + +-- ---------------------------------------- +-- spell scripts and ect spell_area_stuff - +-- ---------------------------------------- + +REPLACE INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_start_active`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`) VALUES +('35481','4100','0','0','0','0','0','1','1'), -- cause careate two spell with different racemask fore one area +('35480','4100','0','0','0','0','0','0','1'); -- cause careate two spell with different racemask fore one area + +-- ---------------------------- +-- Creature Stuff - +-- ---------------------------- + +UPDATE `creature_template` SET `ModelId2` = 24769 WHERE `entry` = 27747; +UPDATE `creature_template` SET `ModelId2` = 24768 WHERE `entry` = 27745; +UPDATE `creature_template` SET `ModelId2` = 24949 WHERE `entry` = 26499; + +UPDATE `creature` SET `spawntimesecs`= 36000 WHERE `id` IN (31127, 31126, 28167, 28169); + +-- Remove old versions +DELETE FROM `creature` WHERE `id` IN (27731,27734,28249,27736,27915,30571,26499,26497,26528,27891,27892,27884,32273,28439); + +-- DB error corrections for above sql query +DELETE FROM `creature_movement` WHERE (`id`='138237' AND `point`='1') OR (`id`='138237' AND `point`='2') OR (`id`='138238' AND `point`='1') OR (`id`='138238' AND `point`='2') OR (`id`='138239' AND `point`='1') OR (`id`='138239' AND `point`='2') OR (`id`='138239' AND `point`='3') OR (`id`='138239' AND `point`='4'); +DELETE FROM `creature_movement` WHERE (`id`='138288' AND `point`='1') OR (`id`='138288' AND `point`='2') OR (`id`='138289' AND `point`='1') OR (`id`='138289' AND `point`='2'); + +-- Add Whats needed -- +DELETE FROM `creature` WHERE `id` in (26497, 26528, 27891, 27892, 32273, 28439); +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600114, 26497, 595, 3, 1, 0, 1221, 1896.39, 1292.91, 143.711, 0.016332, 300, 0, 0, 100800, 88140, 0, 0), +(600115, 26528, 595, 3, 1, 0, 1819, 1761.42, 1285.75, 139.945, 4.93874, 300, 0, 0, 126000, 59910, 0, 0), +(600116, 27891, 595, 3, 1, 0, 0, 1603.38, 805.988, 123.272, 1.90688, 300, 0, 0, 8982, 0, 0, 0), +(600117, 27892, 595, 3, 1, 0, 0, 1602.3, 809.385, 123.454, 5.02884, 300, 0, 0, 8982, 0, 0, 0), +(600118, 32273, 595, 3, 1, 0, 1839, 2330.93, 1275.59, 132.848, 3.60489, 300, 0, 0, 417911, 0, 0, 0), +(600119, 28439, 595, 3, 1, 0, 0, 2336.56, 1277.9, 132.885, 3.47923, 300, 0, 0, 1, 0, 0, 0); + + +-- added some npc s of my own for micro management +-- footman +DELETE FROM `creature_template` WHERE `entry` IN (10, 11, 12, 13); +INSERT INTO `creature_template` (`Entry`, `Name`, `SubName`, `IconName`, `MinLevel`, `MaxLevel`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `FactionAlliance`, `FactionHorde`, `Scale`, `Family`, `CreatureType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `NpcFlags`, `UnitFlags`, `DynamicFlags`, `ExtraFlags`, `CreatureTypeFlags`, `SpeedWalk`, `SpeedRun`, `UnitClass`, `Rank`, `Expansion`, `HealthMultiplier`, `PowerMultiplier`, `DamageMultiplier`, `DamageVariance`, `ArmorMultiplier`, `ExperienceMultiplier`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `MinMeleeDmg`, `MaxMeleeDmg`, `MinRangedDmg`, `MaxRangedDmg`, `Armor`, `MeleeAttackPower`, `RangedAttackPower`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `DamageSchool`, `MinLootGold`, `MaxLootGold`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `KillCredit1`, `KillCredit2`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MechanicImmuneMask`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MovementType`, `MovementTemplateId`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `TrainerTemplateId`, `VendorTemplateId`, `EquipmentTemplateId`, `VehicleTemplateId`, `GossipMenuId`, `AIName`, `ScriptName`) VALUES +(10,'Lordaeron Footman','','','80','80','0','0','0','24768','24768','0','0','2076','2076','1','0','7','3','3','0','0','0','0','0','0','1','1.14286','1','1','-1','1','1','2.7','1','1','1','12600','12600','0','0','420','630','336','504','9730','157','126','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','223','0','0','','npc_arthas_marine'), +(11,'Lordaeron Footman','','','80','80','0','0','0','24768','24768','0','0','2076','2076','1','0','7','3','3','0','0','0','0','0','0','1','1.14286','1','1','-1','1','1','2.7','1','1','1','12600','12600','0','0','420','630','336','504','9730','157','126','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','223','0','0','','npc_arthas_marine'), +(12,'Lordaeron Footman','','','80','80','0','0','0','24768','24768','0','0','2076','2076','1','0','7','3','3','0','0','0','0','0','0','1','1.14286','1','1','-1','1','1','2.7','1','1','1','12600','12600','0','0','420','630','336','504','9730','157','126','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','223','0','0','','npc_arthas_marine'), +(13,'Lordaeron Footman','','','80','80','0','0','0','24768','24768','0','0','2076','2076','1','0','7','3','3','0','0','0','0','0','0','1','1.14286','1','1','-1','1','1','2.7','1','1','1','12600','12600','0','0','420','630','336','504','9730','157','126','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','223','0','0','','npc_arthas_marine'); + +REPLACE INTO `creature_template_spells` (`entry`, `spell1`, `spell2`) VALUES +(10, 52317, 25710), +(11, 52317, 25710), +(12, 52317, 25710), +(13, 52317, 25710); + +-- micro manage spawn w/ news one in there recyling old guids +DELETE FROM `creature` WHERE `id` IN (10, 11, 12, 13); +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600120, 10, 595, 3, 1, 0, 0, 2042.13, 1293.14, 143.336, 4.64258, 300, 0, 0, 12600, 0, 0, 0), +(600121, 11, 595, 3, 1, 0, 0, 2046.71, 1281.91, 143.321, 1.51844, 300, 0, 0, 12600, 0, 0, 0), +(600122, 12, 595, 3, 1, 0, 0, 2041.97, 1281.66, 143.554, 1.62316, 300, 0, 0, 12600, 0, 0, 0), +(600123, 13, 595, 3, 1, 0, 0, 2046.86, 1293.33, 143.132, 4.7822, 300, 0, 0, 12600, 0, 0, 0); + +-- priest +DELETE FROM `creature_template` WHERE `entry` IN(14, 15); +INSERT INTO `creature_template` (`Entry`, `Name`, `SubName`, `IconName`, `MinLevel`, `MaxLevel`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `FactionAlliance`, `FactionHorde`, `Scale`, `Family`, `CreatureType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `NpcFlags`, `UnitFlags`, `DynamicFlags`, `ExtraFlags`, `CreatureTypeFlags`, `SpeedWalk`, `SpeedRun`, `UnitClass`, `Rank`, `Expansion`, `HealthMultiplier`, `PowerMultiplier`, `DamageMultiplier`, `DamageVariance`, `ArmorMultiplier`, `ExperienceMultiplier`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `MinMeleeDmg`, `MaxMeleeDmg`, `MinRangedDmg`, `MaxRangedDmg`, `Armor`, `MeleeAttackPower`, `RangedAttackPower`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `DamageSchool`, `MinLootGold`, `MaxLootGold`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `KillCredit1`, `KillCredit2`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MechanicImmuneMask`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MovementType`, `MovementTemplateId`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `TrainerTemplateId`, `VendorTemplateId`, `EquipmentTemplateId`, `VehicleTemplateId`, `GossipMenuId`, `AIName`, `ScriptName`) VALUES +(14,'High Elf Mage-Priest','','','80','80','0','0','0','24769','0','0','0','2076','2076','1','0','7','3','3','0','0','0','0','0','0','1','1.14286','8','1','-1','1','1','2.9','1','1','1','10080','10080','8814','8814','307','459','246','367','7784','115','92','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','14','0','0','','npc_arthas_priest'), +(15,'High Elf Mage-Priest','','','80','80','0','0','0','24769','0','0','0','2076','2076','1','0','7','3','3','0','0','0','0','0','0','1','1.14286','8','1','-1','1','1','2.9','1','1','1','10080','10080','8814','8814','307','459','246','367','7784','115','92','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','14','0','0','','npc_arthas_priest'); + +REPLACE INTO `creature_template_spells` (`entry`, `spell1`) VALUES +(14, 34232), +(15, 34232); + +-- micro manage spawn w/ news one in there recyling old guids +DELETE FROM `creature` WHERE `id` IN (14, 15); +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600124, 14, 595, 3, 1, 0, 0, 2037.91, 1293.03, 143.499, 4.72984, 300, 0, 0, 10080, 8814, 0, 0), +(600125, 15, 595, 3, 1, 0, 0, 2037.59, 1281.81, 143.666, 1.48353, 300, 0, 0, 10080, 8814, 0, 0); + +-- end of this diff --git a/sql_mr/mr00301_scriptdev2_Quest_Script_stuff.sql b/sql_mr/mr00301_scriptdev2_Quest_Script_stuff.sql new file mode 100644 index 0000000000..125bb399f9 --- /dev/null +++ b/sql_mr/mr00301_scriptdev2_Quest_Script_stuff.sql @@ -0,0 +1,103 @@ +-- ------------------------------------ +-- Quest :: 12644, Quest :: 12645 texts +-- ------------------------------------ + +DELETE FROM script_texts WHERE entry BETWEEN -1999791 AND -1999783; +INSERT INTO script_texts VALUES +('-1999791','Aye, I\'ll try it.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Hemet Nesingwary - Taste Test (1)'), +('-1999790','That\'s exactly what I needed!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Hemet Nesingwary - Taste Test (2)'), +('-1999789','It\'s got my vote! That\'ll put hair on your chest like nothing else will.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Hemet Nesingwary - Taste Test (3)'), +('-1999788','I\'m always up for something of Grimbooze\'s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Hadrius Harlowe - Taste Test (1)'), +('-1999787','Well, so far, it tastes like something my wife would drink...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Hadrius Harlowe - Taste Test (2)'), +('-1999786','Now, there\'s the kick I\'ve come to expect from Grimbooze\'s drinks! I like it!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Hadrius Harlowe - Taste Test (3)'), +('-1999785','Sure!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Tamara Wobblesprocket - Taste Test (1)'), +('-1999784','Oh my...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Tamara Wobblesprocket - Taste Test (2)'), +('-1999783','Tastes like I\'m drinking... engine degreaser!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0','0','0','0','Tamara Wobblesprocket - Taste Test (3)'); + +DELETE FROM script_texts WHERE entry BETWEEN -1999803 AND -1999792; +INSERT into script_texts (entry,content_default,type,comment) VALUES +(-1999792,'Beginning the destillation in 5 seconds',0,'SAY_EVENT_STARTED'), +(-1999793,'Add bannanas',0,'SAY_ADD_BANNANAS'), +(-1999794,'Put a papaya in the still',0,'SAY_ADD_PAPAYA'), +(-1999795,'Good job! Keep your eyes open now',0,'SAY_GOOD_JOB_1'), +(-1999796,'The still needs heat! Light the brazier!',0,'SAY_BRAZIER'), +(-1999797,'Well done, be ready for anything!',0,'SAY_GOOD_JOB_2'), +(-1999798,'Pressuer\'s too high! Open the pressure valve!',0,'SAY_OPEN_VALVE'), +(-1999799,'That\'ll do. Never know what it\'ll need next ...',0,'SAY_GOOD_JOB_3'), +(-1999800,'Nicely handled! Stay on your toes',0,'SAY_GOOD_JOB_4'), +(-1999801,'We\'ve done it! Come get the cask',0,'SAY_EVENT_END'), +(-1999802,'Add orange, quickly !',0,'SAY_ADD_ORANGE'), +(-1999803,'You failed! You will have to begin new destillation process if you still want cask',0,'SAY_FAIL'); + +-- ----------- +-- Quest 11466 +-- ----------- + +DELETE FROM script_texts WHERE entry BETWEEN -1999818 AND -1999812; +INSERT INTO script_texts (`entry`,`content_default`,`type`,`comment`) VALUES +(-1999818,'Keep quiet, will you? If anyone catches on, we\'re both dead.',4,'Olga (0)'), +(-1999817,'All right, fellas! Who ordered the spiced rum? Was it you, Jackie boy?',0,'Olga (1)'), +(-1999816,'Sure thing, love. Put it on Harry\'s tab, will you? He owes me a drink!',0,'Jack Adams (2)'), +(-1999815,'It\'s ok sweetheart. This one is on the house',0,'Olga (3)'), +(-1999814,'Free rum? Why... that\'s me favourite kind!',0,'Jack Adams (4)'), +(-1999813,'Sweet Neptulon! That was... one drink... too many!',0,'Jack Adams (5)'), +(-1999812,'What are you lot looking at? Pour me another drink!',0,'Jack Adams (6)'); + +-- ----------------- +-- Quest texts 14107 +-- ----------------- + +DELETE FROM script_texts WHERE entry BETWEEN -1999823 AND -1999819; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1999819,'At last... now I can rest.',0,0,0,0,'hero spirit SAY_BLESS_1'), +(-1999820,'I\'m so tired. Just let me rest for a moment.',0,0,0,0,'hero spirit SAY_BLESS_2'), +(-1999821,'I can\'t hear the screams anymore. Is this the end?',0,0,0,0,'hero spirit SAY_BLESS_3'), +(-1999822,'My nightmare, is it finally over?',0,0,0,0,'hero spirit SAY_BLESS_4'), +(-1999823,'It was awful... I dreamt I was fighting against my friends.',0,0,0,0,'hero spirit SAY_BLESS_5'); + +-- ------- +-- Quests 13665, 13745, 13750, 13756, 13761, 13767, 13772, 13777, 13782, 13787 +-- ------ +DELETE FROM script_texts WHERE entry = -1999824; +INSERT INTO script_texts (`entry`,`content_default`,`comment`) values +(-1999824,'I have been defeated. Good fight!',''); + + +-- --------- +-- Quest 13663 +-- --------- + +DELETE FROM `script_waypoint` WHERE `entry` = 33519; +INSERT INTO `script_waypoint` (`entry`,`pointid`,`location_x`, +`location_y`,`location_z`,`waittime`,`point_comment`) values +(33519, 0, 8524.63, 578.345, 552.524, 0, ''), +(33519, 1, 8455.89, 694.577, 547.292, 0, ''), +(33519, 2, 8397.99, 748.036, 547.293, 0, ''), +(33519, 3, 8373.84, 797.464, 547.91, 0, ''), +(33519, 4, 8375.42, 858.007, 547.996, 0, ''), +(33519, 5, 8391.85, 867.635, 547.556, 0, ''), +(33519, 6, 8461.66, 871.668, 547.293, 0, ''), +(33519, 7, 8472.43, 881.281, 547.294, 0, ''), +(33519, 8, 8478.89, 1017.11, 547.293, 0, ''), +(33519, 9, 8525.79, 1032.95, 547.293, 0, ''), +(33519, 10, 8537.57, 1076.91, 554.394, 0, ''), +(33519, 11, 8544.016, 1093.445, 562.226, 0, ''), +(33519, 12, 8576.88, 1211.09, 562.226, 0, ''), +(33519, 13, 9094.39, 2031.69, 97.599, 0, ''), +(33519, 14, 9086.074, 2058.25, 82.827, 0, ''), +(33519, 15, 9066.61, 2114.63, 67.966, 0, ''), +(33519, 16, 9052.65, 2115.8, 57.863, 3000, ''); + +-- ------------- +-- Quest 11560 - +-- ------------- + +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1999831 AND -1999825; +INSERT INTO `script_texts` (`entry`,`content_default`,`comment`) VALUES +(-1999825, "Eww.. $r!", "tadpole SAY_RACE"), +(-1999826, "No go with stranger!", "tadpole SAY_2"), +(-1999827, "Close!", "tadpole SAY_3"), +(-1999828, "Me go home?", "tadpole SAY_4"), +(-1999829, "Play!", "tadpole SAY_5"), +(-1999830, "Alurglgl!", "tadpole SAY_6"), +(-1999831, "da-da?", "tadpole SAY_7"); diff --git a/sql_mr/mr00326_scriptdev2_icecrown.sql b/sql_mr/mr00326_scriptdev2_icecrown.sql new file mode 100644 index 0000000000..b38994bcd0 --- /dev/null +++ b/sql_mr/mr00326_scriptdev2_icecrown.sql @@ -0,0 +1,697 @@ +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1631594 AND -1631000; +INSERT INTO `script_texts` (`entry`,`content_loc6`, `content_loc7`, `content_loc8`, `content_default`, `sound`, `type`, `language`, `emote`, `comment`) VALUES + +-- Lord Marrowgar +('-1631001','Este es el principio y el final, mortales. Nadie puede entrar en el sagrario del maestro.','Este es el principio y el final, mortales. Nadie puede entrar en el sagrario del maestro.','Это начало и конец, смертные. Никто не может войти в Храм!','This is the beginning AND the end, mortals. None may enter the master\'s sanctum!','16950','1','0','0','marrowgar SAY_INTRO'), +('-1631002','La plaga arrasará este mundo como un enjambre de muerte y destrucción.','La plaga arrasará este mundo como un enjambre de muerte y destrucción.','Проклятые несут миру смерть и разрушение!','The Scourge will wash over this world as a swarm of death and destruction!','16941','1','0','0','marrowgar SAY_AGGRO'), +('-1631003','¡TORMENTA DE HUESOS!','¡TORMENTA DE HUESOS!','Шторм костей!','BONE STORM!','16946','1','0','0','marrowgar SAY_BONESTORM'), +('-1631004','¡Unidos por los huesos!','¡Unidos por los huesos!','Проткнут костью!','Bound by bone!','16947','1','0','0','marrowgar SAY_BONESPIKE1'), +('-1631005','¡Quedaos cerca!','¡Quedaos cerca!','Кости вокруг!','Stick Around!','16948','1','0','0','marrowgar SAY_BONESPIKE2'), +('-1631006','¡La única salida es la muerte!','¡La única salida es la muerte!','Выход - только смерть!','The only escape is death!','16949','1','0','0','marrowgar SAY_BONESPIKE3'), +('-1631007','¡Más huesos para la ofrenda!','¡Más huesos para la ofrenda!','Больше костей!','More bones for the offering!','16942','1','0','0','marrowgar SAY_KILL1'), +('-1631008','¡Púdrete en tu condena!','¡Púdrete en tu condena!','Будьте прокляты!','Languish in damnation!','16943','1','0','0','marrowgar SAY_KILL2'), +('-1631009','¡LA RABIA DEL MAESTRO FLUYE DENTRO DE MI!','¡LA RABIA DEL MAESTRO FLUYE DENTRO DE MI!','Я вижу... Только тьму...','I see... only darkness...','16944','1','0','0','marrowgar SAY_DEATH'), +('-1631010','Solo veo oscuridad...','Solo veo oscuridad...','ЯРОСТЬ МАСТЕРА ТЕЧЕТ ЧЕРЕЗ МЕНЯ!','THE MASTER\'S RAGE COURSES THROUGH ME!','16945','3','0','0','marrowgar SAY_ENRAGE'), + +-- Lady Deathwhisper +('-1631011','','','Вы нашли свой путь здесь, потому что вы принадлежите к числу немногих одаренных истинным видением мира, проклятого слепотой! Вы можете видеть сквозь туман, что висит над этим миром, как саван, и понять, где истинная сила лжи!','You have found your way here, because you are among the few gifted with true vision in a world cursed with blindness! You can see through the fog that hangs over this world like a shroud and grasp where true power lies!','16880','1','0','0','deathwhisper SAY_INTRO3'), +('-1631013','¡Pegad los ojos sobre vuestras burdas manos! ¡Los tendones, la tierna carne, la oscura sangre que las recorre!','¡Pegad los ojos sobre vuestras burdas manos! ¡Los tendones, la tierna carne, la oscura sangre que las recorre!','Взгляните на ваши мягкие руки! Сухожилия, мясо, кровь! Это слабость! Серьезная ошибка! Шутка создателя со своими творениями! Чем раньше вы поймете что жизнь - это дефект, тем раньше вы сможете преодолеть вашу слабость!','Fix your eyes upon your crude hands! The sinew, the soft meat, the dark blood coursing within! It is a weakness! A crippling flaw! A joke played by the creators upon their own creations! The sooner you come to accept your condition as a defect, the sooner you will find yourselves in a position to transcend it!','16878','1','0','0','deathwhisper SAY_INTRO1'), + +('-1631014','¡Es una debilidad! ¡Un defecto atroz! ¡Una broma de los creadores hacia su creación!','¡Es una debilidad! ¡Un defecto atroz! ¡Una broma de los creadores hacia su creación!','','It is a weakness; a crippling flaw.... A joke played by the Creators upon their own creations.',17268,1,0,0,'deathwhisper SAY_SPEECH_4'), +('-1631015','¡Cuanto antes aceptéis vuestra condición como un defecto, antes os encontraréis en posición de superarlo!','¡Cuanto antes aceptéis vuestra condición como un defecto, antes os encontraréis en posición de superarlo!','','The sooner you come to accept your condition as a defect, the sooner you will find yourselves in a position to transcend it.',17269,1,0,0,'deathwhisper SAY_SPEECH_5'), +('-1631016','','','Через нашего Мастера все возможно! Его сила не имеет предела, и его воля непреклонна! Те, кто против него будут истреблены! А те, кто служат, которые подчиняются полностью, беспрекословно, с беззаветной преданностью ума и души? Возвышены!','Through our master all things are possible! His power is without limit, and his will unbending! Those who oppose him will be destroyed utterly! And those who serve, who serve wholly, unquestioningly, with utter devotion of mind and soul? Elevated! To heights beyond your ken!','16879','1','0','0','deathwhisper SAY_INTRO2'), +('-1631017','¡Los que se oponen a él serán destruidos! ¡Y los que lo sirven! ¡Los que lo sirven en cuerpo y alma con total y completa devoción sin cuestionarle, serán elevados más allá de su conocimiento!','¡Los que se oponen a él serán destruidos! ¡Y los que lo sirven! ¡Los que lo sirven en cuerpo y alma con total y completa devoción sin cuestionarle, serán elevados más allá de su conocimiento!','','Those who oppose him will be destroyed utterly, and those who serve -- who serve wholly, unquestioningly, with utter devotion of mind and soul -- elevated to heights beyond your ken.',17271,1,0,0,'deathwhisper SAY_SPEECH_7'), +('-1631018','¿Qué es este alboroto? ¿Osais entrar en suelo sagrado? Este será vuestro lugar de reposo final.','¿Qué es este alboroto? ¿Osais entrar en suelo sagrado? Este será vuestro lugar de reposo final.','Что это за беспорядок?! Вы смеете гадить на этой священной земле? Вот вам и место последнего упокоения!','What is this disturbance?! You dare trespass upon this hallowed ground? This shall be your final resting place.','16868','1','0','0','deathwhisper SAY_AGGRO'), +('-1631019','¡Basta! ¡Veo que tengo que hacer esto yo misma!','¡Basta! ¡Veo que tengo que hacer esto yo misma!','Однако! Я вижу что пора взять дело в свои руки.','Enough! I see I must take matters into my own hands!','16877','1','0','0','deathwhisper SAY_PHASE2'), +('-1631020','Toma mi bendición y muestrales a estos intrusos el poder del maestro.','Toma mi bendición y muestrales a estos intrusos el poder del maestro.','Возьмите это благословение и покажите этим злоумышленникам где раки зимуют!','Take this blessing and show these intruders a taste of our master\'s power.','16873','1','0','0','deathwhisper SAY_DARKEMPOWERMENT'), +('-1631021','¡Te libero de la maldición de la carne!','¡Te libero de la maldición de la carne!','Мои слуги! Я освобождаю вас от проклятия плоти!','Loyal adherent! I release you from the curse of flesh!','16874','1','0','0','deathwhisper SAY_DARKTRANSFORMATION'), +('-1631022','¡Alzate y goza de tu verdadera forma!','¡Alzate y goza de tu verdadera forma!','Встань и предстань в истинном виде!','Arise and exalt in your pure form!','16875','1','0','0','deathwhisper SAY_ANIMATEDEAD'), +('-1631023','¡Eres frágil y débil para resistirte a mi voluntad!','¡Eres frágil y débil para resistirte a mi voluntad!','Вы слабы и бессильны против меня!','You are weak, powerless to resist my will!','16876','1','0','0','deathwhisper SAY_DOMINATEMIND'), +('-1631024','Esta farsa ya ha durado bastante.','Esta farsa ya ha durado bastante.','Это игра продолжается слишком долго!','This charade has gone on long enough.','16872','3','0','0','deathwhisper SAY_BERSERK'), +('-1631025','¡Todo es parte del plan del maestro! ¡Tu final es inevitable!','¡Todo es parte del plan del maestro! ¡Tu final es inevitable!','Все - части плана Мастера! Ваш конец неизбежен...','All part of the masters plan! Your end is... inevitable!','16871','1','0','0','deathwhisper SAY_DEATH'), +('-1631026','¿Entiendes ya la insignificancia de tus acciones?','¿Entiendes ya la insignificancia de tus acciones?','Вы еще не осознали бесполезность своих действий?','Do you yet grasp of the futility of your actions?','16869','1','0','0','deathwhisper SAY_KILL1'), +('-1631027','Abrazate a la oscuridad... ¡Oscuridad Eterna!','Abrazate a la oscuridad... ¡Oscuridad Eterna!','Прими Тьму! Тьма вечна...','Embrace the darkness... Darkness eternal!','16870','1','0','0','deathwhisper SAY_KILL2'), + +-- Saurfang +('-1631028','¡POR EL PODER DEL REY EXÁNIME!','¡POR EL PODER DEL REY EXÁNIME!','Во имя Короля-Лича!','BY THE MIGHT OF THE LICH KING!','16694','1','0','0','saurfang SAY_AGGRO'), +('-1631029','¡El suelo se vuelve rojo con tu sangre!','¡El suelo se vuelve rojo con tu sangre!','Земля обагрится вашей кровью!','The ground runs red with your blood!','16699','1','0','0','saurfang SAY_FALLENCHAMPION'), +('-1631030','¡Comed esbirros mios!','¡Comed esbirros mios!','Веселитесь, слуги мои!','Feast, my minions!','16700','3','0','0','saurfang SAY_BLOODBEASTS'), +('-1631031','¡No eres nada!','¡No eres nada!','Ты никто!','You are nothing!','16695','1','0','0','saurfang SAY_KILL1'), +('-1631032','¡Tu alma no encontrará redención!','¡Tu alma no encontrará redención!','Ваши души не найдут здесь избавления!','Your soul will find no redemption here!','16696','1','0','0','saurfang SAY_KILL2'), +('-1631033','¡Yo soy la muerte!','¡Yo soy la muerte!','Я вижу приближение смерти!','I have become... death!','16698','3','0','0','saurfang SAY_BERSERK'), +('-1631034','Me... he... liberado.','Me... he... liberado.','Я... Освободился...','I... Am... Released.','16697','1','0','0','saurfang SAY_DEATH'), +('-1631035','Entonces ¡Vámonos! Sali...','Entonces ¡Vámonos! Sali...','','Let\'s get a move on then! Move ou...',16974,1,0,0,'bronzebeard SAY_INTRO_ALLY_0'), +('-1631036','Por cada soldado de la Horda que matásteis, por cada perro de la Alianza que cayó, el ejercito del Rey Exánime creció. Ahora hasta las Valkyr alzan a los caídos para la plaga.','Por cada soldado de la Horda que matásteis, por cada perro de la Alianza que cayó, el ejercito del Rey Exánime creció. Ahora hasta las Valkyr alzan a los caídos para la plaga.','Все павшие воины орды, все дохлые псы альянса - все пополнят армию Короля-Лича! Даже сейчас валькиры воскрешают ваших покойников, чтобы они стали частью Плети!','For every Horde soldier that you killed, for every Alliance dog that fell, the Lich King\'s armies grew. Even now the Val\'kyr work to raise your fallen... As Scourge.','16701','1','0','0','saurfang SAY_INTRO'), +('-1631037','Las cosas se van a poner mucho peor. ¡Venid!, ¡probad el poder que el Rey Exánime me ha concedido!','Las cosas se van a poner mucho peor. ¡Venid!, ¡probad el poder que el Rey Exánime me ha concedido!','Сейчас все будет еще хуже. Идите сюда, я покажу вам, какой силой меня наделил Король-Лич!','Things are about to get much worse. Come, taste the power that the Lich King has bestowed upon me!','16702','1','0','0','saurfang SAY_BERSERK'), +('-1631038','¿Un solo orco, contra el poder de la Alianza?','¿Un solo orco, contra el poder de la Alianza?','','A lone orc, against the might of the Alliance?',16970,1,0,0,'bronzebeard SAY_INTRO_ALLY_3'), +('-1631039','¡Cargad!','¡Cargad!','','Charge!',16971,1,0,0,'bronzebeard SAY_INTRO_ALLY_4'), +('-1631040','¡Jajajaja! Enanos.','¡Jajajaja! Enanos.','Ха-ха-ха. Дворфы!','Hahahaha! Dwarves.','16703','1','0','0','saurfang SAY'), +('-1631041','¡Kor\'kron, vámonos! ¡Campeones, vigilad vuestra retaguardia! La plaga ha sido..','¡Kor\'kron, vámonos! ¡Campeones, vigilad vuestra retaguardia! La plaga ha sido..','','Kor\'kron, move out! Champions, watch your backs. The Scourge have been..',17103,1,0,0,'overlord SAY_INTRO_HORDE_1'), +('-1631042','¡Únete a mi padre! Únete a mí y juntos aplastaremos el mundo en nombre de la plaga. ¡Por la gloria del Rey Exánime!','¡Únete a mi padre! Únete a mí y juntos aplastaremos el mundo en nombre de la plaga. ¡Por la gloria del Rey Exánime!','','Join me, father. Join me and we will crush this world in the name of the Scourge -- for the glory of the Lich King!',16704,1,0,0,'saurfang SAY_INTRO_HORDE_2'), +('-1631043','Mi hijo murió en la puerta de cólera. Solo he venido a recoger su cuerpo.','Mi hijo murió en la puerta de cólera. Solo he venido a recoger su cuerpo.','','My boy died at the Wrath Gate. I am here only to collect his body.',17097,0,0,0,'overlord SAY_INTRO_HORDE_3'), +('-1631044','¡Viejo y testarudo! ¿Que posibilidades tiene? Soy más fuerte y poderoso de lo que tu nunca serás.','¡Viejo y testarudo! ¿Que posibilidades tiene? Soy más fuerte y poderoso de lo que tu nunca serás.','','Stubborn and old. What chance do you have? I am stronger, and more powerful than you ever were.',16705,1,0,0,'saurfang SAY_INTRO_HORDE_4'), +('-1631045','Lo llamamos Dranosh. Quiere decir "Corazón de Draenor" en orco. No deje que los brujos se lo llevarán. Mi hijo estaba a salvo, los ancianos de Garadar lo escondian.','Lo llamamos Dranosh. Quiere decir "Corazón de Draenor" en orco. No deje que los brujos se lo llevarán. Mi hijo estaba a salvo, los ancianos de Garadar lo escondian.','','We named him Dranosh. It means "Heart of Draenor" in orcish. I would not let the warlocks take him. My boy would be safe, hidden away by the elders of Garadar.',17098,0,0,0,'overlord SAY_INTRO_HORDE_5'), +('-1631046','Antes de morir su madre, le prometí que cruzaría el portal oscuro yo solo. Viviera o muriera, mi hijo estaría a salvo, limpio.','Antes de morir su madre, le prometí que cruzaría el portal oscuro yo solo. Viviera o muriera, mi hijo estaría a salvo, limpio.','','I made a promise to his mother before she died; that I would cross the Dark Portal alone - whether I lived or died, my son would be safe. Untainted...',17099,0,0,0,'overlord SAY_INTRO_HORDE_6'), +('-1631047','Hoy, cumplo mi promesa.','Hoy, cumplo mi promesa.','','Today, I fulfill that promise.',17100,0,0,0,'overlord SAY_INTRO_HORDE_7'), +('-1631048','¡Alto señor Libramorte Colmillosauro carga!','¡Alto señor Libramorte Colmillosauro carga!','','High Overlord Saurfang charges!',17104,2,0,0,'overlord SAY_INTRO_HORDE_8'), +('-1631049','¡Viejo orco patético! Venid pues héroes, venid y enfrentaros al poder de la plaga.','¡Viejo orco patético! Venid pues héroes, venid y enfrentaros al poder de la plaga.','','Pathetic old orc. Come then heroes. Come and face the might of the Scourge!',16706,1,0,0,'saurfang SAY_INTRO_HORDE_9'), +('-1631050','%s jadea por aire','%s jadea por aire','','%s gasps for air',16975,2,0,0,'bronzebeard SAY_OUTRO_ALLY_1'), +('-1631051','Ese era el hijo de Colmillosauro, el comandante de la horda en la puerta de cólera. Un trágico final...','Ese era el hijo de Colmillosauro, el comandante de la horda en la puerta de cólera. Un trágico final...','','That was Saurfang\'s boy - the Horde commander at the Wrath Gate. Such a tragic end...',16976,0,0,0,'bronzebeard SAY_OUTRO_ALLY_2'), +('-1631052','¡Que demonios! ¡Allí a lo lejos!','¡Que demonios! ¡Allí a lo lejos!','','What in the... There, in the distance!',16977,0,0,0,'bronzebeard SAY_OUTRO_ALLY_3'), +('-1631053','¡Soldados, en formación! ¡Parece que la Horda viene de nuevo!','¡Soldados, en formación! ¡Parece que la Horda viene de nuevo!','','Soldiers, fall in! Looks like the Horde are comin\' in to take another shot!',16978,1,0,0,'bronzebeard SAY_OUTRO_ALLY_4'), +('-1631054','No me obligues, orco. No podemos dejarte pasar.','No me obligues, orco. No podemos dejarte pasar.','','Don\'t force my hand, orc. We can\'t let you pass.',16972,0,0,0,'bronzebeard SAY_OUTRO_ALLY_5'), +('-1631055','Detrás de ti esta el cuerpo de mi único hijo. Nada me alejará de él.','Detrás de ti esta el cuerpo de mi único hijo. Nada me alejará de él.','','Behind you lies the body of my only son. Nothing will keep me from him.',17094,0,0,0,'overlord SAY_OUTRO_ALLY_6'), +('-1631056','No... No puedo hacerlo. Vuelve a tu nave y te perdonaré la vida.','No... No puedo hacerlo. Vuelve a tu nave y te perdonaré la vida.','','He... I can\'t do it. Get back on your ship and we\'ll spare your life.',16973,0,0,0,'bronzebeard SAY_OUTRO_ALLY_7'), +('-1631057','¡Apartate, Muradin! Abre paso a un padre afligido.','¡Apartate, Muradin! Abre paso a un padre afligido.','','Stand down, Muradin. Let a grieving father pass.',16690,0,0,0,'varian SAY_OUTRO_ALLY_8'), +('-1631058','No\'ku kil zil\'nok ha tar.','No\'ku kil zil\'nok ha tar.','','No\'ku kil zil\'nok ha tar.',17096,0,1,0,'overlord SAY_OUTRO_ALLY_9'), +('-1631059','No olvidaré esta amabilidad. Te doy las gracias, alteza.','No olvidaré esta amabilidad. Te doy las gracias, alteza.','','I will not forget this kindess. I thank you, highness.',17095,0,0,0,'overlord SAY_OUTRO_ALLY_10'), +('-1631060','Yo... yo no estuve en la puerta de cólera. Pero los soldados supervivientes me contaron lo que ocurrió. Tu hijo luchó con honor, murió como un héroe. Se merece un entierro de héroe.','Yo... yo no estuve en la puerta de cólera. Pero los soldados supervivientes me contaron lo que ocurrió. Tu hijo luchó con honor, murió como un héroe. Se merece un entierro de héroe.','','I... I was not at the Wrathgate. But the soldiers who survived told me much of what happened. Your son fought with honor. He died a hero\'s death. He deserves a hero\'s burial.',16691,0,0,0,'varian SAY_OUTRO_ALLY_11'), +('-1631061','%s llora.','%s llora.','','%s cries.',16651,2,0,0,'proudmore SAY_OUTRO_ALLY_12'), +('-1631062','Jaina, ¿Por qué lloras?','Jaina, ¿Por qué lloras?','','Jaina, why are you crying?',16692,0,0,0,'varian SAY_OUTRO_ALLY_13'), +('-1631063','No es nada majestad. Solo... estoy orgullosa de mi Rey.','No es nada majestad. Solo... estoy orgullosa de mi Rey.','','It was nothing, your majesty. Just... I\'m proud of my king.',16652,0,0,0,'proudmore SAY_OUTRO_ALLY_14'), +('-1631064','Bah! Muradin, asegura la cubierta y prepara los soldados para el asalto de la parte superior de la Ciudadela. Enviaré otro regimiento desde Ventormenta.','Bah! Muradin, asegura la cubierta y prepara los soldados para el asalto de la parte superior de la Ciudadela. Enviaré otro regimiento desde Ventormenta.','','Bah! Muradin, secure the deck and prepare our soldiers for an assault on the upper citadel. I\'ll send out another regiment from Stormwind.',16693,0,0,0,'varian SAY_OUTRO_ALLY_15'), +('-1631065','¡Enseguida, majestad!','¡Enseguida, majestad!','','Right away, yer majesty!',16979,0,0,0,'bronzebeard SAY_OUTRO_ALLY_16'), +('-1631066','%s tose.','%s tose.','','%s coughs.',17105,2,0,0,'overlord SAY_OUTRO_HORDE_1'), +('-1631067','%s llora sobre el cuerpo de su hijo.','%s llora sobre el cuerpo de su hijo.','','%s weeps over the corpse of his son.',17106,2,0,0,'overlord SAY_OUTRO_HORDE_2'), +('-1631068','Tendrás una ceremonia digna en Nagrand, junto a las piras de tu madre y tus ancestros.','Tendrás una ceremonia digna en Nagrand, junto a las piras de tu madre y tus ancestros.','','You will have a proper ceremony in Nagrand next to the pyres of your mother and ancestors.',17101,0,0,0,'overlord SAY_OUTRO_HORDE_3'), +('-1631069','El Honor héroes... no importa lo atroz de la batalla... ¡Nunca renunciéis a él!','','','Honor, young heroes... no matter how dire the battle... Never forsake it!',17102,0,0,0,'overlord SAY_OUTRO_HORDE_4'), + +-- Rotface +('-1631070','¿Qué? ¿Precioso? ¡¡¡Noooooooooo!!!','¿Qué? ¿Precioso? ¡¡¡Noooooooooo!!!','Что? Прелесть? Не-е-е-т!','What? Precious? Noooooooooo!!!','16993','6','0','0','Rotface Precious played when precious dies'), +('-1631071','¡Weeeeee! ¡Ja-ha-ha-ha!','¡Weeeeee! ¡Ja-ha-ha-ha!','Й-й-йя-хахаха!','WEEEEEE!','16986','1','0','0','Rotface Aggro'), +('-1631073','Creo que poo-poo enfadado. ¡Va a hacer booom!','Creo que poo-poo enfadado. ¡Va a hacer booom!','Я сделал очень злую каку! Сейчас взорвется!','I think I made an angry poo-poo. It gonna blow!','16992','1','0','0','Rotface Unstable Ooze'), +('-1631074','¡Grandes noticias amigos! ¡Las babosas vuelven a fluir!','¡Grandes noticias amigos! ¡Las babosas vuelven a fluir!','Отличные новости народ! Слизь снова потекла!','Great news, everyone! The slime is flowing again!','17126','1','0','0','putricide SAY_SLIME_FLOW_1'), +('-1631075','¡Buenas noticias amigos! He arreglado las tuberías de babosas venenosas.','¡Buenas noticias amigos! He arreglado las tuberías de babosas venenosas.','Отличные новости народ! Я починил трубы для подачи ядовитой смеси!','Good news, everyone! I\'ve fixed the poison slime pipes!','17123','1','0','0','putricide SAY_SLIME_FLOW_2'), +('-1631076','¡Papi hará juguetes contigo!','¡Papi hará juguetes contigo!','Папочка сделает новые игрушки из тебя!','Daddy make toys out of you!','16988','1','0','0','Rotface Slay 02'), +('-1631077','¡Lo he rooooto!','¡Lo he rooooto!','Я ЭТО заломал!','I brokes-ded it...','16987','1','0','0','Rotface Slay 01'), +('-1631078','¡Hora de dormir!','¡Hora de dormir!','Тихий час!','Sleepy Time!','16990','1','0','0','Rotface Berserk'), +('-1631079','¡Malas noticias papá!','¡Malas noticias papá!','Папочка, не огорчайся...','Bad news daddy.','16989','1','0','0','Rotface Death'), +('-1631080','','','','Terrible news, everyone, Rotface is dead! But great news everyone, he left behind plenty of ooze for me to use! Whaa...? I\'m a poet, and I didn\'t know it? Astounding!',17146,6,0,0,'putricide SAY_ROTFACE_DEATH'), +-- +('-1631226','Moco megajoso.','Moco megajoso.','Липучка-вонючка!','Icky sticky.','16991','1','0','0','Rotface Infection'), +('-1631229','Ja-a-a-a-a','Ja-a-a-a-a','Й-а-а-а!','...','16994','1','0','0','Rotface say'), +('-1631230','¡Ñaaa!','¡Ñaaa!','Ах!','...','16995','1','0','0','Rotface say'), +('-1631231','А-а-у!','А-а-у!','А-а-у!','...','16996','1','0','0','Rotface say'), + +-- Festergut +('-1631081','¡NOOOOOOO! ¡Has matado a apestoso! ¡Paga!','¡NOOOOOOO! ¡Has matado a apestoso! ¡Paga!','Нет! Вы убили Вонючку! Сейчас получите!','NOOOO! You kill Stinky! You pay!','16907','6','0','0','Festergut Stinky Death '), +('-1631082','¡A divertirse!','¡A divertirse!','Повеселимся!','Fun time!','16901','1','0','0','Festergut Aggro'), +('-1631083','Una nube de gas ordinaria. Pero cuidado porque no es una nube de gas ordinaria.','Una nube de gas ordinaria. Pero cuidado porque no es una nube de gas ordinaria.','Это обычное облако газа. Но будьте осторожны, не такое уж оно и обычное...','Just an ordinary gas cloud. But watch out, because that\'s no ordinary gas cloud!','17119','1','0','0','Putricide Gas Explosion'), +('-1631084','%s se tira un pedo.','%s se tira un pedo.','%s пукнул.','%s farts.','16911','2','0','0','Festergut brrr '), +('-1631085','No me encuentro bien...','No me encuentro bien...','Что-то мне нехорошо...','Gyah! Uhhh, I not feel so good...','16906','1','0','0','Festergut Explunge Blight'), +('-1631086','%s vomita.','%s vomita.','','%s vomits',0,2,0,0,'festergut SAY_PUNGUENT_BLIGHT_EMOTE'), +('-1631087','Papi, ¡lo hice!','Papi, ¡lo hice!','Папочка! У меня получилось!','Daddy, I did it!','16902','1','0','0','Festergut Slay 01'), +('-1631088','¡Muerto, muerto, muerto!','¡Muerto, muerto, muerto!','Мертвец! Мертвец! Мертвец!','Dead, dead, dead!','16903','1','0','0','Festergut Slay 02'), +('-1631089','¡No más diversión!','¡No más diversión!','Веселью конец!','Fun time over!','16905','1','0','0','Festergut Berserk'), +('-1631090','A-a-a-a-a... Pa ... Pi...','A-a-a-a-a... Pa ... Pi...','А-а-а-а-а...','Da ... Ddy...','16904','1','0','0','Festergut Death'), +('-1631091','Oh, Panzachancro. Eras mi preferido junto a Carapútrea. La buena noticia es que has dejado tanto gas que casi puedo saborearlo.','Oh, Panzachancro. Eras mi preferido junto a Carapútrea. La buena noticia es que has dejado tanto gas que casi puedo saborearlo.','Тухлопуз! Ты всегда был моим любимчиком, как и Гниломорд... Молодец, что оставил столько газа. Я его даже чувствую.','Oh, Festergut. You were always my favorite. Next to Rotface. The good news is you left behind so much gas, I can practically taste it!','17124','6','0','0','Putricide Festergut Dead'), +-- +('-1631210','...','...','Их-ха!','...','16908','1','0','0','Festergut say '), +('-1631211','...','...','Ы-ы-ы!','...','16909','1','0','0','Festergut say '), +('-1631212','...','...','(Непереводимо)','...','16910','1','0','0','Festergut say '), + +-- Professor Putricide +('-1631092','¡Buenas noticias amigos! Creo que he perfeccionado una plaga que destruirá toda la vida en Azeroth.','¡Buenas noticias amigos! Creo que he perfeccionado una plaga que destruirá toda la vida en Azeroth.','Отличные новости народ! Я усовершенствовал штамм чумы, которая уничтожит весь Азерот!','Good news, everyone! I think I perfected a plague that will destroy all life on Azeroth!','17114','1','0','0','Putricide Aggro'), +('-1631093','¡No podéis entrar así de sucios aquí! Hay que quitaros esa asquerosa piel primero.','¡No podéis entrar así de sucios aquí! Hay que quitaros esa asquerosa piel primero.','Вы слишком грязные чтобы тут расхаживать! Надо сперва соскрести эту мерзкую плоть.','You can\'t come in here all dirty like that! You need that nasty flesh scrubbed off first!','17125','1','0','0','Putricide Airlock01 Before fight'), +('-1631094','¡Dos mocos, una sala! Tantas posibilidades estupendas...','¡Dos mocos, una sala! Tantas posibilidades estupendas...','Два слизнюка в одной комнате? Может получиться что-то любопытное...','Two oozes, one room! So many delightful possibilities...','17122','1','0','0','Putricide Summon Ooze'), +('-1631095','Hmmmm. No siento nada. ¿Queeee? ¿De dónde salió eso?','Hmmmm. No siento nada. ¿Queeee? ¿De dónde salió eso?','Что-то я ничего не чувствую. Что? Это еще откуда?','Hmm. I don\'t feel a thing. Whaa...? Where\'d those come from?','17120','1','0','0','Putricide Transform 01'), +('-1631096','Sabe a... ¡FRESA! ¡Ohhh! ¡Perdón!','Sabe a... ¡FRESA! ¡Ohhh! ¡Perdón!','На вкус как вишенка. Ой, извините...','Tastes like... Cherry! Oh! Excuse me!','17121','1','0','0','Putricide Transform 02'), +('-1631097','M-m-m... Interesante...','M-m-m... Interesante...','М-м-м. Интересно.','Hmm... Interesting...','17115','1','0','0','Putricide Slay 01'), +('-1631098','¡Qué inesperado!','¡Qué inesperado!','О, как неожиданно!','That was unexpected!','17116','1','0','0','Putricide Slay 02'), +('-1631099','¡Excelentes noticias amigos!','¡Excelentes noticias amigos!','Прекрасные новости, народ!','Great news, everyone!','17118','1','0','0','Putricide Berserk'), +('-1631100','¡Malas noticias amigos! No creo que sobreviva.','¡Malas noticias amigos! No creo que sobreviva.','Плохие новости, народ... Похоже, у меня ничего не выйдет.','Bad news, everyone! I don\'t think I\'m going to make it.','17117','1','0','0','Putricide Death'), + +-- Blood Prince Council +('-1631101','¡Estúpidos! ¿Pensásteis que nos derrotaríais tan facilmente? ¡Los San\'layn son los soldados inmortales del Rey Exánime! ¡Ahora os enfrentaréis a todos juntos!','¡Estúpidos! ¿Pensásteis que nos derrotaríais tan facilmente? ¡Los San\'layn son los soldados inmortales del Rey Exánime! ¡Ahora os enfrentaréis a todos juntos!','Глупые смертные! Думали, что одолели нас? Санлейн, непобедимые воины Короля-Лича! Теперь наши силы едины!','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 Intro Princes'), +('-1631102','¡Alzaos hermanos y destruid al enemigo!','¡Alzaos hermanos y destruid al enemigo!','Восстаньте, братья, и уничтожьте наших врагов!','Arise, brothers, and destroy our enemies!','16796','1','0','0','Lanathel resurrect Princes'), + +-- Keleseth +('-1631103','','','','Such wondrous power! The Darkfallen Orb has made me INVINCIBLE!',16727,1,0,0,'keleseth SAY_KELESETH_INVOCATION'), +('-1631104','','','','Blood will flow!',16728,1,0,0,'keleseth SAY_KELESETH_SPECIAL'), +('-1631105','','','','Were you ever a threat?',16723,1,0,0,'keleseth SAY_KELESETH_SLAY_1'), +('-1631106','','','','Truth is found in death.',16724,1,0,0,'keleseth SAY_SKELESETH_SLAY_2'), +('-1631107','','','','%s cackles maniacally!',16726,2,0,0,'keleseth SAY_KELESETH_BERSERK'), +('-1631108','','','','My queen... they come...',16725,1,0,0,'keleseth SAY_KELESETH_DEATH'), + +-- Taldaram +('-1631109','','','','Tremble before Taldaram, mortals, for the power of the orb flows through me!',16857,1,0,0,'taldaram SAY_TALDARAM_INVOCATION'), +('-1631110','','','','Delight in the pain!',16858,1,0,0,'taldaram SAY_TALDARAM_SPECIAL'), +('-1631111','','','','Worm food.',16853,1,0,0,'taldaram SAY_TALDARAM_SLAY_1'), +('-1631112','','','','Beg for mercy!',16854,1,0,0,'taldaram SAY_TALDARAM_SLAY_2'), +('-1631113','','','','%s laughs.',16856,2,0,0,'taldaram SAY_TALDARAM_BERSERK'), +('-1631114','','','','%s gurgles and dies.',16855,2,0,0,'taldaram SAY_TALDARAM_DEATH'), + +-- Valanar +('-1631115','','','Наксанар был досадным недоразумением! Силы сферы позволят Валанару свершить отмщение!','Naxxanar was merely a setback! With the power of the orb, Valanar will have his vengeance!','16685','1','0','0','Valanar Empower'), +('-1631117','La cena... está servida.','La cena... está servida.','Кушать подано!','Dinner... is served.','16681','1','0','0','Valanar Slay 01'), +('-1631118','','','Теперь вы видите, насколько мы сильны?','Do you see NOW the power of the Darkfallen?','16682','1','0','0','Valanar Slay 02'), +('-1631119','','','Хорош тянуть время перед Санлейн!','BOW DOWN BEFORE THE SAN\'LAYN!','16684','1','0','0','Valanar Berserk'), +('-1631120','','','Охохо...','...why...?','16683','1','0','0','Valanar Death'), + +-- Council says +('-1631307','','','Моя чаша полна','My cup runneth over.','16686','1','0','0','Princes Special (attack)'), +('-1631308','...','...','Йих!','...','16687','1','0','0','Princes say'), +('-1631309','...','...','Э-эх!','...','16688','1','0','0','Princes say'), +('-1631310','...','...','До-хо!','...','16689','1','0','0','Princes say'), + +-- Blood Queen Lana'thel +('-1631121','Habéis tomado una decisión incorrecta...','Habéis tomado una decisión incorrecta...','Это было неразумное решение!','You have made an... unwise... decision.','16782','1','0','0','Lanathel Aggro'), +('-1631122','Solo probar...','Solo probar...','Я только попробую на вкус...','Just a taste...','16783','1','0','0','Lanathel Bite 01'), +('-1631123','¡Conoced mi hambre!','¡Conoced mi hambre!','Я голодна!','Know my hunger!','16784','1','0','0','Lanathel Bite 02'), +('-1631124','¡SUFRID!','¡SUFRID!','Страдайте же!','SUFFER!','16786','1','0','0','Lanathel Special 01'), +('-1631125','¿Podéis aguantar esto?','¿Podéis aguantar esto?','Как вам такое?','Can you handle this?','16787','1','0','0','Lanathel Special 02'), +('-1631126','Sí... come vida mía. ¡Ahora me perteneces!','Sí... come vida mía. ¡Ahora me perteneces!','Нет. Моя прелесть, приятного аппетита!','Yes... feed my precious one! You\'re mine now!','16790','1','0','0','Lanathel Mind Control'), +('-1631127','¡Aquí viene! Mmmmm ja-ja-ja-ja.','¡Aquí viene! Mmmmm ja-ja-ja-ja.','Начинаем представление!','Here it comes.','16788','1','0','0','Lanathel Special 03'), +('-1631128','¡Esto acaba AHORA!','¡Esto acaba AHORA!','Сейчас все кончится!','THIS! ENDS! NOW!','16793','1','0','0','Lanathel Berserk'), +('-1631129','Pero... si nos caíamos tan... bien.','Pero... si nos caíamos tan... bien.','Но... Мы ведь так хорошо ладили...','But... we were getting along... so well...','16794','1','0','0','Lanathel Death'), +-- +('-1631324','¡La muerte no es salida!','¡La muerte no es salida!','Смерть вас не спасет!','Death is no escape!','16785','1','0','0','Lanathel Add'), +('-1631328','Qué... desafortunado... hahahahaha','Qué... desafortunado... hahahahaha','Не повезло...','How... Unfortunate...','16789','1','0','0','Lanathel Reset'), +('-1631330','¿En serio? ¿Eso es todo?','¿En serio? ¿Eso es todo?','Вот как... У тебя не получилось?','Really...? Is that all you\'ve got?','16791','1','0','0','Lanathel Slay 01'), +('-1631331','¡Qué pena!','¡Qué pena!','Какая жалость...','Such a pity!','16792','1','0','0','Lanathel Slay 02'), + +-- Svalna event +('-1631130','','','','Ready your arms, my Argent Brothers. The Vrykul will protect the Frost Queen with their lives.',16819,1,0,0,'scourgebane SAY_SVALNA_EVENT_1'), +('-1631131','','','','Even dying here beats spending another day collecting reagents for that madman, Finklestein.',16585,1,0,0,'arnath SAY_SVALNA_EVENT_2'), +('-1631132','','','','Enough idle banter! Our champions have arrived - support them as we push our way through the hall!',16820,1,0,0,'scourgebane SAY_SVALNA_EVENT_3'), +('-1631133','','','','You may have once fought beside me, Crok, but now you are nothing more than a traitor. Come, your second death approaches!',17017,1,0,0,'svalna SAY_SVALNA_EVENT_4'), +('-1631134','','','','Miserable creatures, Die!',17018,1,0,0,'svalna SAY_KILLING_CRUSADERS'), +('-1631135','','','','Foolish Crok, you brought my reinforcements with you! Arise Argent Champions and serve the Lich King in death!',17019,1,0,0,'svalna SAY_RESSURECT'), +('-1631136','','','','Come Scourgebane, I\'ll show the Lich King which one of us is truly worthy of the title, champion!',17020,1,0,0,'svalna SAY_SVALNA_AGGRO'), +('-1631137','','','','What? They died so easily? No matter.',17022,1,0,0,'svalna SAY_KILL_CAPTAIN'), +('-1631138','','','','What a pitiful choice of an ally Crok.',17021,1,0,0,'svalna SAY_KILL_PLAYER'), +('-1631139','','','','Perhaps... you were right... Crok, you must not approach the Frost Queen, quickly, stop them!',17023,1,0,0,'svalna SAY_DEATH'), + +-- Valithria Dreamwalker +('-1631140','¡Héroes, ayudadme! No... ¡No puedo retenerlos mucho más tiempo! ¡Debéis sanar mis heridas!','¡Héroes, ayudadme! No... ¡No puedo retenerlos mucho más tiempo! ¡Debéis sanar mis heridas!','Герои! Вы должны мне помочь! Мои силы на исходе... Залечите мои раны...','Heroes, lend me your aid! I... I cannot hold them off much longer! You must heal my wounds!','17064','1','0','0','Valithria Aggro'), +('-1631141','He abierto un portal hacia el sueño. Vuestra salvación está dentro, héroes.','He abierto un portal hacia el sueño. Vuestra salvación está dentro, héroes.','Я открыла портал в изумрудный сон. Там вы найдете спасение, герои!','I have opened a portal into the Dream. Your salvation lies within, heroes.','17068','1','0','0','Valithria Dream World Open'), +('-1631142','¡Mi fuerza vuelve! ¡Continuad héroes!','¡Mi fuerza vuelve! ¡Continuad héroes!','Силы возвращаются ко мне! Герои, еще немного!','My strength is returning! Press on, heroes!','17070','1','0','0','Valithria Health High'), +('-1631143','¡No aguantaré mucho más!','¡No aguantaré mucho más!','Я долго не продержусь!','I will not last much longer!','17069','1','0','0','Valithria Health Low'), +('-1631144','¡Perdonadme por mis actos! No... puedo... ¡SOLO QUEDAN PESADILLAS!','¡Perdonadme por mis actos! No... puedo... ¡SOLO QUEDAN PESADILLAS!','Простите меня, я не могу остано... ВСЕ ВО ВЛАСТИ КОШМАРА!','Forgive me for what I do! I... cannot... stop... ONLY NIGHTMARES REMAIN!','17072','1','0','0','Valithria Lose'), +('-1631145','Una trágica pérdida...','Una trágica pérdida...','Прискобная потеря.','A tragic loss...','17066','1','0','0','Valithria Slay Good - Player'), +('-1631146','¡FRACASADOS!','¡FRACASADOS!','Неудачники!','FAILURES!','17067','1','0','0','Valithria Berserk'), +('-1631147','¡Estoy renovada! ¡Ysera!, haz que estas asquerosas criaturas descansen.','¡Estoy renovada! ¡Ysera!, haz que estas asquerosas criaturas descansen.','Я излечилась! Изера, даруй мне силу покончить с этими нечестивыми тварями!','I am renewed! Ysera grants me the favor to lay these foul creatures to rest!','17071','1','0','0','Valithria Win'), +-- +('-1631402','Los crueles no merecen descanso...','Los crueles no merecen descanso...','Одержимые не знают отдыха...','No rest for the wicked...','17065','1','0','0','Valithria Slay Bad Hostile NPC'), + +-- Spider event (absent) + +-- Sindragosa +('-1631148','¡Estáis locos por haber venido aquí! ¡Los vientos helados de Rasganorte consumirán vuestras almas!','¡Estáis locos por haber venido aquí! ¡Los vientos helados de Rasganorte consumirán vuestras almas!','Глупцы! Зачем вы сюда явились? Ледяные ветра Нордскола унесут ваши души!','You are fools who have come to this place! The icy winds of Northrend will consume your souls!','17007','1','0','0','Sindragosa Aggro'), +('-1631149','¡Sufrid mortales al ver que vuestra patética mágia os traiciona!','¡Sufrid mortales al ver que vuestra patética mágia os traiciona!','Трепещите, смертные! Ибо ваша жалкая магия теперь бессильна!','Suffer, mortals, as your pathetic magic betrays you!','17014','1','0','0','Sindragosa Arcane'), +('-1631150','¿Podéis sentir el toque helado de la muerte en el corazón?','¿Podéis sentir el toque helado de la muerte en el corazón?','Вы чувствуете, как ледяная ладонь смерти сжимает сердце?','Can you feel the cold hand of death upon your heart?','17013','1','0','0','Sindragosa Freeze'), +('-1631151','¡A-a-a-a-aaa! ¡Quema! ¿Qué brujería es esta?','¡A-a-a-a-aaa! ¡Quema! ¿Qué brujería es esta?','А-а-а! ЖжОт! Что это за колдовство?','Suffer, mortals, as your pathetic magic betrays you!','17015','1','0','0','Sindragosa Special'), +('-1631152','¡Aquí termina vuestra incursión! ¡Nadie sobrevivirá!','¡Aquí termina vuestra incursión! ¡Nadie sobrevivirá!','Здесь ваше вторжение и окончится! Никто не уцелеет!','Your incursion ends here! None shall survive!','17012','1','0','0','Sindragosa Take Off - fly'), +('-1631153','¡Ahora sentid el poder sin fín de mi maestro y desesperad!','¡Ahora sentid el poder sin fín de mi maestro y desesperad!','А теперь почувствуйте всю мощь Господина и погрузитесь в отчаяние!','Now feel my master\'s limitless power and despair!','17016','1','0','0','Sindragosa Low HP'), +('-1631154','¡Morid!','¡Morid!','Погибни!','Perish!','17008','1','0','0','Sindragosa Slay 01'), +('-1631155','Defecto de mortalidad...','Defecto de mortalidad...','Удел смертных!','A flaw of mortality...','17009','1','0','0','Sindragosa Slay 02'), +('-1631156','¡Basta! ¡Estos juegos me cansan!','¡Basta! ¡Estos juegos me cansan!','Хватит! Эти игры меня утомляют!','Enough! I tire of these games!','17011','1','0','0','Sindragosa Berserk'), +('-1631157','¡Libre! Al fin...','¡Libre! Al fin...','Наконец-то! Свободна!','Free...at last...','17010','1','0','0','Sindragosa Death'), + +-- Lich king +('-1631158','Así que por fin ha llegado la gran justicia de la luz.','Así que por fin ha llegado la gran justicia de la luz.','Неужели прибыли, наконец, хваленые силы света? Мне бросить Ледяную скорбь и сдаться на твою милость, Фордринг?','So...the Light\'s vaunted justice has finally arrived. Shall I lay down Frostmourne and throw myself at your mercy, Fordring?','17349','1','0','0','Lich King SAY_INTRO1'), +('-1631160','','','Ты пройдешь через эти мучения сам.','You will learn of that first hand. When my work is complete, you will beg for mercy -- and I will deny you. Your anguished cries will be testament to my unbridled power.','17350','1','0','0','Lich King SAY_INTRO3'), +('-1631162','Te mantendré vivo para presenciar el final, Vadín. No me gustaría que el mejor campeón de la luz se perdiera en este mismo mundo rehecho a mi imagen.','Te mantendré vivo para presenciar el final, Vadín. No me gustaría que el mejor campeón de la luz se perdiera en este mismo mundo rehecho a mi imagen.','Я оставлю тебя в живых, чтобы ты увидел финал! Не могу допустить чтобы величайший служитель света пропустил рождение МОЕГО мира!','I\'ll keep you alive to witness the end, Fordring. I would not want the Light\'s greatest champion to miss seeing this wretched world remade in my image.','17351','1','0','0','Lich King SAY_AGGRO'), +('-1631163','¡Venid campeones, alimentadme con vuestra ira!','¡Venid campeones, alimentadme con vuestra ira!','Ну же, герои! В вашей ярости - МОЯ сила!','Come then champions, feed me your rage!','17352','1','0','0','Lich King SAY'), +('-1631164','¡Os congelaré las entrañas hasta convertiros en un caparazón de hielo!','¡Os congelaré las entrañas hasta convertiros en un caparazón de hielo!','Я проморожу вас насквозь и вы разлетитесь на ледяные осколки!','I will freeze you from within until all that remains is an icy husk!','17369','1','0','0','Lich King SAY'), +('-1631165','¡Contemplad el colapso de vuestro mundo!','¡Contemplad el colapso de vuestro mundo!','Смотрите, как мир рушится вокруг вас!','Watch as the world around you collapses!','17370','1','0','0','Lich King SAY_WIN'), +('-1631166','Val\'kyr, ¡Vuestro maestro os llama!','Val\'kyr, ¡Vuestro maestro os llama!','Валькирия! Твой господин зовет!','Val\'kyr, your master calls!','17373','1','0','0','Lich King SAY_SUMMON'), +('-1631167','La Agonía de Escarcha está hambrienta...','La Agonía de Escarcha está hambrienta...','Ледяная скорбь жаждет крови!','Frostmourne hungers...','17366','1','0','0','Lich King SAY'), +('-1631171','Argh... Agonía de Escarcha, ¡Obedéceme!','Argh... Agonía de Escarcha, ¡Obedéceme!','Ледяная скорбь, повинуйся мне!','Argh... Frostmourne, obey me!','17367','1','0','0','Lich King SAY'), +('-1631172','¡La Agonía de Escarcha se alimentará del alma de vuestro aliado!','¡La Agonía de Escarcha se alimentará del alma de vuestro aliado!','Ледяная скорбь поглотит душу вашего товарища!','Frostmourne feeds on the soul of your fallen ally!','17368','1','0','0','Lich King SAY_KILL'), +('-1631173','','','Конец света!','Apocalypse!','17371','1','0','0','Lich King SAY'), +('-1631174','','','Склонись перед своим господином и повелителем!','Bow down before your lord and master!','17372','1','0','0','Lich King SAY'), +('-1631175','','','Да! Вы меня и правда ранили. Я слишком долго с вами играл. Испытайте на себе возмездие Смерти!','You gnats actually hurt me! Perhaps I\'ve toyed with you long enough, now taste the vengeance of the grave!','17359','1','0','0','Lich King SAY'), +('-1631176','¡Adiós esperanza!','¡Adiós esperanza!','Надежда тает!','Hope wanes!','17363','1','0','0','Lich King SAY'), +('-1631177','¡El Fin ha llegado!','¡El Fin ha llegado!','Пришел конец!','The end has come!','17364','1','0','0','Lich King SAY'), +('-1631178','¡Enfrentaos a vuestro trágico final!','¡Enfrentaos a vuestro trágico final!','Встречайте трагический финал!','Face now your tragic end!','17365','1','0','0','Lich King SAY_KILL'), +('-1631179','','','Сомнений нет - вы сильнейшие герои Азерота! Вы преодолели все препятствия, которые я воздвиг перед вами! Сильнейшие из моих слуг пали под вашим натиском, сгорели в пламени вашей ярости!','No question remains unanswered. No doubts linger. You are Azeroth\'s greatest champions! You overcame every challenge I laid before you. My mightiest servants have fallen before your relentless onslaught, your unbridled fury..','17353','1','0','0','Lich King SAY'), +('-1631180','','','Что движет вами? Праведность? Не знаю...','Is it truly righteousness that drives you? I wonder.','17354','1','0','0','Lich King SAY'), +('-1631181','','','Ты отлично их обучил, Фордринг! Ты привел сюда лучших воинов, которых знал мир! И отдал их в мои руки. Как я и рассчитывал.','You trained them well, Fordring. You delivered the greatest fighting force this world has ever known... right into my hands -- exactly as I intended. You shall be rewarded for your unwitting sacrifice.','17355','1','0','0','Lich King SAY'), +('-1631182','','','Смотри как я буду воскрешать их и превращать в воинов Плети! Они повергнут этот мир в пучину хаоса. Азерот падет от их рук. И ты станешь первой жертвой. ','Watch now as I raise them from the dead to become masters of the Scourge. They will shroud this world in chaos and destruction. Azeroth\'s fall will come at their hands -- and you will be the first to die.','17356','1','0','0','Lich King SAY'), +('-1631183','Ja-ja-ja-ja... ¡No capta esta ironía!','Ja-ja-ja-ja... ¡No capta esta ironía!','Мне по душе эта ирония!','I delight in the irony.','17357','1','0','0','Lich King SAY'), +('-1631185','Imposible...','Imposible...','Невозможно!','Impossible...','17358','1','0','0','Lich King SAY'), +('-1631190','Aquí me hayo, como el lobo entre los corderos... y no me temen.','Aquí me hayo, como el lobo entre los corderos... y no me temen.','И вот я стою как лев пред агнцами. И не дрожат они.','Now I stand, the lion before the lambs... and they do not fear.','17361','1','0','0','Lich King SAY'), +('-1631191','No sienten miedo.','No sienten miedo.','Им неведом страх!','They cannot fear.','17362','1','0','0','Lich King SAY'), +('-1631528','','','%s убит','%s dies.','17374','1','0','0','Lich King SAY_DEATH'), +-- +('-1631514','А-а-х!','А-а-х!','А-а-х!','...','17360','1','0','0','Lich King SAY'), +('-1631531','¡Profanado!','¡Profanado!','Оскверняю!','Defile!','0','3','0','0','Lich King SAY'), + +-- Tirion +('-1631159','¡Te daremos una muerte rápida Arthas! ¡Más de lo que tuvieron aquellos a los que torturaste y asesinaste!','¡Te daremos una muerte rápida Arthas! ¡Más de lo que tuvieron aquellos a los que torturaste y asesinaste!','Мы даруем тебе быструю смерть, Артас! Более быструю чем ты заслуживаешь за то что замучил и погубил десятки тысяч жизней!','We will grant you a swift death, Arthas. More than can be said for the thousands you\'ve tortured and slain.','17390','1','0','0','Tirion SAY_INTRO2'), +('-1631161','Qué así sea. Campeones, ¡Atacar!','Qué así sea. Campeones, ¡Atacar!','Да будет так! Герои, в атаку','So be it. Champions, attack!','17391','1','0','0','Tirion SAY_INTRO4'), +('-1631184','Qué la luz... me vendiga por última vez. Dame fuerzas... para romper estas ataduras.','Qué la luz... me vendiga por última vez. Dame fuerzas... para romper estas ataduras.','Свет! Даруй мне последнее благословение! Дай мне разбить эти оковы!','LIGHT, GRANT ME ONE FINAL BLESSING. GIVE ME THE STRENGTH... TO SHATTER THESE BONDS!','17392','1','0','0','Tirion SAY'), +('-1631186','¡Basta Arthas! ¡Tu odio no consumirá más vidas!','¡Basta Arthas! ¡Tu odio no consumirá más vidas!','Хватит, Артас! Твоя ненависть не заберет больше ни одной жизни!','No more, Arthas! No more lives will be consumed by your hatred!','17393','1','0','0','Tirion SAY'), + +-- Menethil +('-1631168','¿Habéis venido para ajusticiar a Arthas? ¿Para ver la destrucción del Rey Exánime?','¿Habéis venido para ajusticiar a Arthas? ¿Para ver la destrucción del Rey Exánime?','Вы пришли чтобы вершить суд над Артасом? Чтобы уничтожить короля-лича?','You have come to bring Arthas to justice? To see the Lich King destroyed?','17394','1','0','0','Terenas Menethil II SAY'), +('-1631169','Primero, escapad del abrazo de la Agonía de Escarcha o estaréis condenado como yo, atrapado en esta maldita espada toda la eternidad.','Primero, escapad del abrazo de la Agonía de Escarcha o estaréis condenado como yo, atrapado en esta maldita espada toda la eternidad.','Вы не должны оказаться во власти Ледяной скорби. Иначе, как и я, будете навеки порабощены этим проклятым клинком.','First, you must escape Frostmourne\'s hold, or be damned as I am; trapped within this cursed blade for all eternity.','17395','1','0','0','Terenas Menethil II SAY'), +('-1631170','¡Ayudadme a destruir estas almas torturadas! ¡Juntos debilitaremos el poder de la Agonía de Escarcha y al Rey Exánime desde dentro!','¡Ayudadme a destruir estas almas torturadas! ¡Juntos debilitaremos el poder de la Agonía de Escarcha y al Rey Exánime desde dentro!','Помогите мне уничтожить эти истерзанные души. Вместе мы вытянем силу из ледяной скорби и ослабим короля-лича.','Aid me in destroying these tortured souls! Together we will loosen Frostmourne\'s hold and weaken the Lich King from within!','17396','1','0','0','Terenas Menethil II SAY'), +('-1631187','¡Libre al fin! Se acabó hijo mío. Es la hora del juicio final.','¡Libre al fin! Se acabó hijo mío. Es la hora del juicio final.','Наконец я свободен. Все кончено, сын мой. Настал час расплаты.','Free at last! It is over, my son. This is the moment of reckoning.','17397','1','0','0','Terenas Menethil II SAY'), +('-1631188','¡Alzaos, campeones de la luz!','¡Alzaos, campeones de la luz!','Поднимитесь, воины света!','Rise up, champions of the Light!','17398','1','0','0',' SAY'), + +-- Adds +('-1631590','','','Р-р-р-рота, подъем!','P-rr-company, the rise of','0','1','0','0','custom message'), +('-1631591','','','Хилы, не спать!','Heals, do not sleep','0','1','0','0','custom message'), +('-1631592','','','ДД поднажали!','DD put pressure','0','1','0','0','custom message'), +('-1631593','','','Лидер, гони лентяев из рейда! А то еще час возиться будете!','Leader, get lazy from a raid! And then another hour to tinker will','0','1','0','0','custom message'), +('-1631594','','','Ну вот вы и прикончили Артаса. Теперь будем ждать Катаклизм.','Well, you finished off Arthas. Now we wait for the cataclysm','0','1','0','0','custom message'); + +-- Gossips +DELETE FROM `gossip_texts` WHERE `entry` BETWEEN -3631608 AND -3631600; +INSERT INTO `gossip_texts` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`, `comment`) VALUES +('-3631600', "Light\'s Hammer", NULL, NULL, NULL, NULL, NULL, "Martillo de la Luz", "Martillo de la Luz", "Молот света", "IceCrown citadel teleporter text 1"), +('-3631601', "Oratory of the Damned", NULL, NULL, NULL, NULL, NULL, "Oratorio de los Malditos", "Oratorio de los Malditos", "Молельня проклятых", "IceCrown citadel teleporter text 2"), +('-3631602', "Rampart of Skulls", NULL, NULL, NULL, NULL, NULL, "La Muralla de las Calaveras", "La Muralla de las Calaveras", "Черепной вал", "IceCrown citadel teleporter text 3"), +('-3631603', "Deathbringer\'s Rise", NULL, NULL, NULL, NULL, NULL, "Alto del Libramorte", "Alto del Libramorte", "Подъем Смертоносного", "IceCrown citadel teleporter text 4"), +('-3631604', "Icecrown Citadel", NULL, NULL, NULL, NULL, NULL, "Ciudadela de la Corona de Hielo", "Ciudadela de la Corona de Hielo", "Цитадель Ледяной Короны", "IceCrown citadel teleporter text 5"), +('-3631605', "The Sanctum of Blood", NULL, NULL, NULL, NULL, NULL, "El Sagrario de Sangre", "El Sagrario de Sangre", "Святилище крови", "IceCrown citadel teleporter text 6"), +('-3631606', "Frost Queen\'s Lair", NULL, NULL, NULL, NULL, NULL, "La Guarida de la Reina de Escarcha", "La Guarida de la Reina de Escarcha", "Логово Королевы льда", "IceCrown citadel teleporter text 7"), +('-3631607', "Frozen Throne", NULL, NULL, NULL, NULL, NULL, "El Trono Helado", "El Trono Helado", "Ледяной трон", "IceCrown citadel teleporter text 8"), +('-3631608', "We are ready, Tirion!", NULL, NULL, NULL, NULL, NULL, "¡Estamos preparados, Tirion!", "¡Estamos preparados, Tirion!", "Всегда готовы, дедуля!", "IceCrown citadel Tirion gossip"); + +-- Icecrown citadel spelltable + +-- Lord Marrowgar +DELETE FROM `boss_spell_table` WHERE `entry` = 36612; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36612, 69055, 70814, 69055, 70814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), -- handled by dynamic timer in script +(36612, 69138, 0, 0, 0, 6000, 0, 0, 0, 12000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36612, 71580, 0, 0, 0, 6000, 0, 0, 0, 12000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36612, 69146, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36612, 69057, 0, 0, 0, 17000, 0, 0, 0, 27000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(36612, 69076, 0, 0, 0, 45000, 0, 0, 0, 60000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36612, 69075, 0, 0, 0, 2000, 0, 0, 0, 2000, 0, 0, 0, 5, 0, 0, 12, 0, 0), +(36612, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36612, 38711, 20000, 40000, 1, 1, 2, 2, 1, 5, 0, 9), +(36612, 36672, 45000, 45000, 1, 1, 2, 2, 75, 100, 0, 9); +-- Cold flame +DELETE FROM `boss_spell_table` WHERE `entry` = 36672; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36672, 69145, 0, 0, 0, 3000, 3000, 8000, 8000, 3000, 3000, 8000, 8000, 15, 15, 15, 15, 0, 0, 0, 1, 0, 0), +(36672, 69147, 0, 0, 0, 700, 0, 0, 0, 700, 0, 0, 0, 15000, 15000, 30000, 30000, 0, 0, 0, 1, 0, 0), +(36672, 69146, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36672, 36672, 30000, 30000, 1, 1, 1, 1, 0, 0, 0, 11); +-- Bone spike +DELETE FROM `boss_spell_table` WHERE `entry` = 38711; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38711, 46598, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 18, 0, 0), +(38711, 69065, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 6, 0, 0); + +-- Lady Deathwhisper +DELETE FROM `boss_spell_table` WHERE `entry` = 36855; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36855, 70842, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 1, 0, 0), +(36855, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 1, 0, 0), +(36855, 71254, 72008, 72008, 72504, 5000, 0, 0, 0, 8000, 0, 0, 0, 4, 0, 0), +(36855, 71420, 72501, 72007, 72502, 15000, 0, 0, 0, 25000, 0, 0, 0, 4, 0, 0), +(36855, 71001, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 4, 0, 0), +(36855, 71204, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 3, 0, 0), +(36855, 70901, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 6, 0, 0), +(36855, 71289, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 4, 0, 0), +(36855, 71494, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 1, 0, 0); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36855, 37890, 45000, 75000, 1, 1, 2, 2, 75, 100, 0, 11), +(36855, 37949, 45000, 75000, 1, 1, 2, 2, 75, 100, 0, 11), +(36855, 38010, 45000, 45000, 1, 1, 2, 2, 75, 100, 0, 9), +(36855, 38222, 8000, 15000, 1, 1, 1, 1, 75, 100, 0, 9), +(36855, 38009, 45000, 45000, 1, 1, 2, 2, 75, 100, 0, 9); +-- Vengeful shade +DELETE FROM `boss_spell_table` WHERE `entry` = 38222; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38222, 71494, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 1, 0, 0), +(38222, 71544, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 3, 0, 0); +-- Adherent +DELETE FROM `boss_spell_table` WHERE `entry` = 37949; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37949, 71129, 0, 0, 0, 15000, 0, 0, 0, 20000, 0, 0, 0, 3, 0, 0), +(37949, 70594, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 4, 0, 0), +(37949, 71254, 0, 0, 0, 5000, 0, 0, 0, 15000, 0, 0, 0, 4, 0, 0), +(37949, 70906, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 4, 0, 0), +(37949, 70903, 0, 0, 0, 1000, 0, 0, 0, 2000, 0, 0, 0, 1, 0, 0), +(37949, 71237, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 3, 0, 0), +(37949, 70768, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 4, 0, 0), +(37949, 41236, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 1, 0, 0), +(37949, 71234, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 4, 0, 0); +-- Fanatic +DELETE FROM `boss_spell_table` WHERE `entry` = 37890; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37890, 70659, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 3, 0, 0), +(37890, 70670, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 3, 0, 0), +(37890, 70674, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 1, 0, 0); + +-- Gunship battle +-- Frost wyrm +DELETE FROM `boss_spell_table` WHERE `entry` = 37230; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37230, 70116, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 4, 0, 0), +(37230, 70362, 0, 0, 0, 20000, 0, 0, 0, 25000, 0, 0, 0, 4, 0, 0), +(37230, 70361, 0, 0, 0, 3000, 0, 0, 0, 5000, 0, 0, 0, 3, 0, 0), +(37230, 47008, 0, 0, 0, 180000, 0, 0, 0, 180000, 0, 0, 0, 1, 0, 0); + +-- Rotted frost giant +DELETE FROM `boss_spell_table` WHERE `entry` IN (38490, 38494); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38490, 64652, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 4, 0, 0), +(38490, 72865, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 4, 0, 0), +(38490, 47008, 0, 0, 0, 300000, 0, 0, 0, 300000, 0, 0, 0, 1, 0, 0); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38494, 64652, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 4, 0, 0), +(38494, 72865, 0, 0, 0, 25000, 0, 0, 0, 40000, 0, 0, 0, 4, 0, 0), +(38494, 47008, 0, 0, 0, 300000, 0, 0, 0, 300000, 0, 0, 0, 1, 0, 0); + +-- Deathbringer Saurfang +DELETE FROM `boss_spell_table` WHERE `entry` = 37813; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`,`data1`, `data2`, `data3`, `data4`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37813, 72178, 0, 0, 0, 20000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72371, 0, 0, 0, 3000, 0, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72256, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72293, 0, 0, 0, 35000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(37813, 72737, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37813, 72385, 0, 0, 0, 20000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37813, 72380, 0, 0, 0, 25000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37813, 72408, 0, 0, 0, 20000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37813, 72172, 0, 0, 0, 45000, 0, 0, 0, 45000, 0, 0, 0, 2, 5, 2, 5, 1, 0, 0), +(37813, 72173, 0, 0, 0, 45000, 0, 0, 0, 45000, 0, 0, 0, 2, 5, 2, 5, 1, 0, 0), +(37813, 72356, 0, 0, 0, 45000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72357, 0, 0, 0, 45000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72358, 0, 0, 0, 45000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72769, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37813, 72723, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 72242, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37813, 47008, 0, 0, 0, 480000, 0, 0, 0, 480000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(37813, 38508, 45000, 45000, 1, 1, 2, 2, 15, 25, 0, 9); +-- Blood beast +DELETE FROM `boss_spell_table` WHERE `entry` = 38508; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38508, 72176, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 1, 0, 0), +(38508, 72723, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 1, 0, 0), +(38508, 72769, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 1, 0, 0), +(38508, 21150, 0, 0, 0, 15000, 0, 0, 0, 27000, 0, 0, 0, 1, 0, 0); + + +-- Festergut +DELETE FROM `boss_spell_table` WHERE `entry` = 36626; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +( 36626, 69157, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69162, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69164, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69126, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +( 36626, 69152, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +( 36626, 69154, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +( 36626, 69165, 0, 0, 0, 10000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69195, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69278, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69279, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69290, 0, 0, 0, 20000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 69291, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 6, 0, 1), +( 36626, 72219, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +( 36626, 72227, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 6, 0, 1), +( 36626, 72272, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +( 36626, 69244, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +( 36626, 69248, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +( 36626, 72287, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +( 36626, 71379, 0, 0, 0, 20000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 6, 0, 1), +( 36626, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36626, 38548, 12000, 12000, 1, 1, 1, 1, 10, 20, 0, 11); + +-- Rotface +DELETE FROM `boss_spell_table` WHERE `entry` = 36627; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`,`data1`, `data2`, `data3`, `data4`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36627, 69508, 0, 0, 0, 15000, 0, 0, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36627, 69674, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(36627, 70003, 0, 0, 0, 15000, 0, 0, 0, 15000, 0, 0, 0, 1, 2, 1, 3, 6, 0, 0), +(36627, 69788, 0, 0, 0, 20000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36627, 69783, 0, 0, 0, 30000, 0, 0, 0, 45000, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(36627, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36627, 69789, 0, 0, 0, 20000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 0, 6, 0, 1); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36627, 36897, 12000, 12000, 1, 1, 1, 1, 1, 5, 0, 9), +(36627, 37986, 15000, 15000, 1, 1, 1, 1, 10, 20, 0, 11), +(36627, 37013, 15000, 15000, 1, 1, 1, 1, 0, 0, 0, 11); +-- Small ooze +DELETE FROM `boss_spell_table` WHERE `entry` = 36897; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36897,69774, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 4, 0, 0), +(36897,69750, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 1, 0, 0), +(36897,69644, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 6, 0, 0), +(36897,69889, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 6, 0, 0); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36897, 36899, 12000, 12000, 1, 1, 1, 1, 1, 5, 0, 9); +-- Big ooze +DELETE FROM `boss_spell_table` WHERE `entry` = 36899; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36899,69774, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 4, 0, 0), +(36899,69839, 0, 0, 0, 6000, 0, 0, 0, 6000, 0, 0, 0, 1, 0, 0), +(36899,69760, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 1, 0, 0), +(36899,69644, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 1, 0, 0), +(36899,69558, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 1, 0, 0), +(36899,69889, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 6, 0, 0); +-- Ooze explode stalker +DELETE FROM `boss_spell_table` WHERE `entry` = 38107; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38107,69840, 0, 0, 0, 2000, 0, 0, 0, 2000, 0, 0, 0, 1, 0, 0); + +-- Professor Putricide +DELETE FROM `boss_spell_table` WHERE `entry` = 36678; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36678,70351, 0, 0, 0, 40000, 0, 0, 0, 60000, 0, 0, 0, 0, 1, 0, 0), +(36678,71617, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 3, 0, 0), +(36678,71615, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 100, 12, 0, 0), +(36678,71618, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 100, 12, 0, 0), +(36678,71621, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 3, 0, 0), +(36678,71278, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 3, 0, 0), +(36678,71279, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 3, 0, 0), +(36678,71893, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 3, 0, 0), +(36678,71273, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 1, 0, 0), +(36678,71275, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 1, 0, 0), +(36678,71276, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 1, 0, 0), +(36678,71702, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 1, 0, 0), +(36678,71703, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 1, 0, 0), +(36678,71603, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 3, 0, 0), +(36678,70311, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 0, 1, 0, 0), +(36678,47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 1, 0, 0), +(36678,71518, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 6, 0, 1), +(36678,72672, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 3, 0, 0); +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36678,70342, 0, 0, 0, 30000, 0, 0, 0, 60000, 0, 0, 0, 10, 40, 0, 15, 0, 0), +(36678,70852, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 10, 30, 0, 15, 0, 0); + +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36678, 37562, 20000, 40000, 1, 1, 1, 1, 5, 10, 0, 9), +(36678, 38159, 8000, 20000, 1, 1, 1, 1, 20, 40, 0, 9), +(36678, 37690, 40000, 60000, 1, 1, 1, 1, 10, 40, 0, 9), +(36678, 37697, 20000, 40000, 1, 1, 1, 1, 5, 10, 0, 9); +-- Gas cloud +DELETE FROM `boss_spell_table` WHERE `entry` = 37562; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37562,70672, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 0), +(37562,70215, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 0), +(37562,71770, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 1), +(37562,70812, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 1), +(37562,70701, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 0); +-- Volatile ooze +DELETE FROM `boss_spell_table` WHERE `entry` = 37697; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37697,70492, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 1, 0, 0), +(37697,70530, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 1), +(37697,71770, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 1), +(37697,70447, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 6, 0, 0); +-- Mutated abomination (pet?) +DELETE FROM `boss_spell_table` WHERE `entry` = 37672; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37672,70311, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 1, 0, 0), +(37672,72527, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 3, 0, 0), +(37672,72539, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 3, 0, 0), +(37672,70542, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 3, 0, 0), +(37672,70405, 0, 0, 0, 10000, 0, 0, 0, 20000, 0, 0, 0, 1, 0, 0); + +-- Taldaram +DELETE FROM `boss_spell_table` WHERE `entry` = 37973; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37973, 71807, 0, 0, 0, 50000, 0, 0, 0, 10000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(37973, 71718, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37973, 71719, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 15, 0, 0), +(37973, 72040, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37973, 72041, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 15, 0, 0), +(37973, 70952, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37973, 70981, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37973, 70982, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37973, 70983, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37973, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0); + +-- Valanar +DELETE FROM `boss_spell_table` WHERE `entry` = 37970; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37970, 72053, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37970, 38459, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 11, 0, 0), +(37970, 72037, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37970, 38422, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 11, 0, 0), +(37970, 71945, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(37970, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37970, 70983, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37970, 70981, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37970, 70982, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37970, 70952, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37970, 72039, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0); + +-- Keleseth +DELETE FROM `boss_spell_table` WHERE `entry` = 37972; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37972, 71405, 0, 0, 0, 5000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(37972, 71815, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(37972, 71943, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37972, 71822, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37972, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37972, 70952, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37972, 70981, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37972, 70982, 0, 0, 0, 30000, 0, 0, 0, 30000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37972, 70983, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 1, 0, 0); + +-- Lanathel +DELETE FROM `boss_spell_table` WHERE `entry` = 37955; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37955, 72981, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37955, 71623, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(37955, 70451, 70451, 71510, 71510, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 6, 0, 1), +(37955, 70445, 70445, 70821, 70821, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(37955, 71726, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 70867, 71473, 71532, 71533, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 70871, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 70923, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 71340, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 71264, 0, 0, 0, 20000, 0, 0, 0, 35000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 71446, 0, 0, 0, 7000, 0, 0, 0, 12000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37955, 71772, 0, 0, 0, 40000, 0, 0, 0, 60000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37955, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37955, 72934, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 6, 0, 1), +(37955, 71952, 0, 0, 0, 5000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 1, 0, 0); + +-- Valithria +DELETE FROM `boss_spell_table` WHERE `entry` = 36789; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36789, 71977, 0, 0, 0, 30000, 0, 0, 0, 60000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36789, 71987, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 1, 1, 0), +(36789, 72481, 0, 0, 0, 10000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36789, 70873, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36789, 71189, 0, 0, 0, 3000, 0, 0, 0, 3000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36789, 72724, 0, 0, 0, 3000, 0, 0, 0, 3000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36789, 70904, 0, 0, 0, 5000, 0, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 1, 0, 1), +(36789, 71196, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36789, 70702, 0, 0, 0, 15000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 16, 0, 1); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36789, 38429, 30000, 40000, 1, 1, 1, 1, 5, 70, 0, 9), +(36789, 37868, 30000, 45000, 1, 1, 1, 1, 1, 3, 0, 11), +(36789, 37863, 30000, 45000, 1, 1, 1, 1, 1, 3, 0, 11), +(36789, 36791, 30000, 45000, 1, 1, 1, 1, 1, 3, 0, 11), +(36789, 37934, 30000, 45000, 1, 1, 1, 1, 1, 3, 0, 11), +(36789, 37886, 30000, 45000, 1, 1, 1, 1, 1, 3, 0, 11); +-- Nightmare portal +DELETE FROM `boss_spell_table` WHERE `entry` = 38429; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(38429, 70873, 0, 0, 0, 2000, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, 1, 0, 1); + +-- Sindragosa +DELETE FROM `boss_spell_table` WHERE `entry` = 36853; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36853, 70084, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36853, 57764, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 1, 0), +(36853, 19983, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(36853, 71077, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36853, 69649, 0, 0, 0, 20000, 0, 0, 0, 35000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36853, 70107, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36853, 69762, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36853, 69766, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(36853, 69846, 0, 0, 0, 15000, 0, 0, 0, 20000, 0, 0, 0, 50.0, 100.0, 0, 15, 0, 0), +(36853, 70117, 0, 0, 0, 30000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36853, 70123, 0, 0, 0, 20000, 0, 0, 0, 35000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36853, 70126, 0, 0, 0, 90000, 0, 0, 0, 90000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36853, 70157, 0, 0, 0, 6000, 0, 0, 0, 6000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(36853, 71665, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(36853, 69845, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36853, 36980, 0, 0, 0, 90000, 0, 0, 0, 90000, 0, 0, 0, 0, 0, 0, 9, 0, 0), +(36853, 47008, 0, 0, 0, 600000, 0, 0, 0, 600000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36853, 72289, 0, 0, 0, 1000, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 12, 0, 1), +(36853, 70128, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 30.0, 0, 0, 12, 0, 0); + +UPDATE`boss_spell_table` SET `data1` = 2, `data2` = 5, `data3` = 2, `data4` =5 WHERE `entry` = 36853 AND `spellID_N10` = 70126; +UPDATE`boss_spell_table` SET `data1` = 4, `data2` = 4, `data3` = 4, `data4` =4 WHERE `entry` = 36853 AND `spellID_N10` = 69845; + +-- Rimefang +DELETE FROM `boss_spell_table` WHERE `entry` = 37533; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37533, 71387, 0, 0, 0, 0, 0, 0, 0, 3600000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37533, 71386, 0, 0, 0, 5000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(37533, 71376, 0, 0, 0, 4000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 4, 0, 0); +-- Spinestalker +DELETE FROM `boss_spell_table` WHERE `entry` = 37534; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37534, 36922, 0, 0, 0, 8000, 0, 0, 0, 24000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37534, 40505, 0, 0, 0, 5000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(37534, 71369, 0, 0, 0, 4000, 0, 0, 0, 8000, 0, 0, 0, 0, 0, 0, 4, 0, 0); +-- Ice tomb +DELETE FROM `boss_spell_table` WHERE `entry` = 36980; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36980, 70157, 0, 0, 0, 2000, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, 6, 0, 0); + +-- Lich king +DELETE FROM `boss_spell_table` WHERE `entry` = 36597; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36597, 70541, 0, 0, 0, 6000, 0, 0, 0, 12000, 0, 0, 0, 60, 0, 0, 12, 0, 0), +(36597, 70337, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36597, 74074, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36597, 69409, 0, 0, 0, 10000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(36597, 72762, 0, 0, 0, 20000, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36597, 68980, 0, 0, 0, 1500, 0, 0, 0, 25000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36597, 68981, 0, 0, 0, 60000, 0, 0, 0, 60000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 72133, 0, 0, 0, 5000, 0, 0, 0, 10000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 72262, 0, 0, 0, 5000, 0, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 69201, 0, 0, 0, 5000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 1), +(36597, 69200, 0, 0, 0, 5000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(36597, 69242, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 69103, 0, 0, 0, 3000, 0, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 69099, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 69108, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 70358, 0, 0, 0, 40000, 0, 0, 0, 70000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 70372, 0, 0, 0, 40000, 0, 0, 0, 70000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 72149, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 72143, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 70503, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 69037, 0, 0, 0, 20000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 36609, 0, 0, 0, 20000, 0, 0, 0, 40000, 0, 0, 0, 0, 0, 0, 9, 0, 0), +(36597, 71769, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 70063, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 1), +(36597, 47008, 0, 0, 0, 900000, 0, 0, 0, 900000, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(36597, 74352, 0, 0, 0, 8000, 0, 0, 0, 15000, 0, 0, 0, 0, 0, 0, 1, 0, 0); +-- summons +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `timerMin_N10`, `timerMax_N10`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `CastType` ) VALUES +(36597, 37799, 60000, 60000, 8, 10, 10, 10, 15, 25, 0, 11), +(36597, 70498, 3600001, 3600001, 12, 12, 15, 15, 15, 25, 0, 1); +-- ice sphere +DELETE FROM `boss_spell_table` WHERE `entry` = 36633; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36633, 69099, 0, 0, 0, 2000, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(36633, 69108, 0, 0, 0, 2000, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(36633, 69090, 0, 0, 0, 8000, 0, 0, 0, 24000, 0, 0, 0, 0, 0, 0, 1, 0, 0); +-- vile spirit +DELETE FROM `boss_spell_table` WHERE `entry` = 37799; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(37799, 70503, 0, 0, 0, 10000, 0, 0, 0, 10000, 0, 0, 0, 0, 0, 0, 1, 0, 0); +-- raging spirit +DELETE FROM `boss_spell_table` WHERE `entry` = 36701; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `spellID_H10`, `spellID_H25`, `timerMin_N10`, `timerMin_N25`, `timerMin_H10`, `timerMin_H25`, `timerMax_N10`, `timerMax_N25`, `timerMax_H10`, `timerMax_H25`, `locData_x`, `locData_y`, `locData_z`, `CastType`, `isVisualEffect`, `isBugged`) VALUES +(36701, 69242, 0, 0, 0, 2000, 0, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 3, 0, 0); + diff --git a/sql_mr/mr00330_scriptdev2_icecrown_down.sql b/sql_mr/mr00330_scriptdev2_icecrown_down.sql new file mode 100644 index 0000000000..0a50e79036 --- /dev/null +++ b/sql_mr/mr00330_scriptdev2_icecrown_down.sql @@ -0,0 +1,280 @@ +-- Forge of souls +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1632055 AND -1632029; +INSERT INTO `script_texts` (`entry`,`content_default`,`content_loc1`,`content_loc2`,`content_loc3`,`content_loc4`,`content_loc5`,`content_loc6`,`content_loc7`,`content_loc8`,`sound`,`type`,`language`,`emote`,`comment`) VALUES +-- Bronjham +(-1632029,'Excellent work, champions! We shall set up our base camp in these chambers. My mages will get the Scourge transport device working shortly. Step inside it when you''re ready for your next mission. I will meet you on the other side.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Вы справились. Мы разобьем лагерь в этих покоях. Вскоре мои маги заставят портал плети работать! Войдите в него, когда будете готовы к следующему заданию. Я присоединюсь к вам чуть позже.',16625,1,0,0,'Jaina SAY_JAINA_OUTRO'), +(-1632030,'Excellent work, champions! We shall set up our base camp in these chambers. My mages will get the Scourge transport device working shortly. Step inside when you are ready for your next mission. I will meet you on the other side.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Превосходно! Мы разобьем лагерь в этих покоях! Вскоре мои маги заставят портал плети работать, войдите в него когда будете готовы к следующему заданию! Я присоединюсь к вам позже.',17044,1,0,0,'Sylvanas SAY_SYLVANAS_OUTRO'), + +-- Jaina +(-1632040,'Thank the light for seeing you here safely. We have much work to do if we are to defeat the Lich King and put an end to the Scourge.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Слава свету! Вы целы и невредимы нам предстоит многое сделать, если мы хотим покончить с королем личем и плетью.',16617,0,0,0,'Jaina SAY_INTRO_1'), +(-1632041,'Our allies within the Argent Crusade and the Knights of the Ebon Blade have broken through the front gate of Icecrown and are attempting to establish a foothold within the Citadel.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Серебряный Авангард и рыцари черного клинка прорвались через главные ворота и пытаются укрепить свои позиции в цитадели!',16618,0,0,0,'Jaina SAY_INTRO_2'), +(-1632042,'Their success hinges upon what we discover in these cursed halls. Although our mission is a wrought with peril, we must persevere!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Их успех зависит от того что мы найдем этих ужасных залах. Пусть наша миссия опасна, но мы должны выстоять.',16619,0,0,0,'Jaina SAY_INTRO_3'), +(-1632043,'With the attention of the Lich King drawn toward the front gate, we will be working our way through the side in search of information that will enable us to defeat the Scourge - once and for all.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Пока король лич отвлекся на главные ворота, мы проникнем внутрь другим путем и постараемся узнать как можно покончить с плетью раз и навсегда.',16620,0,0,0,'Jaina SAY_INTRO_4'), +(-1632044,'King Varian''s SI7 agents have gathered information about a private sanctum of the Lich King''s deep within a place called the Halls of Reflection.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Разведчики SI7 отправленные Варианом сообщают что покои короля находятся в глубине дворца! Это место называется Залами отражений.',16621,0,0,0,'Jaina SAY_INTRO_5'), +(-1632045,'We will carve a path through this wretched place and find a way to enter the Halls of Reflection. I sense powerful magic hidden away within those walls... Magic that could be the key to destroy the Scourge.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Мы проложим себе путь сквозь это проклятое место и найдем вход в залы отражений. Я чувствую что в них сокрыта могушественная магия, которая поможет нам сокрушить плеть!',16622,0,0,0,'Jaina SAY_INTRO_6'), +(-1632046,'Your first mission is to destroy the machines of death within this malevolent engine of souls, and clear a path for our soldiers.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Ваша первая задача разрушить машины смерти в этом механизме душ, это откроет путь нашим солдатам.',16623,0,0,0,'Jaina SAY_INTRO_7'), +(-1632047,'Make haste, champions! I will prepare the troops to fall in behind you.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Спешите герои, я прикажу солдатам следовать за вами!',16624,0,0,0,'Jaina SAY_INTRO_8'), + +-- Sylvanas +(-1632050,'The Argent Crusade and the Knights of the Ebon Blade have assaulted the gates of Icecrown Citadel and are preparing for a massive attack upon the Scourge. Our missition is a bit more subtle, but equally as important.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Серебряный Авангард и рыцари черного клинка штурмуют ворота цитадели ледяной короны! И готовятся нанести решаюший удар! Мы будем действовать незаметно, но не менее эффективно.',17038,0,0,0,'Sylvanas SAY_INTRO_1'), +(-1632051,'With the attention of the Lich King turned towards the front gate, we''ll be working our way through the side in search of information that will enable us to defeat the Lich King - once and for all.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Пока Король-Лич отвлекся мы проникнем внутрь другим путем и постараемся понять как можно покончить с ним раз и навсегда.',17039,0,0,0,'Sylvanas SAY_INTRO_2'), +(-1632052,'Our scouts have reported that the Lich King has a private chamber, outside of the Frozen Throne, deep within a place called the Halls of Reflection. That is our target, champions.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Наши разведчики сообщили что покои короля лича находятся в глубине дворца, недалеко от ледяного трона. Это место называется залами отражений, туда и лежит наш путь.',17040,0,0,0,'Sylvanas SAY_INTRO_3'), +(-1632053,'We will cut a swath of destruction through this cursed place and find a way to enter the Halls of Reflection. If there is anything of value to be found here, it will be found in the Halls.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Мы проложим себе путь сквозь это проклетое место и найдем и найдем вход в залы отражений! Если в цитадели и есть что то достойное внимания оно ждет нас именно там.',17041,0,0,0,'Sylvanas SAY_INTRO_4'), +(-1632054,'Your first mission is to destroy the machines of death within this wretched engine of souls, and clear a path for our soldiers.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Вашей первой задачей будет разрушение машин смерти в этом гнусном механизме душ, это откроет путь к нашим солдатам',17042,0,0,0,'Sylvanas SAY_INTRO_5'), +(-1632055,'The Dark Lady watches over you. Make haste!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Темная госпожа будет наблюдать за вами, спешите!',17043,0,0,0,'Sylvanas SAY_INTRO_6'); + +-- Halls of reflection (from MaxXx2021 aka Mioka) +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1668523 AND -1668433; +INSERT INTO `script_texts` (`entry`,`content_default`,`content_loc8`,`sound`,`type`,`language`,`emote`,`comment`) VALUES +-- SCENE - Hall Of Reflection (Intro) - PreUther +(-1668433, 'The chill of this place freezes the marrow of my bones!', 'Как же тут холодно... Кровь стынет в жилах.', 16631,0,0,1, '67234'), +(-1668434, 'I... I don\'t believe it! Frostmourne stands before us, unguarded! Just as the Gnome claimed. Come, heroes!', 'Я... Я не верю своим глазам. Ледяная скорбь перед нами без всякой охраны! Как и говорил гном. Вперед герои!', 17049,0,0,1, '67234'), +(-1668435, 'What is that? Up ahead! Could it be ... ? Heroes at my side!', 'Что это там впереди? Неужели? Скорее герои!', 16632,1,0,1, '67234'), +(-1668436, 'Frostmourne ... The blade that destroyed our kingdom ...', 'Ледяная Скорбь, клинок, разрушивший наше королевство...', 16633,1,0,1, '67234'), +(-1668437, 'Standing this close to the blade that ended my life... The pain... It is renewed.', 'Боль снова захлестывает меня, когда я так близко вижу меч, отнявший у меня жизнь.', 17050,0,0,1, '67234'), +(-1668438, 'Stand back! Touch that blade and your soul will be scarred for all eternity! I must attempt to commune with the spirits locked away within Frostmourne. Give me space, back up please!', 'Отойдите. Тот кто коснется этого клинка обречет себя на вечные муки. Я попытаюсь заговорить с душами заключенными в Ледяной скорби. Расступитесь... Чуть назад! Прошу.', 16634,1,0,1, '67234'), +(-1668439, 'I dare not touch it. Stand back! Stand back! As I attempt to commune with the blade. Perhaps our salvation lies within.', 'Я не смею его коснуться. Назад! Отступите! Я попробую установить связь с мечом. Возможно, спасение находится внутри!', 17051,1,0,1, '67234'), +-- SCENE - Hall Of Reflection (Intro) - UtherDialog +(-1668440, 'Jaina! Could it truly be you?', 'Джайна? Неужели это ты?', 16666,0,0,1, '67234'), +(-1668441, 'Careful, girl. I\'ve heard talk of that cursed blade saving us before. Look around you and see what has been born of Frostmourne.', 'Осторожней девочка! Однажды мне уже говорили, что этот проклятый меч может нас спасти. Посмотри вокруг, и ты увидишь, что из этого вышло.', 16659,0,0,1, '67234'), +(-1668442, 'Uther! Dear Uther! I... I\'m so sorry.', 'Утер? Милый Утер! Мне... Мне так жаль.', 16635,0,0,1, '67234'), +(-1668443, 'Uther...Uther the Lightbringer. How...', 'Утер? Утер Светоносный? Как...', 17052,0,0,1, '67234'), +(-1668444, 'Jaina, you haven\'t much time. The Lich King sees what the sword sees. He will be here shortly.', 'Джайна, у вас мало времени. Король - Лич видит все что видит Ледяная Скорбь. Вскоре он будет здесь.', 16667,0,0,1, '67234'), +(-1668445, 'You haven\'t much time. The Lich King sees what the sword sees. He will be here shortly.', 'У вас мало времени. Король - Лич видит все что видит Ледяная Скорбь. Вскоре он будет здесь.', 16660,0,0,1, '67234'), +(-1668446, 'Arthas is here? Maybe I...', 'Артас здесь? Может я...', 16636,0,0,1, '67234'), +(-1668447, 'The Lich King is here? Then my destiny shall be fulfilled today!', 'Король - Лич здесь? Значит моя судьба решится сегодня!', 17053,1,0,1, '67234'), +(-1668448, 'No, girl. Arthas is not here. Arthas is merely a presence within the Lich King\'s mind. A dwindling presence...', 'Нет девочка. Артаса здесь нет. Артас лишь тень, мелькающая в сознании Короля - Лича. Смутная тень.', 16668,0,0,1, '67234'), +(-1668449, 'You cannot defeat the Lich King. Not here. You would be a fool to try. He will kill those who follow you and raise them as powerful servants of the Scourge. But for you, Sylvanas, his reward for you would be worse than the last.', 'Вам не победить Короля - Лича. Покрайней мере не здесь. Глупо и пытаться. Он убьет твоих соратников и воскресит их как воинов плети. Но что до тебя Сильвана, он готовит тебе участь еще страшнее, чем в прошлый раз.', 16661,0,0,1, '67234'), +(-1668450, 'But Uther, if there\'s any hope of reaching Arthas. I... I must try.', 'Но если есть малейшая надежда вернуть Артаса... Я должна попытаться!', 16637,0,0,1, '67234'), +(-1668451, 'There must be a way...', 'Должен быть способ!', 17054,0,0,1, '67234'), +(-1668452, 'Jaina, listen to me. You must destroy the Lich King. You cannot reason with him. He will kill you and your allies and raise you all as powerful soldiers of the Scourge.', 'Джайна послушай меня. Вам нужно уничтожить Короля - Лича. С ним нельзя договориться. Он убьет вас всех и превратит в могущественных воинов Плети.', 16669,0,0,1, '67234'), +(-1668453, 'Perhaps, but know this: there must always be a Lich King. Even if you were to strike down Arthas, another would have to take his place, for without the control of the Lich King, the Scourge would wash over this world like locusts, destroying all that they touched.', 'Возможно... Но знай! Король - Лич должен быть всегда. Даже если вы убьете Артаса кто то обязан будет занять его место. Лишившись правителя Плеть налетит на мир как стая саранчи и уничтожит все на своем пути.', 16662,0,0,1, '67234'), +(-1668454, 'Tell me how, Uther? How do I destroy my prince? My...', 'Но как Утер? Как мне убить моего принца, моего...', 16638,0,0,1, '67234'), +(-1668455, 'Who could bear such a burden?', 'Кому по силам такое бремя?', 17055,0,0,1, '67234'), +(-1668456, 'Snap out of it, girl. You must destroy the Lich King at the place where he merged with Ner\'zhul - atop the spire, at the Frozen Throne. It is the only way.', 'Забудь об этом девочка. Короля - Лича нужно уничтожить на том месте, где он слился с Нерзулом. На самой вершине, у Ледяного Трона!', 16670,0,0,1, '67234'), +(-1668457, 'I do not know, Banshee Queen. I suspect that the piece of Arthas that might be left inside the Lich King is all that holds the Scourge from annihilating Azeroth.', 'Не знаю, Королева Баньши... Если бы не Артас, который все еще является частью Короля - Лича, Плеть давно бы уже уничтожила Азерот.', 16663,0,0,1, '67234'), +(-1668458, 'You\'re right, Uther. Forgive me. I... I don\'t know what got a hold of me. We will deliver this information to the King and the knights that battle the Scourge within Icecrown Citadel.', 'Ты прав Утер, прости меня... Я не знаю что на меня нашло. Мы передадим твои слова Королю и рыцарям, которые сражаются с Плетью в Цитадели Ледяной Короны.', 16639,0,0,1, '67234'), +(-1668459, 'There is... something else that you should know about the Lich King. Control over the Scourge must never be lost. Even if you were to strike down the Lich King, another would have to take his place. For without the control of its master, the Scourge would run rampant across the world - destroying all living things.', 'Тебе нужно знать еще кое что о Короле - Личе. Плеть не должна выйти из под контроля. Даже если вы убьете Короля - Лича, кто-то должен будет занять его место. Без Короля Плеть налетит на мир как стая саранчи и уничтожит все живое.', 16671,0,0,1, '67234'), +(-1668460, 'Alas, the only way to defeat the Lich King is to destroy him at the place he was created.', 'Увы единственый способ одолеть Короля - Лича - это убить его там где он был порожден.', 16664,0,0,1, '67234'), +(-1668461, 'Who could bear such a burden?', 'Кому по силам такое бремя?', 16640,0,0,1, '67234'), +(-1668462, 'The Frozen Throne...', 'Ледяной Трон!', 17056,0,0,1, '67234'), +(-1668463, 'A grand sacrifice by a noble soul...', 'Великая жертва, благородной души.', 16672,0,0,1, '67234'), +(-1668464, 'I do not know, Jaina. I suspect that the piece of Arthas that might be left inside the Lich King is all that holds the Scourge from annihilating Azeroth.', 'Не знаю Джайна... мне кажется если бы не Артас, который все еще является частью Короля - Лича, Плеть давно бы уже уничтожила Азерот.', 16673,0,0,1, '67234'), +(-1668465, 'Then maybe there is still hope...', 'Но может еще есть надежда?', 16641,0,0,1, '67234'), +(-1668466, 'No, Jaina! ARRRRRRGHHHH... He... He is coming. You... You must...', 'Нет Джайна... Эээээ... Он... Он приближается... Вы... Вы должны...', 16674,1,0,1, '67234'), +(-1668467, 'Aye. ARRRRRRGHHHH... He... He is coming. You... You must...', 'Да... Эээээ... Он... Он приближается... Вы... Вы должны...', 16665,1,0,1, '67234'), +(-1668468, 'SILENCE, PALADIN!', 'Замолчи, паладин.', 17225,1,0,0, '67234'), +(-1668469, 'So you wish to commune with the dead? You shall have your wish.', 'Так ты хочешь поговорить с мертвыми? Нет ничего проще!', 17226,1,0,0, '67234'), +(-1668470, 'Falric. Marwyn. Bring their corpses to my chamber when you are through.', 'Фалрик, Марвин, когда закончите, принесите их тела в мои покои.', 17227,0,0,0, '67234'), +(-1668471, 'You won\'t deny me this, Arthas! I must know... I must find out...', 'Ты от меня не отмахнешься Артас. Я должна понять, я должна знать.', 16642,1,0,1, '67234'), +(-1668472, 'You will not escape me that easily, Arthas! I will have my vengeance!', 'Ты так просто от меня не уйдешь Артас. Я отомщу тебе!', 17057,1,0,1, '67234'), +(-1668473, '', 'Глупая девчонка! Тот кого ты ищещь давно убит! Теперь он лишь призрак, слабый отзвук в моем сознании!', 17229,1,0,0, '67234'), +(-1668474, '', 'Я не повторю прежней ошибки, Сильвана. На этот раз тебе не спастись. Ты не оправдала моего доверия и теперь тебя ждет только забвение!', 17228,1,0,0, '67234'), +(-1668475, 'As you wish, my lord.', 'Как пожелаете, мой господин!', 16717,1,0,0, '67234'), +(-1668476, 'As you wish, my lord.', 'Как пожелаете, мой господин!', 16741,1,0,0, '67234'), +-- SCENE - Hall Of Reflection (Extro) - PreEscape +(-1668477, 'Your allies have arrived, Jaina, just as you promised. You will all become powerful agents of the Scourge.', 'Твои союзники прибыли, Джайна! Как ты и обещала... Ха-ха-ха-ха... Все вы станете могучими солдатами Плети...', 17212,1,0,0, '67234'), +(-1668478, 'I will not make the same mistake again, Sylvanas. This time there will be no escape. You will all serve me in death!', 'Я не повторю прежней ошибки, Сильвана! На этот раз тебе не спастись. Вы все будите служить мне после смерти...', 17213,1,0,0, '67234'), +(-1668479, 'He is too powerful, we must leave this place at once! My magic will hold him in place for only a short time! Come quickly, heroes!', 'Он слишком силен. Мы должны выбраться от сюда как можно скорее. Моя магия задержит его ненадолго, быстрее герои...', 16644,0,0,1, '67234'), +(-1668480, 'He\'s too powerful! Heroes, quickly, come to me! We must leave this place immediately! I will do what I can do hold him in place while we flee.', 'Он слишком силен. Герои скорее, за мной. Мы должны выбраться отсюда немедленно. Я постараюсь его задержать, пока мы будем убегать.', 17058,0,0,1, '67234'), +-- SCENE - Hall Of Reflection (Extro) - Escape +(-1668481, 'Death\'s cold embrace awaits.', 'Смерть распростерла ледяные обьятия!', 17221,1,0,0, '67234'), +(-1668482, 'Rise minions, do not left them us!', 'Восстаньте прислужники, не дайте им сбежать!', 17216,1,0,0, '67234'), +(-1668483, 'Minions sees them. Bring their corpses back to me!', 'Схватите их! Принесите мне их тела!', 17222,1,0,0, '67234'), +(-1668484, 'No...', 'Надежды нет!', 17214,1,0,0, '67234'), +(-1668485, 'All is lost!', 'Смирись с судьбой.', 17215,1,0,0, '67234'), +(-1668486, 'There is no escape!', 'Бежать некуда!', 17217,1,0,0, '67234'), +(-1668487, 'I will destroy this barrier. You must hold the undead back!', 'Я разрушу эту преграду, а вы удерживайте нежить на расстоянии!', 16607,1,0,0, '67234'), +(-1668488, 'No wall can hold the Banshee Queen! Keep the undead at bay, heroes! I will tear this barrier down!', 'Никакие стены не удержат Королеву Баньши. Держите нежить на расстоянии, я сокрушу эту преграду.', 17029,1,0,0, '67234'), +(-1668489, 'Another ice wall! Keep the undead from interrupting my incantation so that I may bring this wall down!', 'Опять ледяная стена... Я разобью ее, только не дайте нежити прервать мои заклинания...', 16608,1,0,0, '67234'), +(-1668490, 'Another barrier? Stand strong, champions! I will bring the wall down!', 'Еще одна преграда. Держитесь герои! Я разрушу эту стену!', 17030,1,0,0, '67234'), +(-1668491, 'Succumb to the chill of the grave.', 'Покоритесь Леденящей смерти!', 17218,1,0,0, '67234'), +(-1668492, 'Another dead end.', 'Вы в ловушке!', 17219,1,0,0, '67234'), +(-1668493, 'How long can you fight it?', 'Как долго вы сможете сопротивляться?', 17220,1,0,0, '67234'), +(-1668494, '', 'Он с нами играет. Я покажу ему что бывает когда лед встречается со огнем!', 16609,0,0,0, '67234'), +(-1668495, 'Your barriers can\'t hold us back much longer, monster. I will shatter them all!', 'Твои преграды больше не задержат нас, чудовище. Я смету их с пути!', 16610,1,0,0, '67234'), +(-1668496, 'I grow tired of these games, Arthas! Your walls can\'t stop me!', 'Я устала от этих игр Артас. Твои стены не остановят меня!', 17031,1,0,0, '67234'), +(-1668497, 'You won\'t impede our escape, fiend. Keep the undead off me while I bring this barrier down!', 'Ты не помешаешь нам уйти, монстр. Сдерживайте нежить, а я уничтожу эту преграду.', 17032,1,0,0, '67234'), +(-1668498, 'There\'s an opening up ahead. GO NOW!', 'Я вижу выход, скорее!', 16645,1,0,0, '67234'), +(-1668499, 'We\'re almost there... Don\'t give up!', 'Мы почти выбрались, не сдавайтесь!', 16646,1,0,0, '67234'), +(-1668500, 'There\'s an opening up ahead. GO NOW!', 'Я вижу выход, скорее!', 17059,1,0,0, '67234'), +(-1668501, 'We\'re almost there! Don\'t give up!', 'Мы почти выбрались, не сдавайтесь!', 17060,1,0,0, '67234'), +(-1668502, 'It... It\'s a dead end. We have no choice but to fight. Steel yourself heroes, for this is our last stand!', 'Больше некуда бежать. Теперь нам придется сражаться. Это наша последняя битва!', 16647,1,0,0, '67234'), +(-1668503, 'BLASTED DEAD END! So this is how it ends. Prepare yourselves, heroes, for today we make our final stand!', 'Проклятый тупик, значит все закончится здесь. Готовьтесь герои, это наша последняя битва.', 17061,1,0,0, '67234'), +(-1668504, 'Nowhere to run! You\'re mine now...', 'Ха-ха-ха... Бежать некуда. Теперь вы мои!', 17223,1,0,0, '67234'), +(-1668505, 'Soldiers of Lordaeron, rise to meet your master\'s call!', 'Солдаты Лордерона, восстаньте по зову Господина!', 16714,1,0,0, '67234'), +(-1668506, 'The master surveyed his kingdom and found it... lacking. His judgement was swift and without mercy. Death to all!', 'Господин осмотрел свое королевство и признал его негодным! Его суд был быстрым и суровым - предать всех смерти!', 16738,1,0,0, '67234'), + +-- Falric +(-1668507, 'Men, women and children... None were spared the master\'s wrath. Your death will be no different.', 'Мужчины, Женщины и дети... Никто не избежал гнева господина. Вы разделите их участь!', 16710,1,0,0, '67234'), +(-1668508, 'Marwyn, finish them...', 'Марвин... Добей их...', 16713,1,0,0, '67234'), +(-1668509, 'Sniveling maggot!', 'Сопливый червяк!', 16711,1,0,0, '67234'), +(-1668510, 'The children of Stratholme fought with more ferocity!', 'Стратхольмские детишки - и те сражались отчаяннее!', 16712,1,0,0, '67234'), +(-1668511, 'Despair... so delicious...', 'Как сладостно отчаянье!', 16715,1,0,0, '67234'), +(-1668512, 'Fear... so exhilarating...', 'Как приятен страх!', 16716,1,0,0, '67234'), + +-- Marwyn +(-1668513, 'Death is all that you will find here!', 'Вы найдете здесь лишь смерть!', 16734,1,0,0, '67234'), +(-1668514, 'Yes... Run... Run to meet your destiny... Its bitter, cold embrace, awaits you.', 'Эээээ... Да... Бегите навстречу судьбе. Ее жестокие и холодные обьятия ждут вас...', 16737,1,0,0, '67234'), +(-1668515, 'I saw the same look in his eyes when he died. Terenas could hardly believe it. Hahahaha!', 'У Теренаса был такой же взгляд в миг смерти, он никак не мог поверить... Ха-ха-ха-ха-ха...', 16735,1,0,0, '67234'), +(-1668516, 'Choke on your suffering!', 'Захлебнись страданием!', 16736,1,0,0, '67234'), +(-1668517, 'Your flesh shall decay before your very eyes!', 'Вы увидите как разлагается ваша плоть!', 16739,1,0,0, '67234'), +(-1668518, 'Waste away into nothingness!', 'Сгиньте без следа!', 16740,1,0,0, '67234'), + +-- FrostWorn General +(-1668519, 'You are not worthy to face the Lich King!', 'Вы недостойны предстать перед Королем - Личом!', 16921,1,0,0, '67234'), +(-1668520, 'Master, I have failed...', 'Господин... Я подвел вас...', 16922,1,0,0, '67234'), + +-- add +(-1668521, 'Well, now it\'s time to just a dump', 'Ну теперь-то точно пора сваливать.', 0,0,0,0, '67234'), +(-1668522, 'Here\'s a chest behind the work', 'Вот вам сундук за работу.', 0,0,0,0, '67234'), +(-1668523, 'And since the ship with Offa will not, here\'s a portal to Dalaran', 'И, поскольку корабля с оффа не будет, вот вам портал в Даларан.', 0,0,0,0, '67234'); + +-- Gossips +DELETE FROM gossip_texts WHERE entry BETWEEN -3594540 AND -3594536; +REPLACE INTO gossip_texts (entry, content_default, content_loc8, comment) VALUES +(-3594536, 'Lady Jaina, we are ready for next mission!', 'Джайна, мы готовы!',''), +(-3594537, 'Lady Jaina, Let\'s go!', 'Давай быстрее!', ''), +(-3594538, 'Lady Sylvanas, we are ready for next mission!', 'Сильвана, мы готовы!', ''), +(-3594539, 'Lady Sylvanas, Let\'s go!', 'Поехали!', ''), +(-3594540, 'Let\'s go!', 'Побежали!', ''); + +-- Waypoints to escort event on Halls of reflection + +DELETE FROM script_waypoint WHERE entry=36955; +DELETE FROM script_waypoint WHERE entry=37226; +DELETE FROM script_waypoint WHERE entry=37554; + +INSERT INTO script_waypoint VALUES +-- Jaina + + (36955, 0, 5587.682,2228.586,733.011, 0, 'WP1'), + (36955, 1, 5600.715,2209.058,731.618, 0, 'WP2'), + (36955, 2, 5606.417,2193.029,731.129, 0, 'WP3'), + (36955, 3, 5598.562,2167.806,730.918, 0, 'WP4 - Summon IceWall 01'), + (36955, 4, 5556.436,2099.827,731.827, 0, 'WP5 - Spell Channel'), + (36955, 5, 5543.498,2071.234,731.702, 0, 'WP6'), + (36955, 6, 5528.969,2036.121,731.407, 0, 'WP7'), + (36955, 7, 5512.045,1996.702,735.122, 0, 'WP8'), + (36955, 8, 5504.490,1988.789,735.886, 0, 'WP9 - Spell Channel'), + (36955, 9, 5489.645,1966.389,737.653, 0, 'WP10'), + (36955, 10, 5475.517,1943.176,741.146, 0, 'WP11'), + (36955, 11, 5466.930,1926.049,743.536, 0, 'WP12'), + (36955, 12, 5445.157,1894.955,748.757, 0, 'WP13 - Spell Channel'), + (36955, 13, 5425.907,1869.708,753.237, 0, 'WP14'), + (36955, 14, 5405.118,1833.937,757.486, 0, 'WP15'), + (36955, 15, 5370.324,1799.375,761.007, 0, 'WP16'), + (36955, 16, 5335.422,1766.951,767.635, 0, 'WP17 - Spell Channel'), + (36955, 17, 5311.438,1739.390,774.165, 0, 'WP18'), + (36955, 18, 5283.589,1703.755,784.176, 0, 'WP19'), + (36955, 19, 5260.400,1677.775,784.301, 3000, 'WP20'), + (36955, 20, 5262.439,1680.410,784.294, 0, 'WP21'), + (36955, 21, 5260.400,1677.775,784.301, 0, 'WP22'), + +-- Sylvana + + (37554, 0, 5587.682,2228.586,733.011, 0, 'WP1'), + (37554, 1, 5600.715,2209.058,731.618, 0, 'WP2'), + (37554, 2, 5606.417,2193.029,731.129, 0, 'WP3'), + (37554, 3, 5598.562,2167.806,730.918, 0, 'WP4 - Summon IceWall 01'), + (37554, 4, 5556.436,2099.827,731.827, 0, 'WP5 - Spell Channel'), + (37554, 5, 5543.498,2071.234,731.702, 0, 'WP6'), + (37554, 6, 5528.969,2036.121,731.407, 0, 'WP7'), + (37554, 7, 5512.045,1996.702,735.122, 0, 'WP8'), + (37554, 8, 5504.490,1988.789,735.886, 0, 'WP9 - Spell Channel'), + (37554, 9, 5489.645,1966.389,737.653, 0, 'WP10'), + (37554, 10, 5475.517,1943.176,741.146, 0, 'WP11'), + (37554, 11, 5466.930,1926.049,743.536, 0, 'WP12'), + (37554, 12, 5445.157,1894.955,748.757, 0, 'WP13 - Spell Channel'), + (37554, 13, 5425.907,1869.708,753.237, 0, 'WP14'), + (37554, 14, 5405.118,1833.937,757.486, 0, 'WP15'), + (37554, 15, 5370.324,1799.375,761.007, 0, 'WP16'), + (37554, 16, 5335.422,1766.951,767.635, 0, 'WP17 - Spell Channel'), + (37554, 17, 5311.438,1739.390,774.165, 0, 'WP18'), + (37554, 18, 5283.589,1703.755,784.176, 0, 'WP19'), + (37554, 19, 5260.400,1677.775,784.301, 3000, 'WP20'), + (37554, 20, 5262.439,1680.410,784.294, 0, 'WP21'), + (37554, 21, 5260.400,1677.775,784.301, 0, 'WP22'), + +-- Lich King + + (37226, 0, 5577.187,2236.003,733.012, 0, 'WP1'), + (37226, 1, 5587.682,2228.586,733.011, 0, 'WP2'), + (37226, 2, 5600.715,2209.058,731.618, 0, 'WP3'), + (37226, 3, 5606.417,2193.029,731.129, 0, 'WP4'), + (37226, 4, 5598.562,2167.806,730.918, 0, 'WP5'), + (37226, 5, 5559.218,2106.802,731.229, 0, 'WP6'), + (37226, 6, 5543.498,2071.234,731.702, 0, 'WP7'), + (37226, 7, 5528.969,2036.121,731.407, 0, 'WP8'), + (37226, 8, 5512.045,1996.702,735.122, 0, 'WP9'), + (37226, 9, 5504.490,1988.789,735.886, 0, 'WP10'), + + (37226, 10, 5489.645,1966.389,737.653, 0, 'WP10'), + (37226, 11, 5475.517,1943.176,741.146, 0, 'WP11'), + (37226, 12, 5466.930,1926.049,743.536, 0, 'WP12'), + (37226, 13, 5445.157,1894.955,748.757, 0, 'WP13'), + (37226, 14, 5425.907,1869.708,753.237, 0, 'WP14'), + (37226, 15, 5405.118,1833.937,757.486, 0, 'WP15'), + (37226, 16, 5370.324,1799.375,761.007, 0, 'WP16'), + (37226, 17, 5335.422,1766.951,767.635, 0, 'WP17'), + (37226, 18, 5311.438,1739.390,774.165, 0, 'WP18'), + (37226, 19, 5283.589,1703.755,784.176, 0, 'WP19'), + (37226, 20, 5278.694,1697.912,785.692, 0, 'WP20'), + (37226, 21, 5283.589,1703.755,784.176, 0, 'WP19'); + +-- BSW + +-- Icecrown down spelltable + +-- Boss Bronjahm +DELETE FROM `boss_spell_table` WHERE `entry` = 36497; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(36497, 68793, 0, 3000, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(36497, 36535, 0, 30000, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, NULL), +(36497, 68839, 0, 15000, 0, 25000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, NULL), +(36497, 68858, 0, 1000, 0, 3000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(36497, 68988, 0, 1000, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(36497, 68950, 0, 8000, 0, 12000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(36497, 68872, 0, 1000, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(36497, 68921, 0, 360001, 0, 360001, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 12, 0, 0, 0, NULL), +(36497, 70043, 0, 2000, 0, 6000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL); + +-- Spiritual reflection +DELETE FROM `boss_spell_table` WHERE `entry` = 37068; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(37068, 69933, 0, 4000, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(37068, 69900, 0, 6000, 0, 15000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, NULL); + +-- HOR undead warriors +DELETE FROM `boss_spell_table` WHERE `entry` = 36941; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(36941, 70144, 0, 15000, 0, 25000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(36941, 70080, 0, 4000, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(36941, 70145, 0, 10000, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +DELETE FROM `boss_spell_table` WHERE `entry` = 37069; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(37069, 40505, 0, 5000, 0, 10000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL); + +DELETE FROM `boss_spell_table` WHERE `entry` = 36940; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(36940, 70150, 0, 5000, 0, 10000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL); + +-- Boss Falric +DELETE FROM `boss_spell_table` WHERE `entry` = 38112; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(38112, 72395, 0, 1000, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL), +(38112, 72426, 0, 15000, 0, 25000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, -1594511, NULL), +(38112, 72435, 0, 25000, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1594512, NULL), +(38112, 72422, 0, 7000, 0, 14000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(38112, 47008, 0, 180000, 0, 180000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + +-- Boss Marwin +DELETE FROM `boss_spell_table` WHERE `entry` = 38113; +INSERT INTO `boss_spell_table` (`entry`, `spellID_N10`, `spellID_N25`, `timerMin_N10`, `timerMin_N25`, `timerMax_N10`, `timerMax_N25`, `data1`, `data2`, `data3`, `data4`, `locData_x`, `locData_y`, `locData_z`, `varData`, `StageMask_N`, `StageMask_H`, `CastType`, `isVisualEffect`, `isBugged`, `textEntry`, `comment`) VALUES +(38113, 72360, 0, 8000, 0, 12000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, NULL), +(38113, 72368, 0, 15000, 0, 20000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, NULL), +(38113, 72362, 0, 25000, 0, 30000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, -1594518, NULL), +(38113, 72436, 0, 10000, 0, 16000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1594518, NULL), +(38113, 47008, 0, 180000, 0, 180000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, NULL); + diff --git a/sql_mr/mr00359_mangos_ruby_sanctum.sql b/sql_mr/mr00359_mangos_ruby_sanctum.sql new file mode 100644 index 0000000000..27ca771f51 --- /dev/null +++ b/sql_mr/mr00359_mangos_ruby_sanctum.sql @@ -0,0 +1,37 @@ +-- Ruby sanctum +-- Halion +UPDATE `creature_template` SET `ScriptName`='boss_halion_real', `AIName` ='' WHERE `entry`=39863; +UPDATE `creature_template` SET `ScriptName`='boss_halion_twilight', `AIName` ='' WHERE `entry`=40142; +UPDATE `creature_template` SET `ScriptName`='mob_halion_meteor', `AIName` ='' WHERE `entry` = 40029; +UPDATE `creature_template` SET `ScriptName`='mob_halion_flame', `AIName` ='' WHERE `entry` IN (40041); +UPDATE `creature_template` SET `ScriptName`='mob_halion_control', `AIName` ='' WHERE `entry` IN (40146); +UPDATE `creature_template` SET `ScriptName`='mob_halion_orb', `AIName` ='' WHERE `entry` IN (40083,40100); +UPDATE `creature_template` SET `ScriptName`='mob_orb_rotation_focus', `AIName` ='' WHERE `entry` = 40091; +UPDATE `creature_template` SET `ScriptName`='mob_orb_carrier', `AIName` ='' WHERE `entry` = 40081; +UPDATE `creature_template` SET `ScriptName`='mob_fiery_combustion', `AIName` ='' WHERE `entry` = 40001; +UPDATE `creature_template` SET `ScriptName`='mob_soul_consumption', `AIName` ='' WHERE `entry` = 40135; +# +UPDATE `gameobject_template` SET `data10` = 74807, `ScriptName` = 'go_halion_portal_twilight' WHERE `entry` IN (202794,202795); +UPDATE `gameobject_template` SET `ScriptName` = 'go_halion_portal_real' WHERE `entry` = 202796; + +-- Baltharus +UPDATE `creature_template` SET `DamageMultiplier` = 80 WHERE `entry` = 39751; +UPDATE `creature_template` SET `ScriptName`='mob_baltharus_clone', `AIName` ='', `DamageMultiplier` = 80 WHERE `entry` = 39899; +INSERT IGNORE INTO `creature_template` (`Entry`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `KillCredit1`, `KillCredit2`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `Name`, `SubName`, `IconName`, `GossipMenuId`, `MinLevel`, `MaxLevel`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `Armor`, `FactionAlliance`, `FactionHorde`, `NpcFlags`, `SpeedWalk`, `SpeedRun`, `Scale`, `Rank`, `MinMeleeDmg`, `MaxMeleeDmg`, `DamageSchool`, `MeleeAttackPower`, `DamageMultiplier`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `UnitClass`, `UnitFlags`, `DynamicFlags`, `Family`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `MinRangedDmg`, `MaxRangedDmg`, `RangedAttackPower`, `CreatureType`, `CreatureTypeFlags`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MinLootGold`, `MaxLootGold`, `AIName`, `MovementType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MovementTemplateId`, `HealthMultiplier`, `EquipmentTemplateId`, `MechanicImmuneMask`, `ExtraFlags`, `ScriptName`) VALUES +(16, 0, 0, 0, 0, 0, 11686, 0, 11686, 0, 'Baltharus Target Dummy', '', NULL, 0, 1, 1, 25, 27, 0, 0, 17, 35, 35, 0, 1, 1.14286, 1, 0, 1, 2, 0, 0, 1, 2000, 2000, 1, 33554432, 0, 0, 0, 0, 0, 0, 1, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 258, ''); + +-- Zarithian +UPDATE `creature` SET `position_x` = '3008.552734',`position_y` = '530.471680',`position_z` = '89.195290',`orientation` = '6.16' WHERE `id` = 39746; +UPDATE `creature_template` SET `ScriptName` = 'mob_flamecaller_ruby', `AIName` ='' WHERE `entry`=39814; + +-- Saviana Ragefire +DELETE FROM `spell_script_target` WHERE `entry` IN (74455); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +('74455', '1', '39747'); + +-- Xerestrasza +UPDATE `creature_template` SET `ScriptName`='mob_xerestrasza', `AIName` ='' WHERE `entry`=40429; + +-- Mobs +UPDATE `creature_template` SET `ScriptName` = 'mob_living_ember' WHERE `entry` IN ('40683'); +UPDATE `creature_template` SET `ScriptName` = 'mob_living_inferno' WHERE `entry` IN ('40681'); diff --git a/sql_mr/mr00360_mangos_gundrak.sql b/sql_mr/mr00360_mangos_gundrak.sql new file mode 100644 index 0000000000..51b75eaacb --- /dev/null +++ b/sql_mr/mr00360_mangos_gundrak.sql @@ -0,0 +1,4 @@ +-- Gundrak +UPDATE creature_template SET UnitFlags = UnitFlags &~ 33600 WHERE `entry` IN (29307, 31365); +UPDATE creature_template SET `ScriptName` = 'mob_sladran_constrictor' WHERE `entry` = 29713; +UPDATE creature_template SET `ScriptName` = 'mob_sladran_snake_wrap' WHERE `entry` = 29742; diff --git a/sql_mr/mr00361_mangos_trial_of_crusader.sql b/sql_mr/mr00361_mangos_trial_of_crusader.sql new file mode 100644 index 0000000000..bb7f3739ac --- /dev/null +++ b/sql_mr/mr00361_mangos_trial_of_crusader.sql @@ -0,0 +1,153 @@ +-- instance +DELETE FROM `creature` WHERE `map` = 649 AND `id` IN +(34797,34796,34799,35144,34780,34460,34463,34461,34471,34475,34472,34453,34455,34458,34454,34451,34456,34497,34496,34564,34467,35465,34468,35610,34473,34474,34441,34449,34448,34450,34606, 34605, 34607); + +-- announcers +INSERT IGNORE INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `DeathState`, `MovementType`) VALUES +(600126, 34816, 649, 15, 65535, 0, 0, 559.258, 90.2662, 395.123, 5.01319, 300, 0, 0, 126000, 0, 0, 0); +UPDATE `creature_template` SET `ScriptName` = 'npc_toc_announcer' WHERE `entry` = 34816; +DELETE FROM `creature` WHERE `map` = 649 AND `id` = 35766; + +DELETE FROM `npc_text` WHERE `ID` IN (724001, 724002, 724003, 724004, 724005, 724006); +INSERT INTO `npc_text` (`ID`, `Text0_0`) VALUES +(724001, 'Greetings $N! Are you ready to be tested in Crusaders Coliseum?'), +(724002, 'Are you ready for the next stage?'), +(724003, 'Are you ready to fight the champions of the Silver vanguard?'), +(724004, 'Are you ready for the next stage?'), +(724005, 'Are you ready to continue battle with Anub-Arak?'), +(724006, 'Today, the arena is closed.'); + +DELETE FROM `locales_npc_text` WHERE `entry` IN (724001, 724002, 724003, 724004, 724005, 724006); +INSERT INTO `locales_npc_text` (`entry`, `Text0_0_loc1`, `Text0_0_loc2`, `Text0_0_loc3`, `Text0_0_loc4`, `Text0_0_loc5`, `Text0_0_loc6`, `Text0_0_loc7`, `Text0_0_loc8`) VALUES +(724001, 'Greetings $N! Are you ready to be tested in Crusaders Coliseum?', NULL, NULL, NULL, NULL, NULL, NULL, 'Приветствую, $N! Вы готовы пройти Испытание Крестоносца?'), +(724002, 'Are you ready for the next stage?', NULL, NULL, NULL, NULL, NULL, NULL, 'Вы готовы к следующему этапу?'), +(724003, 'Are you ready to fight the champions of the Silver vanguard?', NULL, NULL, NULL, NULL, NULL, NULL, 'Вы готовы драться с чемпионами Серебряного авангарда?'), +(724004, 'Are you ready for the next stage?', NULL, NULL, NULL, NULL, NULL, NULL, 'Вы готовы к следующему этапу?'), +(724005, 'Are you ready to continue battle with Anub-Arak?', NULL, NULL, NULL, NULL, NULL, NULL, 'Вы готовы продолжить бой с Ануб-Араком?'), +(724006, 'Today, the arena is closed.', NULL, NULL, NULL, NULL, NULL, NULL, 'На сегодня арена закрыта.'); + +UPDATE `creature_template` SET `ScriptName` = 'boss_lich_king_toc' WHERE `entry` = 35877; +UPDATE `creature_template` SET `ScriptName` = 'npc_fizzlebang_toc' WHERE `entry` = 35458; +DELETE FROM `creature` WHERE `map` = 649 AND `id` IN (35651, 22517); + +UPDATE `creature_template` SET `ScriptName` = 'npc_tirion_toc' WHERE `entry` = 34996; +UPDATE `creature_template` SET `ScriptName` = 'npc_garrosh_toc' WHERE `entry` = 34995; +UPDATE `creature_template` SET `ScriptName` = 'npc_rinn_toc' WHERE `entry` = 34990; + +-- Grand crusaders +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_warrior', `AIName` ='' WHERE `entry` IN (34475,34453); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_mage', `AIName` ='' WHERE `entry` IN (34468,34449); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_shaman', `AIName` ='' WHERE `entry` IN (34463,34455); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_enh_shaman', `AIName` ='' WHERE `entry` IN (34470,34444); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_hunter', `AIName` ='' WHERE `entry` IN (34467,34448); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_rogue', `AIName` ='' WHERE `entry` IN (34472,34454); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_priest', `AIName` ='' WHERE `entry` IN (34466,34447); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_shadow_priest', `AIName` ='' WHERE `entry` IN (34473,34441); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_dk', `AIName` ='' WHERE `entry` IN (34461,34458); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_paladin', `AIName` ='' WHERE `entry` IN (34465,34445); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_retro_paladin', `AIName` ='' WHERE `entry` IN (34471,34456); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_druid', `AIName` ='' WHERE `entry` IN (34460,34451); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_boomkin', `AIName` ='' WHERE `entry` IN (34469,34459); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_warlock' WHERE `entry` IN (34474,34450); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_pet_warlock', `AIName` ='' WHERE `entry` IN (35465); +UPDATE `creature_template` SET `ScriptName` = 'mob_toc_pet_hunter', `AIName` ='' WHERE `entry` IN (35610); + +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3444101 AND 3444119; + +-- Nortrend beasts +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (34796, 34799, 35144, 34797); +UPDATE `creature_template` SET `ScriptName` = 'mob_snobold_vassal', `AIName` = '' WHERE `entry` = 34800; +UPDATE `creature_template` SET `ScriptName` = 'mob_fire_bomb' WHERE `entry` = 34854; +UPDATE `creature_template` SET `ScriptName` = 'mob_slime_pool', `MinLevelHealth`= 30000, `MaxLevelHealth` = 30000, `ModelId3` = 11686 WHERE `entry` = 35176; + +-- Jaraxxus +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (34780, 34784, 34813, 34815, 34825, 34826); +UPDATE `creature_template` SET `ScriptName` = 'mob_legion_flame', `MinLevel` = 82, `MaxLevel` = 82, `ModelId1` = 11686, `ModelId2` = 11686, `ModelId3` = 11686, `ModelId4` = 11686, `AIName` ='' WHERE `entry` = 34784; +UPDATE `creature_template` SET `ScriptName` = 'mob_infernal_volcano', `AIName` ='' WHERE `entry` = 34813; +UPDATE `creature_template` SET `ScriptName` = 'mob_fel_infernal', `AIName` ='' WHERE `entry` = 34815; +UPDATE `creature_template` SET `ScriptName` = 'mob_nether_portal', `AIName` ='' WHERE `entry` = 34825; +UPDATE `creature_template` SET `ScriptName` = 'mob_mistress_of_pain', `AIName` ='' WHERE `entry` = 34826; + +-- Valkiries +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (34497, 34496, 34568, 34567); +UPDATE `creature_template` SET `NpcFlags` = 1, `ScriptName` = 'mob_light_essence', `AIName` ='' WHERE entry = 34568; +UPDATE `creature_template` SET `NpcFlags` = 1, `ScriptName` = 'mob_dark_essence', `AIName` ='' WHERE entry = 34567; +UPDATE `creature_template` SET `MinLevel` = 82, `MaxLevel` = 82, `AIName` = '', `ScriptName` = 'mob_unleashed_dark' WHERE `entry` = 34628; +UPDATE `creature_template` SET `MinLevel` = 82, `MaxLevel` = 82, `AIName` = '', `ScriptName` = 'mob_unleashed_light' WHERE `entry` = 34630; +-- Twin pact by Wowka321 +DELETE FROM `spell_script_target` WHERE `entry` IN (65875,67303,67304,67305,65876,67306,67307,67308); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +('65875', '1', '34497'), +('67303', '1', '34497'), +('67304', '1', '34497'), +('67305', '1', '34497'), +('65876', '1', '34496'), +('67306', '1', '34496'), +('67307', '1', '34496'), +('67308', '1', '34496'); + +-- Anub'arak +UPDATE `creature_template` SET `ScriptName` = 'boss_anubarak_trial', `UnitFlags` = 0, `AIName` = '' WHERE `entry` = 34564; + +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (34606, 34605, 34607, 34564, 34660); +UPDATE `creature_template` SET `ModelId1` = 25144, `ModelId2` = 0, `ModelId3` = 25144, `ModelId4` = 0, `AIName` = '', `ScriptName` = 'mob_frost_sphere' WHERE `entry` = 34606; +UPDATE `creature_template` SET `ScriptName` = 'mob_swarm_scarab', `AIName` ='' WHERE `entry`=34605; +UPDATE `creature_template` SET `ScriptName` = 'mob_nerubian_borrower', `AIName` ='' WHERE `entry`=34607; +UPDATE `creature_template` SET `ScriptName` = 'mob_anubarak_spike', `MinLevel` = 80, `MaxLevel` = 80, `AIName` = '' WHERE `entry` = 34660; + +DELETE FROM `creature_template` WHERE `entry` IN (7, 8, 9); +INSERT INTO `creature_template` (`Entry`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `KillCredit1`, `KillCredit2`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `Name`, `SubName`, `IconName`, `GossipMenuId`, `MinLevel`, `MaxLevel`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `Armor`, `FactionAlliance`, `FactionHorde`, `NpcFlags`, `SpeedWalk`, `SpeedRun`, `Scale`, `Rank`, `MinMeleeDmg`, `MaxMeleeDmg`, `DamageSchool`, `MeleeAttackPower`, `DamageMultiplier`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `UnitClass`, `UnitFlags`, `DynamicFlags`, `Family`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `MinRangedDmg`, `MaxRangedDmg`, `RangedAttackPower`, `CreatureType`, `CreatureTypeFlags`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MinLootGold`, `MaxLootGold`, `AIName`, `MovementType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MovementTemplateId`, `HealthMultiplier`, `EquipmentTemplateId`, `MechanicImmuneMask`, `ExtraFlags`, `ScriptName`) VALUES +(7, 0, 0, 0, 0, 0, 19725, 28549, 0, 0, 'Nerubian Burrow Two', '', '', 0, 1, 1, 1, 1, 0, 0, 17, 35, 35, 0, 1, 1.14286, 1, 0, 1, 2, 0, 0, 1, 2000, 2000, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, ''), +(8, 0, 0, 0, 0, 0, 19725, 28549, 0, 0, 'Nerubian Burrow Three', '', '', 0, 1, 1, 1, 1, 0, 0, 17, 35, 35, 0, 1, 1.14286, 1, 0, 1, 2, 0, 0, 1, 2000, 2000, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, ''), +(9, 0, 0, 0, 0, 0, 19725, 28549, 0, 0, 'Nerubian Burrow Four', '', '', 0, 1, 1, 1, 1, 0, 0, 17, 35, 35, 0, 1, 1.14286, 1, 0, 1, 2, 0, 0, 1, 2000, 2000, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, ''); + +DELETE FROM `creature_template_addon` WHERE `entry` IN (7, 8, 9); +INSERT INTO `creature_template_addon` VALUES +(7, 0, 0, 1, 0, 0, 0, '66324'), +(8, 0, 0, 1, 0, 0, 0, '66324'), +(9, 0, 0, 1, 0, 0, 0, '66324'); + +-- Must be spawned by the script!! +DELETE FROM `creature` WHERE `id` IN (34862, 7, 8, 8); +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `DeathState`, `MovementType`) VALUES +(600000, 34862, 649, 15, 1, 0, 0, 735.403, 75.3576, 142.202, 2.09439, 180, 0, 0, 1, 0, 0, 0), +(600001, 7, 649, 15, 1, 0, 0, 692.92, 184.809, 142.203, 5.35816, 180, 0, 0, 1, 0, 0, 0), +(600002, 8, 649, 15, 1, 0, 0, 688.207, 102.847, 142.202, 0.645772, 180, 0, 0, 1, 0, 0, 0), +(600003, 9, 649, 15, 1, 0, 0, 740.545, 189.113, 142.197, 3.75246, 180, 0, 0, 1, 0, 0, 0); + +UPDATE `gameobject_template` SET `flags` = '4' WHERE `entry` = 195485; +UPDATE `gameobject` SET `spawnMask` = '15' WHERE `guid` = 2358; +UPDATE `creature_template` SET `ExtraFlags` = '2' WHERE `entry` IN (34862, 7, 8, 9); + +-- PSZ patch for Fel Fireball (thx) +DELETE FROM `spell_dbc` WHERE `Id` IN (66532, 66963, 66964, 66965); +INSERT INTO `spell_dbc`( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `RangeIndex`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask` ) VALUES +(66532, 0, 1, 0, 0, 136, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 9, 0, 0, 101, 0, 0, 0, 0, 28, 13, 0, -1, 0, 0, 2, 6, 0, 775, 301, 0, 0, 0, 0, 15112, 5849, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2352, "Fel Fireball", 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 4 ), +(66963, 0, 1, 0, 0, 136, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 9, 0, 0, 101, 0, 0, 0, 0, 28, 13, 0, -1, 0, 0, 2, 6, 0, 1251, 475, 0, 0, 0, 0, 24374, 9262, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2352, "Fel Fireball", 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 4 ), +(66964, 0, 1, 0, 0, 136, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 9, 0, 0, 101, 0, 0, 0, 0, 28, 13, 0, -1, 0, 0, 2, 6, 0, 925, 401, 0, 0, 0, 0, 18037, 7799, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2352, "Fel Fireball", 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 4 ), +(66965, 0, 1, 0, 0, 136, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 9, 0, 0, 101, 0, 0, 0, 0, 28, 13, 0, -1, 0, 0, 2, 6, 0, 1751, 551, 0, 0, 0, 0, 34124, 10724, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2352, "Fel Fireball", 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 4 ); + +UPDATE `spell_dbc` SET `InterruptFlags` = 0x04, `Comment` = 'Replacement for spell "Fel Fireball" - set SPELL_INTERRUPT_FLAG_INTERRUPT' WHERE `Id` IN (66532, 66963, 66964, 66965); + +UPDATE `creature_template` SET `ModelId1` = '17612', `ModelId2` = '0' WHERE `entry` = 5672; +UPDATE `creature_template` SET `MinLevelHealth` = '12000', `MaxLevelHealth` = '12000' WHERE `entry` = 35458; + +UPDATE `creature_template` SET `ExtraFlags` = '2' WHERE `entry` = 33184; +UPDATE `creature_template` SET `Name` = 'Permafrost', `UnitFlags` = '0', `ModelId1` = '17612' WHERE `entry` = 33184; + +UPDATE `creature_template` SET `ExtraFlags` = '256' WHERE `entry` = 34800; + +UPDATE `creature_template` SET `MechanicImmuneMask` = 769605631 WHERE `entry` IN (34780, 35216, 35268, 35269); +UPDATE `creature_template` SET `MechanicImmuneMask` = 635387903 WHERE `entry` IN (34496, 35347, 35348, 35349); +UPDATE `creature_template` SET `MechanicImmuneMask` = 635387903 WHERE `entry` IN (34497, 35350, 35351, 35352); + +UPDATE `creature_template` SET `UnitFlags` = 0 WHERE `entry` IN (34566, 35615, 35616); + +UPDATE `creature_template` SET `ModelId2` = '0', `minlevel` = '83', `maxlevel` = '83', `DamageMultiplier` = '4' WHERE `entry` = 34660; +UPDATE `creature_template` SET `ModelId2` = '0', `minlevel` = '83', `maxlevel` = '83', `DamageMultiplier` = '6' WHERE `entry` = 35652; +UPDATE `creature_template` SET `ModelId2` = '0', `minlevel` = '83', `maxlevel` = '83', `DamageMultiplier` = '6' WHERE `entry` = 35653; +UPDATE `creature_template` SET `ModelId2` = '0', `minlevel` = '83', `maxlevel` = '83', `DamageMultiplier` = '8' WHERE `entry` = 35654; + +UPDATE `gameobject` SET `position_x` = '805.67', `position_y` = '129.72', `orientation` = '2.97' WHERE `id` = 195669; +UPDATE `gameobject` SET `position_x` = '804.48', `position_y` = '139.91', `orientation` = '3.49' WHERE `id` = 195670; +UPDATE `gameobject` SET `position_x` = '804.33', `position_y` = '124.45', `orientation` = '2.77' WHERE `id` = 195671; diff --git a/sql_mr/mr00367_mangos_instance_sunwell_plateau.sql b/sql_mr/mr00367_mangos_instance_sunwell_plateau.sql new file mode 100644 index 0000000000..ff0747b739 --- /dev/null +++ b/sql_mr/mr00367_mangos_instance_sunwell_plateau.sql @@ -0,0 +1,154 @@ +-- ------------------------ +-- Instance Sunwell Plateau +-- ------------------------ + +-- ------------ +-- Kalegcos --- +-- YTDB:614 --- +-- ------------ + +-- make normal and spectral realm bunnie invis to players +UPDATE `creature_template` SET `ExtraFlags` = 128 WHERE `entry` IN (25795, 25796); +-- correct spawn of kalegcos +UPDATE `creature` SET `position_x` = 1704.49, `position_y` = 925.522, `position_z` = -74.5584, `orientation` = 4.72577 WHERE `id` = 24891; +-- correct spawn of Sathrovarr +UPDATE `creature` SET `position_x` = 1704.63, `position_y` = 916.777, `position_z` = -74.5584, `orientation` = 1.68785 WHERE `id` = 24892; +-- disable spellProcEvent for invisibility spells +DELETE FROM `spell_proc_event` WHERE `entry` IN (46021, 44801); +INSERT INTO `spell_proc_event` SET `entry` = 46021; +INSERT INTO `spell_proc_event` SET `entry` = 44801; +-- prevent cast spell to players (it is self target) +-- ERROR:Table `spell_script_target`: spellId 44807 listed for TargetEntry 24850 does not have any implicit target TARGET_SCRIPT(38) or TARGET_SCRIPT_COORDINATES (46) or TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (40). +-- ERROR:Table `spell_script_target`: spellId 44807 listed for TargetEntry 24892 does not have any implicit target TARGET_SCRIPT(38) or TARGET_SCRIPT_COORDINATES (46) or TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (40). +DELETE FROM `spell_dbc` WHERE `Id` = 44807; +INSERT INTO `spell_dbc` (`Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) VALUES +(44807, 0, 0, 0, 264592, 0, 4, 268435456, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 101, 0, 0, 26, 26, 6, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 6, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 22, 0, 0, 7, 0, 0, 28, 0, 0, 23, 0, 0, 5000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, "Crazed Rage", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0 ); +UPDATE `spell_dbc` SET `EffectImplicitTargetA1` = 1, `EffectImplicitTargetB1` = 1, `Comment` = 'Replacement target for spell 44807 ("Crazed Rage")' WHERE `Id` = 44807; + +-- ------------ +-- Brutallus -- +-- YTDB:614 --- +-- ------------ + +-- remove static spawn as Madrigosa is summoned when needed +DELETE FROM `creature` WHERE `id` = 24895 AND `map` = 580; +-- brutallus should be a ground only walker +UPDATE `creature_template` SET `InhabitType` = 1 WHERE `entry` = 24882; +-- Death cloud invis to players +UPDATE `creature_template` SET `ExtraFlags` = 128 WHERE `entry` = 25703; + +-- ------------- +-- Felmyst ----- +-- YTDB:614 ---- +-- ------------- + +-- remove static spawn as Felmyst is summoned when needed +DELETE FROM `creature` WHERE `id` = 25038; + +UPDATE `creature_template` SET `ScriptName` = 'npc_felmyst_vapor' WHERE `entry` = 25265; + +-- Demonic Vapor :: unit flags (not attackable, pacified, not selectable), bosslevel, factions, speed, spawn/dmg aura +UPDATE `creature_template` SET `ModelId2` = 11686, `MinLevel` = 73, `MaxLevel` = 73, `FactionAlliance` = 16, `FactionHorde` = 16, `UnitFlags` = 33685506 WHERE `entry` = 25265; +DELETE FROM `creature_template_addon` WHERE `entry` = '25265'; +INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `b2_0_sheath`, `b2_1_pvp_state`, `emote`, `moveflags`, `auras`) VALUES +(25265, 0, 0, 0, 0, 0, 0, '45411'); + +-- Demonic Vapor Cloud :: unit flags (not attackable, pacified, not selectable), bosslevel, factions +UPDATE `creature_template` SET `ModelId2` = 11686, `MinLevel` = 73, `MaxLevel` = 73, `FactionAlliance` = 16, `FactionHorde` = 16, `UnitFlags` = 33685506 WHERE `entry` = 25267; + +-- Unyielding Death: Aura +DELETE FROM `creature_template_addon` WHERE `entry` = 25268; +INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `b2_0_sheath`, `b2_1_pvp_state`, `emote`, `moveflags`, `auras`) VALUES +(25268, 0, 0, 0, 0, 0, 0, '45415'); + +-- ------------ +-- The Twins -- +-- YTDB:614 --- +-- ------------ + +-- Shadowy Image fixes +UPDATE `creature_template` SET `MinLevel` = 73, `MaxLevel` = 73, `MinLevelHealth` = 10000, `MaxLevelHealth` = 10000, `FactionAlliance` = 14, `FactionHorde` = 14, `UnitFlags` = `UnitFlags` | 33554432 | 2 WHERE `entry` = 25214; + +-- ------------ +-- M'uru ------ +-- YTDB:614 --- +-- ------------ +UPDATE `creature_template` SET `AIName` = '', `EquipmentTemplateId` = 0 WHERE `entry` IN(25741, 25840); + +-- move slower then the player they are suppose run away from then +UPDATE `creature_template` SET `SpeedWalk` = 1, `SpeedRun` = 1.14286 WHERE `entry` = 25744; +-- shorter attack range ( needs to be for chase explode ) +UPDATE `creature_model_info` SET `combat_reach` = 0.5 WHERE `modelid` IN(1126,23842); + +-- Singularity + +-- move slower then the player they are suppose run away from then +UPDATE `creature_template` SET `FactionAlliance` = 14, `FactionHorde` = 14, `SpeedWalk` = 0, `SpeedRun` = 1.14286 WHERE `entry` = 25855; + +UPDATE `creature_template` SET `UnitFlags` = `UnitFlags` | 2, `ScriptName` = 'mob_singularity' WHERE `entry` = 25855; + +UPDATE `creature_template` SET `ModelId1` = 25206, `ModelId2` = 25206 WHERE `entry` = 25855; +-- added throw character aura if they get to close and acrance form aura +DELETE FROM `creature_template_addon` WHERE `entry` = 25855; +INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `b2_0_sheath`, `b2_1_pvp_state`, `emote`, `moveflags`, `auras`) VALUES +(25855, 0, 0, 0, 0, 0, 0, '46228 48019'); +-- short their attack range to they have to be close before effect iss triggered +UPDATE `creature_model_info` SET `bounding_radius` = 0.75, `combat_reach` = 0.5 WHERE `modelid` = 25206; + +-- added no movement to template as well +UPDATE `creature_template` SET `UnitFlags` = `UnitFlags` | 4 WHERE `entry` = 25770; +-- disable movement in spawn distance +UPDATE `creature` SET spawndist = 0, `MovementType` = 0 WHERE `id` = 25770; + +-- -------------------------------- +-- kil jaeden +-- YTDB:614 --- +-- -------------------------------- + +-- Replace Kil'jaeden with Kil'jaeden controller +DELETE FROM creature WHERE id = 25315; +-- Kalecgos summoning by script +DELETE FROM creature WHERE id = 25319; +-- Kalecgos speed +UPDATE `creature_template` SET `SpeedWalk` = 5, `SpeedRun` = 5 WHERE `entry` = 25319; +-- Anveena position +UPDATE `creature` SET position_z = 60.0 WHERE id = 26046; +-- Orb of the Blue Flight +UPDATE `gameobject_template` SET `type` = 10, `flags` = 16 WHERE `entry` = 188415; +-- Felfire Portal +UPDATE `creature_template` SET `UnitFlags` = 33554438, `FactionAlliance` = 14, `FactionHorde` = 14 WHERE `entry` = 25603; +-- Kil'jaeden +UPDATE `creature_template` SET `UnitFlags` = `UnitFlags` | 4 WHERE `entry` = 25315; +-- Shield Orb +UPDATE `creature_template` SET `ScriptName` = 'mob_shield_orb' WHERE `entry` = 25502; +UPDATE `creature_template` SET `SpeedWalk` = 2, `SpeedRun` = 2 WHERE `entry` = 25502; +-- armageddon creature +UPDATE `creature_template` SET `ModelId1` = 15880, `UnitFlags` = 33554438, `FactionAlliance` = 14, `FactionHorde` = 14, `MinLevel` = 73, `MaxLevel` = 73 WHERE `entry` = 25735; + +-- --------------------------------------------- +-- InstanceFixes and Related Data -------------- +-- YTDB:614 ------------------------------------ +-- --------------------------------------------- +UPDATE `gameobject_template` SET `flags` = `flags` | 6 WHERE `entry` IN(187990, 188118); +UPDATE `gameobject_template` SET `flags` = 38 WHERE `entry` = 188075; + +-- Some missing doors +DELETE FROM `gameobject` WHERE `id` = 188118 AND `map` = 580; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(600000, 188118, 580, 1, 1, 1777.03, 674.714, 71.1903, 2.31614, 0, 0, 0.916031, 0.401107, 25, 255, 1); + +DELETE FROM `gameobject` WHERE `id` = 187990 AND `map` = 580; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(600001, 187990, 580, 1, 1, 1849.54, 597.848, 81.9718, 5.59911, 0, 0, 0.335408, -0.942073, 25, 255, 1); + +DELETE FROM `gameobject` WHERE `id` = 187766 AND `map` = 580; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(600002, 187766, 580, 1, 1, 1710.29, 531.319, 93.3079, 4.30948, 0, 0, 0.834295, -0.551318, 25, 255, 1); + +DELETE FROM `gameobject` WHERE `id` = 187764 AND `map` = 580; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(600003, 187764, 580, 1, 1, 1832.99, 671.026, 42.7647, 4.45321, 0, 0, 0.792556, -0.609799, 25, 255, 1); + +DELETE FROM `gameobject` WHERE `id` = 187765 AND `map` = 580; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(600004, 187765, 580, 1, 1, 1693.96, 711.259, 83.7941, 6.18337, 0, 0, 0.0498847, -0.998755, 25, 255, 1); diff --git a/sql_mr/mr00374_scriptdev2_game_event_stuff.sql b/sql_mr/mr00374_scriptdev2_game_event_stuff.sql new file mode 100644 index 0000000000..c44f600947 --- /dev/null +++ b/sql_mr/mr00374_scriptdev2_game_event_stuff.sql @@ -0,0 +1,23 @@ +-- ------------------------------- +-- headless horseman event texts - +-- ------------------------------- + +DELETE FROM script_texts WHERE entry BETWEEN -1110006 AND -1110001; +INSERT INTO script_texts (entry, content_default, TYPE, sound) VALUES +(-1110001, "Prepare yourselves, the bells have tolled! Shelter your weak, your young and your old! Each of you shall pay the final sum. Cry for mercy, the reckoning has come!",1,11966), +(-1110002, "The sky is dark. The fire burns. You strive in vain as Fate's wheel turns.",1,12570), +(-1110003, "The town still burns, a cleansing fire! Time is short, I'll soon retire!",1,12571), + +(-1110004, "Fire consumes! You've tried and failed. Let there be no doubt, justice prevailed!",1,11967), +(-1110005, "My flames have died, left not a spark. I shall send you myself, to the lifeless dark.",1,11968); + +-- ------------------------------ +-- Pilgrim's bounty event texts - +-- ------------------------------ + +DELETE FROM `script_texts` WHERE `entry` in (-1730001, -1730002, -1730003, -1730004); +INSERT INTO `script_texts` (`entry`, `content_default`, `content_loc8`, `type`, `comment`) VALUES +(-1730001, 'Turkey Hunter!', 'Охотник на индеек!', 3, 'Pilgrim\'s Bounty - 10 Wild Turkeys killed'), +(-1730002, 'Turkey Domination!', 'Повелитель индеек!', 3, 'Pilgrim\'s Bounty - 20 Wild Turkeys killed'), +(-1730003, 'Turkey Slaughter!', 'Истребитель индеек!', 3, 'Pilgrim\'s Bounty - 30 Wild Turkeys killed'), +(-1730004, 'TURKEY TRIUMPH!', 'ТРИУМФ НАД ИНДЕЙКАМИ!', 3, 'Pilgrim\'s Bounty - 40 Wild Turkeys killed'); diff --git a/sql_mr/mr00389_mangos_game_event_stuff.sql b/sql_mr/mr00389_mangos_game_event_stuff.sql new file mode 100644 index 0000000000..c6ec9eafb1 --- /dev/null +++ b/sql_mr/mr00389_mangos_game_event_stuff.sql @@ -0,0 +1,105 @@ +-- ------------------------------ +-- Game Events && Holiday Stuff - +-- ------------------------------ + +-- -------------------------- +-- Hallow Ends +-- -------------------------- + +-- Fixed Correct spell on bobbing apples ( Hallow Ends Event ) // DBC still showing wrong description in-game but effect works like it should +UPDATE `item_template` SET `spellid_1` = 24707 WHERE `entry` = 20516; + +-- ------------------------------------------ +-- Boss Headless Horseman fight in scarlet monastry +-- ------------------------------------------ + +-- Pumkin fiend template fixes +UPDATE `creature_template` SET `ModelId2` = 21822, `FactionAlliance` = 14, `FactionHorde` = 14 WHERE `entry` = 23545; + +-- Pulsing pumkin template fixes +UPDATE `creature_template` SET `ModelId2` = 24720, `FactionAlliance` = 14, `FactionHorde` = 14, `CreatureType` = 6, `MechanicImmuneMask` = 8388624, `ExtraFlags` = 0 WHERE `entry` = 23694; + +-- head of the horseman fixes +UPDATE `creature_template` SET `ModelId2` = 21908, `FactionAlliance` = 7, `FactionHorde` = 7, `MechanicImmuneMask` = 787202047 WHERE `entry` = 23775; + +-- Fixes to his template ( smart to wiped clean and replaced data) +-- Headless Horseman fixes and ect +UPDATE `creature_template` SET `Rank` = 3, `CreatureType` = 6, `EquipmentTemplateId` = 10400, `MechanicImmuneMask` = `MechanicImmuneMask` | 128 WHERE `entry` = 23682; + +-- Fix quest script to correct horseman summon location +UPDATE `dbscripts_on_quest_end` SET `x` = 1766.8, `y` = 1349.54, `z` = 18.6855, `o` = 6.2786 WHERE `id` IN(11392, 11401, 11404, 11405); + +-- -- Quest fix to get quest inside instance w/o having the others from the villages ( this is the daily neutral one ) +UPDATE `quest_template` SET `PrevQuestId` = 0 WHERE `entry` = 11401; + +-- built new equip_template for him +DELETE FROM `creature_equip_template` WHERE `entry` = 10400; +INSERT INTO `creature_equip_template` (`entry`, `equipentry1`, `equipentry2`, `equipentry3`) VALUES +(10400, 38175, 0, 0); + +-- fix no sword showing on regen/whirlwinding headless dude +UPDATE `creature_template` SET `EquipmentTemplateId` = 10400 WHERE `entry` = 23800; + +-- -------------------------------------------------------------------------------------------------------------------------------------------- + +-- ----------------------------- +-- Headless horseman Quest Event +-- ----------------------------- + +-- Headless Horseman fire bunny +UPDATE creature_template SET UnitFlags = 0, AIName = '', FactionAlliance = 35, FactionHorde = 35, ScriptName = 'npc_horseman_fire_bunny' WHERE entry = 23686; +UPDATE creature_template SET InhabitType = 4, ScriptName = 'npc_shade_of_horseman' WHERE entry = 23543; + +-- Headless Horseman fire bunny +UPDATE creature_template SET UnitFlags = 0, AIName = 'EventAI' WHERE entry = 23686; +DELETE FROM creature_ai_scripts WHERE id IN (2368601, 2368602); +INSERT INTO creature_ai_scripts (id,creature_id,event_type,event_chance,action1_type,action1_param1) VALUES +-- visual fire aura on initial spawn +(2368601,23686,11,100,11,42075), +-- evade immediately after receiving bucket hit +(2368602,23686,4,100,24,0); + +DELETE FROM game_event WHERE entry = 101; +INSERT INTO game_event (entry,start_time,end_time,occurence,LENGTH,description) VALUES +(101,'2012-11-02 18:45:00','2020-12-31 09:00:00','15','6','Hallows End - Horseman Village Attack'); + +DELETE FROM creature WHERE id IN (23543,23686); +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `DeathState`, `MovementType`) VALUES +-- Elwynn Forest +-- Shade of Horseman +('600004','23543','0','1','1','0','1870','-9482.45','64.2219','76.6803','6.12238','900','0','0','2220','0','0','2'), +-- Fire Bunny +('600005','23686','0','1','65535','0','0','-9452.62','43.2718','57.0975','1.17919','900','0','0','67000','7196','0','0'), +('600006','23686','0','1','65535','0','0','-9452.99','80.362','57.3495','4.99359','900','0','0','67000','7196','0','0'), +('600007','23686','0','1','65535','0','0','-9468.09','79.9088','57.7395','4.60482','900','0','0','67000','7196','0','0'), +('600008','23686','0','1','65535','0','0','-9479.98','29.4727','56.1416','3.0835','900','0','0','67000','7196','0','0'), +('600009','23686','0','1','65535','0','0','-9480.2','41.9719','56.9226','2.84004','900','0','0','67000','7196','0','0'), +('600010','23686','0','1','65535','0','0','-9468.28','44.7625','56.7081','1.47502','900','0','0','67000','7196','0','0'), +('600011','23686','0','1','65535','0','0','-9481.17','23.2341','56.6099','2.91857','900','0','0','67000','7196','0','0'), +('600012','23686','0','1','65535','0','0','-9479.61','34.9436','57.3245','2.99319','900','0','0','67000','7196','0','0'), +('600013','23686','0','1','65535','0','0','-9460.37','81.2598','57.9887','4.87028','900','0','0','67000','7196','0','0'), +('600014','23686','0','1','65535','0','0','-9474.57','43.9885','56.6427','1.51664','900','0','0','67000','7196','0','0'), +('600015','23686','0','1','65535','0','0','-9458.91','45.2892','56.6756','1.48287','900','0','0','67000','7196','0','0'), +-- Durotar +-- Shade of Horseman +('600016','23543','1','1','1','0','1870','347.11','-4720.79','31.8356','1.29259','900','0','0','2220','0','0','2'), +-- Fire Bunny +('600017','23686','1','1','1','0','0','370.54','-4717.46','15.853','4.49793','900','0','0','67000','7196','0','0'), +('600018','23686','1','1','1','0','0','364.968','-4715.02','15.7461','3.795','900','0','0','67000','7196','0','0'), +('600019','23686','1','1','1','0','0','365.457','-4709.27','16.062','2.69151','900','0','0','67000','7196','0','0'), +('600020','23686','1','1','1','0','0','366.783','-4702.53','16.2973','2.73471','900','0','0','67000','7196','0','0'), +('600021','23686','1','1','1','0','0','345.918','-4710.18','16.7095','5.30687','900','0','0','67000','7196','0','0'), +('600022','23686','1','1','1','0','0','351.283','-4704.73','16.6699','5.31473','900','0','0','67000','7196','0','0'), +('600023','23686','1','1','1','0','0','356.453','-4700.39','16.5244','5.58962','900','0','0','67000','7196','0','0'), +('600024','23686','1','1','1','0','0','361.826','-4695.48','16.4174','5.55821','900','0','0','67000','7196','0','0'), +('600025','23686','1','1','1','0','0','338.509','-4707.98','17.6254','4.10129','900','0','0','67000','7196','0','0'), +('600026','23686','1','1','1','0','0','329.66','-4703.14','16.7397','4.31334','900','0','0','67000','7196','0','0'), +('600027','23686','1','1','1','0','0','322.6','-4698.53','16.8243','4.28585','900','0','0','67000','7196','0','0'); + +DELETE FROM game_event_creature WHERE guid IN (SELECT guid FROM creature WHERE id IN (23543,23686)); +INSERT INTO game_event_creature (guid, event) SELECT guid, 101 FROM creature WHERE id IN (23543,23686); + +-- -------------------------------- +-- Pilgrim's bounty event scripts - +-- -------------------------------- +UPDATE `creature_template` SET `ScriptName` = 'npc_wild_turkey' WHERE `entry` = 32820; diff --git a/sql_mr/mr00409_mangos_oculus.sql b/sql_mr/mr00409_mangos_oculus.sql new file mode 100644 index 0000000000..5ccb079381 --- /dev/null +++ b/sql_mr/mr00409_mangos_oculus.sql @@ -0,0 +1,136 @@ +-- --------------- +-- Oculus instance +-- --------------- +-- ---------------------- Script Names ---------------------- +UPDATE `creature_template` SET `ScriptName` = 'mob_oculus_dragon' WHERE `entry` IN (27692, 27756, 27755); +UPDATE `creature_template` SET `ScriptName` = 'npc_unstable_sphere' WHERE entry = 28166; +UPDATE `creature_template` SET `ScriptName` = 'boss_drakos' WHERE entry = 27654; +UPDATE `creature_template` SET `ScriptName` = 'boss_varos' WHERE entry = 27447; +UPDATE `creature_template` SET `ScriptName` = 'npc_varos_orb' WHERE entry = 28183; +UPDATE `creature_template` SET `ScriptName` = 'npc_varos_beam_target' WHERE entry = 28239; +UPDATE `creature_template` SET `ScriptName` = 'npc_oculus_robot' WHERE entry = 27641; +UPDATE `creature_template` SET `ScriptName` = 'npc_planar_anomaly' WHERE entry = 30879; +UPDATE `creature_template` SET `ScriptName` = 'npc_belgar_image' WHERE entry = 28012; +UPDATE `gameobject_template` SET `ScriptName` = 'go_oculus_portal' WHERE `entry` = 188715; + +-- ----------------------- Instance fixes DB ----------------------------- + +-- Unstable Sphere Fixes +UPDATE `creature_template` SET `MinLevel` = 81, `MaxLevel` = 81, `UnitFlags` = 33587202 WHERE `entry` = 28166; + +-- from traponinet +/* Belgaristrasz and his companions give Drake, after completed quest (13124) */ +UPDATE `creature_template` SET `GossipMenuId` = 27657 WHERE `entry` = 27657; +UPDATE `creature_template` SET `GossipMenuId` = 27658 WHERE `entry` = 27658; +UPDATE `creature_template` SET `GossipMenuId` = 27659 WHERE `entry` = 27659; + +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +-- (61407, 1, 27447), -- TargetEntry 27447 does not have any implicit target TARGET_SCRIPT(38) or TARGET_SCRIPT_COORDINATES (46) or TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (40). +(51022, 1, 28239); -- in YTDB target is 28236 + +DELETE FROM `dbscripts_on_gossip` WHERE `id` IN (27657, 27658, 27659); +INSERT INTO `dbscripts_on_gossip` VALUES +(27657,0,17,37815,1,0,0,0,0,0,0,0,0,0,0,0,''), +(27658,0,17,37860,1,0,0,0,0,0,0,0,0,0,0,0,''), +(27659,0,17,37859,1,0,0,0,0,0,0,0,0,0,0,0,''); + +DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (27657, 27658, 27659); +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `action_script_id`, `box_coded`, `box_money`, `box_text`) VALUES +(27657,0,0,'What\'s can Emerald Drake?.',1,1,13259,0,0,0,0,NULL), +(27657,1,2,'Take the Emerald Essence if you want to fly on the wings of the Green Flight.',1,1,-1,0,27657,0,0,NULL /*,16,37859,1,16,37815,1,16,37860,1*/), +(27659,0,0,'What\'s can Bronze Drake?.',1,1,13255,0,0,0,0,NULL), +(27659,1,2,'Take the Amber Essence if you want to fly on the wings of the Bronze Flight.',1,1,-1,0,27659,0,0,NULL /*,16,37859,1,16,37815,1,16,37860,1*/), +(27658,0,0,'What\'s can Ruby Drake?.',1,1,13257,0,0,0,0,NULL), +(27658,1,2,'Take the Ruby Essence if you want to fly on the wings of the Red Flight.',1,1,-1,0,27658,0,0,NULL /*,16,37859,1,16,37815,1,16,37860,1*/); +-- (27658,0,0,'GOSSIP_OPTION_QUESTGIVER',2,2,0,0,0,0,0,NULL); + +DELETE FROM `locales_gossip_menu_option` WHERE `menu_id` IN (27657, 27658, 27659); +INSERT INTO `locales_gossip_menu_option` (`menu_id`, `id`, `option_text_loc1`, `option_text_loc2`, `option_text_loc3`, `option_text_loc4`, `option_text_loc5`, `option_text_loc6`, `option_text_loc7`, `option_text_loc8`, `box_text_loc1`, `box_text_loc2`, `box_text_loc3`, `box_text_loc4`, `box_text_loc5`, `box_text_loc6`, `box_text_loc7`, `box_text_loc8`) VALUES +(27657, 0, 'What\'s can Emerald Drake?', NULL, NULL, NULL, NULL, NULL, NULL, 'Что умеет Изумрудный дракон?', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(27657, 1, 'Take the Emerald Essence if you want to fly on the wings of the Green Flight.', NULL, NULL, NULL, NULL, NULL, NULL, 'Возьмите Изумрудную эссенцию, если Вы хотите лететь на зеленом драконе.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(27659, 0, 'What\'s can Bronze Drake?', NULL, NULL, NULL, NULL, NULL, NULL, 'Что умеет Бронзовый дракон?', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(27659, 1, 'Take the Amber Essence if you want to fly on the wings of the Bronze Flight.', NULL, NULL, NULL, NULL, NULL, NULL, 'Возьмите Янтарную эссенцию, если Вы хотите лететь на бронзовом драконе.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(27658, 0, 'What\'s can Red Drake?', NULL, NULL, NULL, NULL, NULL, NULL, 'Что умеет Красный дракон?', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(27658, 1, 'Take the Ruby Essence if you want to fly on the wings of the Red Flight.', NULL, NULL, NULL, NULL, NULL, NULL, 'Возьмите Рубиновую эссенцию, если Вы хотите лететь на красном драконе.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + +DELETE FROM `gossip_menu` WHERE `entry` IN (27657, 27658, 27659); +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES +(27657,13258), +(27658,13254), +(27659,13256); +DELETE FROM `gossip_menu` WHERE `entry` IN (13259, 13255, 13257); +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES +(13259,13259), +(13255,13255), +(13257,13257); + +-- Fix YTDB bug +UPDATE `npc_text` SET `text0_0` = `text0_1` WHERE `text0_0` = '' AND `ID` IN (13258,13259); +UPDATE `locales_npc_text` SET `Text0_0_loc8` = `Text0_1_loc8` WHERE `Text0_0_loc8` = '' AND `entry` IN (13258,13259); + +-- Eregos chests +UPDATE `gameobject` SET `spawnMask` = 2 WHERE `map` = 578 AND `id` = 193603; +UPDATE `gameobject` SET `spawnMask` = 1 WHERE `map` = 578 AND `id` = 191349; + +UPDATE `creature_template` SET `InhabitType` = 3 WHERE `entry` IN (27755,27756,27692); + +UPDATE `creature_template_addon` SET `bytes1` = 0, `b2_0_sheath` = 0, `b2_1_pvp_state` = 0 , `auras` = '57403' WHERE `entry` IN (27755, 27756, 27692); + +/* hack for broken Nexus Portal */ +UPDATE `gameobject_template` SET `data0` = 49665 WHERE `entry` = 189985; +UPDATE `spell_target_position` SET `id` = 49665 WHERE `id` = 49305; + +UPDATE `creature_template` SET `InhabitType` = 3 WHERE `entry` IN (27692, 27755, 27756); + +DELETE FROM `dbscripts_on_go_use` WHERE id IN (40557,42275); +INSERT INTO `dbscripts_on_go_use` (id, delay, command, datalong, datalong2, dataint, x, y, z, o, comments) VALUES +(42275, 1, 6, 571, 0, '0', 3878.0, 6984.0, 106.0, 0, ''), +(40557, 1, 6, 578, 0, '0', 1001.61, 1051.13, 359.48, 3.1, ''); + +DELETE FROM `spell_script_target` WHERE `entry` IN (49460, 49346, 49464); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(49460, 1, 27755), +(49346, 1, 27692), +(49464, 1, 27756); + +DELETE FROM `creature_spell` WHERE `guid` IN (27755,27756,27692); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(27756, 50232, 0, 0, 0, 0), +(27756, 50248, 1, 0, 0, 0), +(27756, 50240, 2, 0, 0, 0), +(27756, 50253, 3, 0, 0, 0), +(27756, 57403, 5, 0, 0, 0); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(27755, 49840, 0, 0, 0, 0), +(27755, 49838, 1, 0, 0, 0), +(27755, 49592, 2, 0, 0, 0), +(27755, 57403, 5, 0, 0, 0); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(27692, 50328, 0, 0, 0, 0), +(27692, 50341, 1, 0, 0, 0), +(27692, 50344, 2, 0, 0, 0), +(27692, 57403, 5, 0, 0, 0); + +DELETE FROM `spell_script_target` WHERE `entry` IN (49460, 49346, 49464); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(49460, 1, 27755), +(49346, 1, 27692), +(49464, 1, 27756); + +-- herbalism flower a ytdb bugs flowers cant wander around lol +UPDATE `creature_template` SET `UnitFlags` = 33555204, `DynamicFlags` = 8 WHERE `entry` = 29888; +UPDATE `creature_template` SET `SpeedWalk` = 0, `SpeedRun` = 0, `MovementTemplateId` = 0 WHERE `entry` = 29888; + +-- Varos +UPDATE `creature_template` SET `MechanicImmuneMask` = 617299931 WHERE `entry` = 27447; -- added immune to pacify +UPDATE `creature_template` SET `MechanicImmuneMask` = 617299931 WHERE `entry` = 31559; -- added immune to pacify to hard version + +-- Drakos the Interrogator +UPDATE `creature_template` SET `MaxLevelHealth` = 431392 WHERE `entry` = 31558; -- Hard Instance Version data from wow.com +UPDATE `creature_template` SET `MechanicImmuneMask` = 617299931 WHERE `entry` = 27654; -- added immune to pacify +UPDATE `creature_template` SET `MechanicImmuneMask` = 617299931 WHERE `entry` = 31558; -- added immune to pacify to hard version + +-- ---------------------Achievements ------------------------------ + +-- Make It Count + Expirienced Drake Rider +DELETE FROM `achievement_criteria_requirement` WHERE `criteria_id` IN(7145, 7178, 7179, 7177) AND `type` = 18; diff --git a/sql_mr/mr00423_mangos_utgarde_pinnacle.sql b/sql_mr/mr00423_mangos_utgarde_pinnacle.sql new file mode 100644 index 0000000000..c481d45415 --- /dev/null +++ b/sql_mr/mr00423_mangos_utgarde_pinnacle.sql @@ -0,0 +1,13 @@ +-- svala +DELETE FROM spell_script_target WHERE entry = 59930; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(59930, 1, 26555); + +UPDATE `creature_template` SET `FactionAlliance` = 35, `FactionHorde` = 35 WHERE `entry` = 27327; +UPDATE `creature_template` SET `FactionAlliance` = 35, `FactionHorde` = 35 WHERE `entry` = 30805; +UPDATE `creature_template` SET `FactionAlliance` = 14, `FactionHorde` = 14, `InhabitType` = 7 WHERE `entry` = 27273; +UPDATE `creature_template` SET `FactionAlliance` = 14, `FactionHorde` = 14, `InhabitType` = 7 WHERE `entry` = 30771; + +-- skadi +UPDATE `creature_template` SET `InhabitType` = 7 WHERE `entry` = 26893; +UPDATE `creature_template` SET `InhabitType` = 7 WHERE `entry` = 30775; diff --git a/sql_mr/mr00427_mangos_naxxramas.sql b/sql_mr/mr00427_mangos_naxxramas.sql new file mode 100644 index 0000000000..329ffb4c01 --- /dev/null +++ b/sql_mr/mr00427_mangos_naxxramas.sql @@ -0,0 +1,43 @@ +-- ----------------------------- Achievemets: -------------------------------- +-- Arachnophobia +DELETE FROM `achievement_criteria_requirement` WHERE `criteria_id` IN (7129, 7128) AND `type` = 18; + +-- And The Would All Go Down Together +DELETE FROM `achievement_criteria_requirement` WHERE `criteria_id` IN (7600,7601); +INSERT INTO `achievement_criteria_requirement` VALUES +(7600,12,0,0), +(7600,18,0,0), +(7601,12,1,0), +(7601,18,0,0); + +-- The Military Quarter (Horsemen) +DELETE FROM `achievement_criteria_requirement` WHERE `criteria_id` IN(7192,7193); +INSERT INTO `achievement_criteria_requirement` VALUES +(7192,12,0,0), +(7193,12,1,0); + +-- Make Quick Werk of Him +DELETE FROM `achievement_criteria_requirement` WHERE `criteria_id` IN(7126, 7127) AND `type` = 18; + +-- ----------- +-- Anub'Rekhan +-- ----------- + +-- Crypt Guard summon by script +DELETE FROM `creature` WHERE `id` = 16573; + +-- Replace DBC values for spell 29105 - "Summon Corpse Scarabs (5)" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 29105; +INSERT INTO `spell_dbc` ( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) VALUES +(29105, 0, 0, 0, 8388864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 28, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16698, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, "Summon Corpse Scarabs (5)", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0 ); + +UPDATE `spell_dbc` SET `EffectRadiusIndex1` = 0, `Comment` = 'Summon Corpse Scarabs (5) - Summon in caster location' WHERE `Id` = 29105; + +-- Replace DBC values for spell 28864 - "Summon Corpse Scarabs (10)" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 28864; +INSERT INTO `spell_dbc` ( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) VALUES +(28864, 0, 0, 0, 8388864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 28, 0, 0, 1, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16698, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, "Summon Corpse Scarabs (10)", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0 ); + +UPDATE `spell_dbc` SET `EffectRadiusIndex1` = 0, `Comment` = 'Summon Corpse Scarabs (10) - Summon in caster location' WHERE `Id` = 28864; diff --git a/sql_mr/mr00436_mangos_eye_of_eternity.sql b/sql_mr/mr00436_mangos_eye_of_eternity.sql new file mode 100644 index 0000000000..550a26ec86 --- /dev/null +++ b/sql_mr/mr00436_mangos_eye_of_eternity.sql @@ -0,0 +1,47 @@ + +-- only 56266 is used +DELETE FROM `spell_script_target` WHERE `targetEntry` = 30090; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(55853, 1, 30090), -- nonhero +(56263, 1, 30090), +(56264, 1, 30090), +(56265, 1, 30090), +(56266, 1, 30090), +(61071, 1, 30090), -- hero +(61072, 1, 30090), +(61073, 1, 30090), +(61074, 1, 30090), +(61075, 1, 30090); + +UPDATE creature_template SET InhabitType = 7, AIName ='NullAI' WHERE entry IN (30090, 30118); +-- UPDATE creature SET MovementType = 1 WHERE id = 30090; + +-- Eye of Eternity from Tassadar && bwsrv +UPDATE `gameobject_template` SET `ScriptName`='go_focusing_iris' WHERE entry IN (193958, 193960); +UPDATE `creature_template` SET `ScriptName`='npc_nexus_lord' WHERE entry=30245; +UPDATE `creature_template` SET `ScriptName`='npc_scion_of_eternity' WHERE entry=30249; +UPDATE `creature_template` SET `ScriptName`='npc_hover_disk' WHERE entry IN (30234, 30248); +UPDATE `creature_template` SET `InhabitType` = 7, `ScriptName`='npc_whyrmrest_skytalon' WHERE entry=30161; +UPDATE `creature_template` SET `InhabitType` = 7 WHERE entry=31752; +UPDATE `creature_template` SET `ScriptName`='npc_alexstrasza' WHERE entry=32295; + +DELETE FROM `npc_spellclick_spells` WHERE npc_entry IN (30234, 30248); +INSERT INTO `npc_spellclick_spells` (npc_entry, spell_id, quest_start, quest_start_active, quest_end, cast_flags) VALUES +(30234, 48754, 0, 0, 0, 1), +(30248, 48754, 0, 0, 0, 1); + +DELETE FROM `creature_spell` WHERE `guid` IN (30161,31752); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`) VALUES +(30161, 56091, 0), +(30161, 56092, 1), +(30161, 57090, 2), +(30161, 57143, 3), +(30161, 57108, 4), +(30161, 57092, 5); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`) VALUES +(31752, 56091, 0), +(31752, 56092, 1), +(31752, 57090, 2), +(31752, 57143, 3), +(31752, 57108, 4), +(31752, 57092, 5); diff --git a/sql_mr/mr00443_mangos_icecrown.sql b/sql_mr/mr00443_mangos_icecrown.sql new file mode 100644 index 0000000000..818d4994c4 --- /dev/null +++ b/sql_mr/mr00443_mangos_icecrown.sql @@ -0,0 +1,528 @@ +-- -------- +-- Entrance +-- -------- + +-- make teleports always usable +-- TODO: implement "discovering" teleports +UPDATE `gameobject_template` SET `flags` = 0, `ScriptName` = 'go_icecrown_teleporter' WHERE `entry` IN (202242, 202243, 202244, 202245, 202235, 202223, 202246); +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(70856, 0, 202223), +(70856, 0, 202235), +(70856, 0, 202242), +(70856, 0, 202243), +(70856, 0, 202244), +(70856, 0, 202245), +(70856, 0, 202246), +(70857, 0, 202223), +(70857, 0, 202235), +(70857, 0, 202242), +(70857, 0, 202243), +(70857, 0, 202244), +(70857, 0, 202245), +(70857, 0, 202246), +(70858, 0, 202223), +(70858, 0, 202235), +(70858, 0, 202242), +(70858, 0, 202243), +(70858, 0, 202244), +(70858, 0, 202245), +(70858, 0, 202246), +(70859, 0, 202223), +(70859, 0, 202235), +(70859, 0, 202242), +(70859, 0, 202243), +(70859, 0, 202244), +(70859, 0, 202245), +(70859, 0, 202246), +(70860, 0, 202223), +(70860, 0, 202235), +(70860, 0, 202242), +(70860, 0, 202243), +(70860, 0, 202244), +(70860, 0, 202245), +(70860, 0, 202246), +(70861, 0, 202223), +(70861, 0, 202235), +(70861, 0, 202242), +(70861, 0, 202243), +(70861, 0, 202244), +(70861, 0, 202245), +(70861, 0, 202246), +(70781, 0, 202223), +(70781, 0, 202235), +(70781, 0, 202242), +(70781, 0, 202243), +(70781, 0, 202244), +(70781, 0, 202245), +(70781, 0, 202246); + +REPLACE INTO `spell_target_position` (`id`, `target_map`, `target_position_x`, `target_position_y`, `target_position_z`, `target_orientation`) VALUES +(70781, 631, -17.1928, 2211.44, 30.1158, 3.14), +(70856, 631, -503.62, 2211.47, 62.8235, 3.14), +(70857, 631, -615.145, 2211.47, 199.972, 0), +(70858, 631, -549.131, 2211.29, 539.291, 0), +(70859, 631, 4198.42, 2769.22, 351.065, 0), +(70861, 631, 4356.58, 2565.75, 220.402, 4.9); + +-- Icecrown buff +DELETE FROM `spell_area` WHERE `spell` IN +(73762, 73824, 73825, 73826, 73827, 73828, -- Alliance +73816, 73818, 73819, 73820, 73821, 73822); -- Horde +-- +5% +-- INSERT INTO `spell_area` (`spell`, `area`, `racemask`, `gender`, `autocast`) VALUES +-- (73762, 4812, 1101, 2, 1), -- Alliance +-- (73816, 4812, 690, 2, 1); -- Horde +-- +10% +-- INSERT INTO `spell_area` (`spell`, `area`, `racemask`, `gender`, `autocast`) VALUES +-- (73824, 4812, 1101, 2, 1), -- Alliance +-- (73818, 4812, 690, 2, 1); -- Horde +-- +15% +-- INSERT INTO `spell_area` (`spell`, `area`, `racemask`, `gender`, `autocast`) VALUES +-- (73825, 4812, 1101, 2, 1), -- Alliance +-- (73819, 4812, 690, 2, 1); -- Horde +-- +20% +-- INSERT INTO `spell_area` (`spell`, `area`, `racemask`, `gender`, `autocast`) VALUES +-- (73826, 4812, 1101, 2, 1), -- Alliance +-- (73820, 4812, 690, 2, 1); -- Horde +-- +25% +-- INSERT INTO `spell_area` (`spell`, `area`, `racemask`, `gender`, `autocast`) VALUES +-- (73827, 4812, 1101, 2, 1), -- Alliance +-- (73821, 4812, 690, 2, 1); -- Horde +-- +30% +-- INSERT INTO `spell_area` (`spell`, `area`, `racemask`, `gender`, `autocast`) VALUES +-- (73828, 4812, 1101, 2, 1), -- Alliance +-- (73822, 4812, 690, 2, 1); -- Horde + +-- -------- +-- Saurfang +-- -------- + +-- vehicle_id: ytdb = 591, here some old custom = 639 +UPDATE `creature_template` SET `AIName`='', `ScriptName`='boss_deathbringer_saurfang' WHERE `entry`=37813; +UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_highlord_saurfang_icc' WHERE `entry`=37187; +UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_deathbringer_event_guards_iccAI' WHERE `entry` IN (37920, 37902); +UPDATE `creature_template` SET `AIName`='', `ScriptName`='mob_blood_beast' WHERE `entry`= 38508; + +-- is this needed? +-- UPDATE `creature_template` SET `PowerType` = 3 WHERE `entry` IN (38402,38582,38583); +-- old hacky way of moving from behind the door +-- UPDATE `creature` SET `position_x` = -476.621 WHERE `id` = 37813; + +DELETE FROM `spell_proc_event` WHERE entry IN (72178, 72256); +INSERT INTO `spell_proc_event` VALUES +(72256, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), +(72178, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0); + +-- Rune of Blood (Saurfang) +DELETE FROM `spell_proc_event` WHERE `entry` = 72408; +INSERT INTO `spell_proc_event` () VALUES +(72408, 0x00, 0x00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000, 0x00000000, 0x00000000, 0x00000014, 0x00000003, 0, 0, 0); + +-- Blood Link (Saurfang, Blood Beast) +DELETE FROM `spell_proc_event` WHERE `entry` = 72176; +INSERT INTO `spell_proc_event` () VALUES +(72176, 0x00, 0x00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000, 0x00000000, 0x00000000, 0x00000014, 0x00000003, 0, 0, 0); + +-- update attack speed for Saurfang (in ytdb other than 10normal have 2s) +UPDATE `creature_template` SET MeleeBaseAttackTime = 1000 WHERE `entry` IN (37813, 38402, 38582, 38583); + + +-- ------------ +-- Deathwhisper +-- ------------ + +UPDATE `creature_template` SET `ExtraFlags` = `ExtraFlags` | 256 WHERE `entry` IN (38296, 38297); -- can't taunt on heroic mode +UPDATE `creature_template` SET `FactionAlliance` = 14, `FactionHorde` = 14,`ScriptName` = '', `AIName` = 'EventAI' WHERE `entry`= 38222; +UPDATE `creature_template` SET `ScriptName`='mob_cult_adherent', `AIName`='' WHERE `entry`= 37949; +UPDATE `creature_template` SET `ScriptName`='mob_cult_fanatic', `AIName`='' WHERE `entry`= 37890; + +-- Vengeful Blast aura for shades +DELETE FROM `creature_template_addon` WHERE `entry` = 38222; +INSERT INTO `creature_template_addon` (`entry`, `auras`) VALUES (38222, "71494"); + +-- --------- +-- Marrowgar +-- --------- + +UPDATE `creature_template` SET `ScriptName`='mob_coldflame', `MinLevel` = 82, `MaxLevel` = 82, `ModelId1` = 11686, `ModelId2` = 11686, `ModelId3` = 11686, `ModelId4` = 11686, `FactionAlliance` = 14, `FactionHorde` = 14, `AIName`='' WHERE `entry`= 36672; +UPDATE `creature_template` SET `ScriptName`='mob_bone_spike', `AIName`='' WHERE `entry`= 38711; + +-- -------------- +-- Gunship battle +-- -------------- + +UPDATE `creature_template` SET `ScriptName`='mob_spire_frostwyrm', `AIName`='' WHERE `entry`= 37230; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 37230; +UPDATE `creature_template` SET `ScriptName`='mob_frost_giant', `AIName`='' WHERE `entry` IN (38490, 38494) ; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (38490, 38494); +DELETE FROM `creature` WHERE `guid` = 94094 AND `id` = 38490; + +-- -------------- +-- Gunship armory +-- -------------- + +-- ----------- +-- Plague wing +-- ----------- + +-- ------- +-- Rotface +-- ------- + +UPDATE `creature_template` SET `FactionAlliance` = 14, `FactionHorde` = 14, `ScriptName` = 'mob_rotface_ooze_dummy', UnitFlags = 524288, ExtraFlags = ExtraFlags | 2 WHERE `entry` IN (37013, 37986, 38548); +UPDATE `creature_template` SET `FactionAlliance` = 2212, `FactionHorde` = 2212, `ScriptName` = 'mob_sticky_ooze' WHERE `entry` = 37006; +UPDATE `creature_template` SET `FactionAlliance` = 2212, `FactionHorde` = 2212, `ScriptName` = 'mob_ooze_explosion_stalker' WHERE `entry` = 38107; + +DELETE FROM `spell_script_target` WHERE `entry` = 70079; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +('70079', '1', '36627'); -- Ooze Flood remove + +-- fix rotface combat reach was set to 40 he could hit u from across the room +UPDATE `creature_model_info` SET `combat_reach` = 4 WHERE `modelid` = 31005; + +-- fix stinky modelID info +UPDATE `creature_model_info` SET `combat_reach` = 1 WHERE `modelid` = 30483; + +-- fix flags of Puddle Stalkers +UPDATE `creature_template` SET `UnitFlags` = 524288 WHERE `entry` = 37013; + +-- --------- +-- Festergut +-- --------- + +UPDATE `creature_template` SET `ScriptName` = 'mob_vile_gas_malleable_goo', `ExtraFlags` = `ExtraFlags` | 2 | 128 WHERE `entry` IN (38548, 38556); +-- orange gas stalker +UPDATE `creature_template` SET `UnitFlags` = `UnitFlags` & ~33554432 & ~2, `FactionAlliance` = 2212, `FactionHorde` = 2212, `ScriptName`='', `AIName`='' WHERE `entry`= 36659; +DELETE FROM `spell_script_target` WHERE `entry` IN (69157, 69162, 69164); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(69157, 1, 36659), +(69162, 1, 36659), +(69164, 1, 36659); + +-- original auras from YTDB +-- DELETE FROM `creature_template_addon` WHERE `entry` = 36659; +-- INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `bytes2`, `emote`, `moveflags`, `auras`) VALUES +-- (36659, 0, 0, 1, 0, 0, '69126 69152 69154'); + +-- gas from valves +UPDATE `creature` SET `spawntimesecs` = 300 WHERE `id` = 37013; +DELETE FROM `spell_script_target` WHERE `entry` = 69125; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES (69125, 1, 37013); + +-- proper way for Gastric Bloat, but cooldowns for creatures not implemented yet +-- -- Gastric Bloat +-- DELETE FROM `spell_proc_event` WHERE `entry` = 72214; +-- INSERT INTO `spell_proc_event` VALUES +-- (72214, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 8); + +-- fixed modelID info +UPDATE `creature_model_info` SET `combat_reach` = 4 WHERE `modelid` = 31006; + +-- fix peroicus modelID info +UPDATE `creature_model_info` SET `combat_reach` = 1 WHERE `modelid` = 30483; + +-- make triggers not visible +UPDATE `creature_template` SET `UnitFlags` = `UnitFlags` | 33554432 | 2 WHERE entry IN (37013, 37986, 38107, 38548, 37006, 38107, 38548, 38556, 36659); + +-- ------------------- +-- Professor putricide +-- ------------------- + +UPDATE `gameobject_template` SET `data0` = 0 WHERE `entry` IN (201613, 201614); +UPDATE `gameobject` SET `state` = 1 WHERE `id` IN (201614, 201613); +UPDATE `gameobject` SET `state` = '0' WHERE `id` IN (201372); +UPDATE `creature_template` SET `ScriptName`='mob_icc_gas_cloud', `AIName`='' WHERE `entry`= 37562; +UPDATE `creature_template` SET `ScriptName`='mob_icc_volatile_ooze', `AIName`='' WHERE `entry`= 37697; +UPDATE `creature_template` SET `ScriptName` = 'mob_choking_gas_bomb', `AIName` = '',`MinLevel` = 82, `MaxLevel` = 82, `Scale` = 0.5 WHERE `entry` = 38159; +UPDATE `creature_template` SET `ScriptName` = 'mob_ooze_puddle', `Scale` = 1.0, `AIName` = '', `MinLevel` = 82, `MaxLevel` = 82, `ModelId1` = 11686, `ModelId2` = 11686, `ModelId3` = 11686, `ModelId4` = 11686 WHERE `entry` = 37690; +UPDATE `gameobject_template` SET `faction` = 0, `ScriptName` = 'go_plague_sigil' WHERE `entry` = 202182; + +DELETE FROM `spell_script_target` WHERE `entry` = 71617; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(71617, 1, 38317); -- Tear Gas + +-- delete Grow Stacker - handle in script +DELETE FROM `creature_template_addon` WHERE `entry` = 37690; + +-- Transform +REPLACE INTO `spell_script_target` +(`entry`, `type`, `targetEntry`) VALUES +(72850, 1, 38308), +(72850, 1, 38309), +(72851, 1, 38308), +(72851, 1, 38309), +(72852, 1, 38308), +(72852, 1, 38309); + + +-- remove proc from Mutated Strength - currently cooldown for creatures not handled in core +DELETE FROM `spell_proc_event` WHERE `entry` IN (71604, 72673, 72674, 72675); +INSERT INTO `spell_proc_event` (`entry`, `procFlags`) VALUES +(71604, 256), +(72673, 256), +(72674, 256), +(72675, 256); + +-- ----------- +-- Abomination +-- ----------- + +DELETE FROM `spell_script_target` WHERE `entry` IN (70360,72527); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(70360, 1, 37690), +(72527, 1, 37690); + +UPDATE `creature_template` SET `ScriptName`='mob_mutated_amobination' WHERE `entry`=37672; + +-- GO Drink Me table -- +UPDATE `gameobject_template` SET `ScriptName`='go_drink_me', `data3`=0 WHERE `entry`=201584; + +-- ---------- +-- Blood wing +-- ---------- + +UPDATE `gameobject_template` SET `faction` = 0, `ScriptName` = 'go_bloodwing_sigil' WHERE `entry` = 202183; + +-- -------------- +-- Lanathel intro +-- -------------- + +UPDATE `creature_template` SET `ScriptName`='boss_blood_queen_lanathel_intro', `AIName`='' WHERE `entry`= 38004; + +UPDATE `creature_template` SET `MinLevelHealth` = 5647725, `MaxLevelHealth` = 5647725, `ScriptName`='npc_blood_orb_control', `AIName`='' WHERE `entry`= 38008; +UPDATE `creature_template` SET `MinLevelHealth` = 22590900, `MaxLevelHealth` = 22590900 WHERE `entry` = 38641; +UPDATE `creature_template` SET `MinLevelHealth` = 7600025, `MaxLevelHealth` = 7600025 WHERE `entry` = 38773; +UPDATE `creature_template` SET `MinLevelHealth` = 30469825, `MaxLevelHealth` = 30469825 WHERE `entry` = 38774; + +-- -------- +-- Taldaram +-- -------- + +UPDATE `creature_template` SET `ScriptName` = 'mob_ball_of_flames' WHERE `entry` IN (38332, 38451); + +-- ------- +-- Valanar +-- ------- + +UPDATE `creature_template` SET `ScriptName` = 'mob_kinetic_bomb' WHERE `entry` = 38454; +UPDATE `creature_template` SET `ScriptName` = 'mob_shock_vortex', `AIName` = '' WHERE `entry` = 38422; +UPDATE `creature_template` SET `ScriptName`='mob_kinetic_bomb_target', `AIName`='' WHERE `entry`= 38458; + +DELETE FROM `spell_proc_event` WHERE `entry` = 72059; +INSERT INTO `spell_proc_event` (`entry`, `SchoolMask`, `procFlags`, `procEx`) VALUES +(72059, 127, 0x00000008|0x00000020|0x00000080|0x00000200|0x00002000|0x00020000|0x00400000, 0x0010000); + +-- -------- +-- Keleseth +-- -------- + +UPDATE `creature_template` SET `ScriptName` = 'mob_dark_nucleus', `FactionAlliance` = 14, `FactionHorde` = 14 WHERE `entry` = 38369; + +DELETE FROM `creature_template_addon` WHERE `entry` IN (37972,37973,37970,38401,38784,38785,38399,38769,38770,38400,38771,38772); + + +-- ----------------- +-- Loot and deathstate for blood council (correct YTDB bugs, flags - from already killed princes) +-- ----------------- + +UPDATE `creature_template` SET `UnitFlags` = 0 WHERE `entry` IN (37972,37973,37970,38401,38784,38785,38399,38769,38770,38400,38771,38772); + +UPDATE `gameobject_template` SET `faction` = 114 WHERE `entry` IN (201377, 201378, 201376); +UPDATE `gameobject` SET `state` = 1 WHERE `id` = 201920; +UPDATE `gameobject` SET `state` = '0' WHERE `id` IN (201376); + +-- --------------- +-- Queen Lana'thel +-- --------------- + +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'mob_swarming_shadows' WHERE `entry` = 38163; +UPDATE `gameobject_template` SET `faction` = 0, `ScriptName` = 'go_frostwing_sigil' WHERE `entry` = 202181; + +-- Essence of the Blood Queen +DELETE FROM `spell_proc_event` WHERE entry IN (70871); +INSERT INTO `spell_proc_event` VALUES +(70871, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0); + +-- by default Pact of the Darkfallen is getting spell power coeff, so set it to 0 +DELETE FROM `spell_bonus_data` WHERE `entry` = 71341; +INSERT INTO `spell_bonus_data` VALUES +(71341, 0, 0, 0, 0, 'Pact of the Darkfallen (Lanathel)'); + +UPDATE `creature_model_info` SET `combat_reach` = 5 WHERE `modelid` = 31165; + +UPDATE `creature_model_info` SET `combat_reach` = 2 WHERE `modelid` = 31093; + +UPDATE `gameobject_template` SET `type`='0', `flags`='32', `faction`='114' WHERE `entry`=201755; + +-- --------------------- +-- Valithria dreamwalker +-- --------------------- +DELETE FROM `creature` WHERE `id` = 36789; -- Summon by script +UPDATE `creature_template` SET `ScriptName` = 'mob_valithria_combat_trigger', `ExtraFlags` = `ExtraFlags` &~2 WHERE `entry` = 38752; +UPDATE `creature` SET `phaseMask` = `phaseMask` | 16 WHERE `id` = 38752; -- phaseMask for Combat Trigger +UPDATE `creature_template` SET `UnitFlags` = `UnitFlags` &~ 33554432, `AIName` = '', `ScriptName` = 'mob_valithria_dream_phase' WHERE `entry` = 37950; -- Valithria in dream phase +REPLACE INTO `creature_template_addon` (`entry`, `emote`) VALUES +(37950, 453); -- flying state of dream Valithria +UPDATE `creature_template` SET `ScriptName` = 'mob_dream_portal_pre' WHERE `entry` = 38186; +UPDATE `creature_template` SET `IconName` = '', `NpcFlags` = `NpcFlags` | 1, `ScriptName` = 'mob_dream_portal' WHERE `entry` = 37945; +UPDATE `creature_template` SET `FactionAlliance` = 16, `FactionHorde` = 16, `ScriptName` = 'mob_dream_cloud', `AIName` = '', `ExtraFlags` = `ExtraFlags` &~128 WHERE `entry`= 37985; +UPDATE `creature_template` SET `ScriptName` = 'mob_nightmare_portal_pre' WHERE `entry` = 38429; +UPDATE `creature_template` SET `IconName` = '', `NpcFlags` = `NpcFlags` | 1, `ScriptName` = 'mob_nightmare_portal' WHERE `entry` = 38430; +UPDATE `creature_template` SET `FactionAlliance` = 16, `FactionHorde` = 16, `ScriptName` = 'mob_nightmare_cloud', `AIName` = '', `ExtraFlags` = `ExtraFlags` &~128 WHERE `entry` = 38421; +UPDATE `creature_template` SET `ScriptName` = 'mob_gluttonous_abomination', `AIName` = '' WHERE `entry` = 37886; +UPDATE `creature_template` SET `ScriptName` = 'mob_blistering_zombie', `AIName` = '' WHERE `entry` = 37934; +UPDATE `creature_template` SET `ScriptName` = 'mob_risen_archmage', `AIName` = '' WHERE `entry` = 37868; +UPDATE `creature_template` SET `ScriptName` = 'mob_blazing_skeleton', `AIName` = '', `MechanicImmuneMask` = `MechanicImmuneMask` | 2048 WHERE `entry` = 36791; +UPDATE `creature_template` SET `ScriptName` = 'mob_suppresser', `AIName` = '' WHERE `entry` = 37863; +UPDATE `creature_template` SET `MinLevel` = 82, `MaxLevel` = 82, `ScriptName`='mob_mana_void', `AIName`='', `ExtraFlags` = `ExtraFlags` &~128 WHERE `entry`= 38068; +UPDATE `creature_template` SET `ScriptName`='mob_column_of_frost', `AIName`='', `ExtraFlags` = `ExtraFlags` &~128 WHERE `entry`= 37918; + +DELETE FROM `spell_script_target` WHERE `entry` IN (71946, 72031, 72032, 72033); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(71946, 1, 37950), +(72031, 1, 37950), +(72032, 1, 37950), +(72033, 1, 37950); + +-- spawn Valithria in dream state +UPDATE `creature` SET `phaseMask` = 16, `position_x` = 4203.14, `position_y` = 2484.86, `position_z` = 386.485, `orientation` = 6.276 WHERE `id` = 37950; + +DELETE FROM `creature` WHERE `guid` = 47738 AND `id` = 38589; +DELETE FROM `pool_creature` WHERE `guid`=47738; + +UPDATE `gameobject_template` SET `faction` = 0 WHERE `entry` IN (201375, 201373); +UPDATE `gameobject_template` SET `faction` = 114 WHERE `entry` IN (201380, 201381, 201382, 201383); +UPDATE `gameobject_template` SET `faction` = '0' WHERE `entry` IN (201380,201381,201382,201383); + +UPDATE `gameobject_template` SET `faction` = 114 WHERE `entry` IN (201380, 201381, 201382, 201383); +UPDATE `gameobject_template` SET `flags` = 32 WHERE `entry` = 201919; + +UPDATE `creature_template_addon` SET `auras` = '' WHERE `entry` IN ('38131', '38132', '37134', '37132'); +UPDATE `creature_template_addon` SET `auras` = '71244' WHERE `entry`='38133'; + +-- remove unwanted right now dummy The Lich King spawn +DELETE FROM `creature` WHERE `guid` = 111453 AND `id` = 16980; + +-- ---------- +-- Sindragosa +-- ---------- +UPDATE `creature_template` SET `ScriptName`='mob_rimefang', `AIName`='' WHERE `entry`= 37533; +UPDATE `creature_template` SET `ScriptName`='mob_spinestalker', `AIName`='' WHERE `entry`= 37534; + +UPDATE `creature_template` SET `ScriptName`='mob_ice_tomb', `AIName`='' WHERE `entry`= 36980; +UPDATE `creature_template` SET `ScriptName`='mob_frost_bomb', `AIName`='' WHERE `entry`= 37186; + +-- ------------------------------- +-- frost bomb target from Lordronn +-- ------------------------------- + +-- --------- +-- Lich King +-- --------- + +UPDATE `creature_template_addon` SET `auras` = '73878 73220 72846' WHERE `entry` IN (39166, 39167, 39168); +UPDATE `creature_template` SET `SpeedWalk` = 1.0, `SpeedRun` = 1.1 WHERE `entry` IN (36597, 39166, 39167, 39168); +UPDATE `creature_template` SET `ScriptName` = 'boss_tirion_icc' WHERE `entry`= 38995; +-- UPDATE `creature_template` SET `ScriptName` = 'boss_terenas_menethil_icc' WHERE entry = 38579; + +UPDATE `creature_template` SET `ScriptName`='mob_ice_sphere_icc', `AIName`='' WHERE `entry`= 36633; +UPDATE `creature_template` SET `ScriptName`='mob_defiler_icc', `AIName`='' WHERE `entry`= 38757; +UPDATE `creature_template` SET `ScriptName`='mob_strangulate_vehicle', `AIName`='' WHERE `entry`= 36598; +UPDATE `creature_template` SET `ScriptName`='mob_vile_spirit', `AIName`='' WHERE `entry` IN (37799, 39190); +UPDATE `creature_template` SET `SpeedWalk` = 1.8, `SpeedRun` = 1.1 WHERE `entry` IN (37799, 39284, 39285, 39286); +UPDATE `creature_template` SET `ScriptName`='mob_raging_spirit', `AIName`='' WHERE `entry`= 36701; +UPDATE `creature_template` SET `ScriptName`='mob_drudge_ghoul', `AIName`='' WHERE `entry`= 37695; +UPDATE `creature_template` SET `ScriptName`='mob_shambling_horror', `AIName`='' WHERE `entry`= 37698; +UPDATE `creature_template` SET `ScriptName`='mob_shadow_trap', `AIName`='', `FactionAlliance` = 14, `FactionHorde` = 14, `UnitFlags` = `UnitFlags` | 2 | 33554432 WHERE `entry`= 39137; +UPDATE `creature_template` SET `ScriptName`='mob_valkyr_shadowguard', `AIName`='' WHERE `entry`= 36609; +UPDATE `creature_template` SET `ScriptName`='npc_terenas_fm', `AIName`='' WHERE `entry`= 36823; -- normal +UPDATE `creature_template` SET `ScriptName`='npc_terenas_fm', `AIName`='' WHERE `entry`= 39217; -- heroic, different entry +UPDATE `creature_template` SET `ScriptName`='mob_spirit_warden', `AIName`='' WHERE `entry`= 36824; +UPDATE `creature_template` SET `ScriptName`='mob_spirit_bomb', `AIName`='', MinLevel = 83, MaxLevel = 83, `UnitFlags` = `UnitFlags` | 33554432, `FactionAlliance` = 14, `FactionHorde` = 14 WHERE `entry`= 39189; + +-- speed of Wicked Spirits +UPDATE `creature_template` SET `SpeedWalk` = 0.9, `SpeedRun` = 0.9 WHERE `entry` IN (39190, 39287, 39288, 39289); + +-- damage of Terenas and Spirit Warden, they should be hitting each other for around 10-11k normal melee damage +UPDATE `creature_template` SET `DamageMultiplier` = 46 WHERE `entry` IN (36823, 36824, 39296); + +-- make Ice Spheres untauntable +UPDATE `creature_template` SET `MechanicImmuneMask` = `MechanicImmuneMask` | 256 WHERE `entry` IN (36633, 39305, 39306, 39307); + +DELETE FROM `spell_script_target` WHERE `entry` IN (71614, 74074, 73028, 74321, 74322, 74323, 72679, 74318, 74319, 74320); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(71614, 1, 38995), +(74074, 1, 36597), +(73028, 1, 36597), -- Harvested Soul +(74321, 1, 36597), +(74322, 1, 36597), +(74323, 1, 36597), +(72679, 1, 36597), +(74318, 1, 36597), +(74319, 1, 36597), +(74320, 1, 36597); + +-- proc for Dark Hunger +DELETE FROM `spell_proc_event` WHERE `entry` = 69383; +INSERT INTO `spell_proc_event` (`entry`, `procFlags`) VALUES +(69383, 0x04 | 0x10 | 0x10000); + +-- fix stats for some creatures +-- Raging Spirit +UPDATE `creature_template` SET `MinLevelHealth` = 885400, `MaxLevelHealth` = 885400 WHERE `entry` = 36701; -- 10normal +UPDATE `creature_template` SET `MinLevelHealth` = 2650000, `MaxLevelHealth` = 2650000 WHERE `entry` = 39302; -- 25normal +UPDATE `creature_template` SET `MinLevelHealth` = 1230000, `MaxLevelHealth` = 1230000 WHERE `entry` = 39303; -- 10hero +UPDATE `creature_template` SET `MinLevelHealth` = 4150000, `MaxLevelHealth` = 4150000 WHERE `entry` = 39304; -- 25hero + +-- Ice Sphere +UPDATE `creature_template` SET `MinLevelHealth` = 6000, `MaxLevelHealth` = 6000 WHERE `entry` = 36633; -- 10normal +UPDATE `creature_template` SET `MinLevelHealth` = 15200, `MaxLevelHealth` = 15200 WHERE `entry` = 39305; -- 25normal +UPDATE `creature_template` SET `MinLevelHealth` = 15200, `MaxLevelHealth` = 15200 WHERE `entry` = 39306; -- 10hero +UPDATE `creature_template` SET `MinLevelHealth` = 53200, `MaxLevelHealth` = 53200 WHERE `entry` = 39307; -- 25hero + +-- ----------------- +-- EAI YTDB CLEAN UP +-- ----------------- +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=37973); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=37972); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=37970); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=38004); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=38112); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=37813); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=36627); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=36723); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=36789); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=36612); +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=36855); + +-- ----------------------------------------------------------------------------------------------- +-- Instance Fixes -------------------------------------------------------------------------------- +-- ----------------------------------------------------------------------------------------------- + +-- The Following had the auras ' permanet Fegien death, be undead and some other retarded aura +UPDATE `creature_template_addon` SET `auras` = '' WHERE `entry` IN (37122, 37123, 37124, 37125, 37132, 37133, 37134); +-- end of weird addon fix + +-- DELETE FROM `creature` WHERE `id`=37950; + +-- ------ + +-- ICC Achievements criterias -- +REPLACE INTO `achievement_criteria_requirement` VALUES(12777,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(13079,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(13080,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(13081,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12776,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12995,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12997,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12998,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12778,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(13035,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(13036,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(13037,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12971,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12978,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12979,18,0,0); +REPLACE INTO `achievement_criteria_requirement` VALUES(12980,18,0,0); +DELETE FROM `achievement_criteria_requirement` WHERE criteria_id IN (12780, 13011, 13012, 13013); +INSERT INTO `achievement_criteria_requirement` VALUES(12780,0,0,0),(13011,0,0,0),(13012,0,0,0),(13013,0,0,0); diff --git a/sql_mr/mr00473_mangos_wintergrasp.sql b/sql_mr/mr00473_mangos_wintergrasp.sql new file mode 100644 index 0000000000..b6733bcfd0 --- /dev/null +++ b/sql_mr/mr00473_mangos_wintergrasp.sql @@ -0,0 +1,3 @@ +-- Wintergrasp +UPDATE gameobject_template SET ScriptName='go_wg_teleport' WHERE entry = 190763; +UPDATE creature_template SET `ScriptName`='npc_wg_demolisher_engineer' WHERE `entry` IN (30499,30400); diff --git a/sql_mr/mr00489_mangos_quests_scripts.sql b/sql_mr/mr00489_mangos_quests_scripts.sql new file mode 100644 index 0000000000..b979490ead --- /dev/null +++ b/sql_mr/mr00489_mangos_quests_scripts.sql @@ -0,0 +1,548 @@ +-- ---------------------- +-- QUEST && Ect Support - +-- ---------------------- +-- temp fix need to find true fix +-- help fix quest 12813 currently +-- insert been commented out til i figure out how to handle this guy in this area he shouldn't be here like this or in this form or something +DELETE FROM `creature` WHERE `id` = 29560; +-- INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +-- (88692, 29560, 571, 1, 1, 0, 0, 7458.74, 4846.24, 54.1606, 0.0676441, 300, 0, 0, 63000, 19970, 0, 0); + + +-- ---------------------------------------------------------------- +-- Start of Quest and related data and fixes ---------------------- +-- ---------------------------------------------------------------- + + +-- ------------- +-- Quest 11560 - +-- ------------- +UPDATE `gameobject_template` SET `data2` = 11560 WHERE `entry` = 187373; +UPDATE `creature_template` SET `ScriptName` = "npc_tadpole" WHERE `entry` = 25201; +DELETE FROM `scripted_event_id` WHERE `id` = 11560; +INSERT INTO `scripted_event_id` (`id`,`ScriptName`) VALUES +(11560, "go_tadpole_cage"); + +-- -------------- +-- Quest 12240 - +-- -------------- +UPDATE `creature_template` SET `ModelId1` = 17612 WHERE `entry` = 27353; +DELETE FROM `creature` WHERE `id` = 27238; +UPDATE `creature_template` SET `Armor` = 7618, `FactionAlliance` = 67, `FactionHorde` = 67 WHERE `entry` = 27238; + +-- ------------- +-- Quest 14104 - +-- ------------- +DELETE FROM `dbscripts_on_event` WHERE `id` = 22030; +INSERT INTO `dbscripts_on_event` (`id`,`delay`,`command`,`datalong`,`datalong2`,`x`,`y`,`z`,`o`,`comments`) VALUES +(22030,3,10,35012,300000,10006.4,650.6,10.34,4.542,""); + +-- ------------ +-- Quest 9164 - +-- ------------ +UPDATE `creature` SET `MovementType` = 0 WHERE `id` IN (16206, 16208, 16209); -- in YTDB is 2 + +-- --- +-- -Quest 8468 +-- --- +-- Thaelis has wrong faction was gettting killed by his own kind 8P +UPDATE `creature_template` SET `FactionAlliance` = 16, `FactionHorde` = 16 WHERE `entry` = 15949; + +-- ------------ +-- Quest 13828, 13829, 13835, 13838, 13837, 13839, 13625, 13677 +-- ------------ +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_melee_target' WHERE `entry` = 33229; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_ranged_target' WHERE `entry` = 33243; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_charge_target' WHERE `entry` = 33272; + +-- ------------ +-- Quest 13663 +-- ------------ +UPDATE creature_template SET `AIName` = '', `ScriptName` = 'npc_black_knights_gryphon' WHERE `entry` = 33519; +UPDATE creature_template SET VehicleTemplateId = 402 WHERE entry = 33519; -- vehicle_id can be 88 107 108 112 143 etc. +UPDATE creature_template SET KillCredit1 = 38595 WHERE entry = 33448; + +-- ------------------ +-- Quests 13665, 13745, 13750, 13756, 13761, 13767, 13772, 13777, 13782, 13787, 13790, 13793, 13811, 13814 +-- ------------------ +-- dk fix + +UPDATE quest_template SET RequiredClasses = 0 WHERE entry = 13794; +UPDATE quest_template SET PrevQuestId = 13794, ExclusiveGroup = 0 WHERE entry = 13795; + +-- it is also necessary (otherwise spell=63010 do not work) +UPDATE creature_template SET UnitFlags = 8 WHERE entry IN (33217,33316,33317,33318,33319,33320,33321,33322,33323,33324); + +-- The Valiant's Challenge (10 quests) +UPDATE `creature_template` SET `KillCredit1` = 33708 WHERE `entry` = 33707; +UPDATE `creature_template_addon` SET `b2_0_sheath` = 0 WHERE `entry` = 33707; +-- UPDATE `dbscripts_on_gossip` SET datalong = 33707 WHERE id IN (33518,50102); -- Not found in YTDB + +-- Among the Champions (4 quests) (may do not need) +DELETE FROM `dbscripts_on_gossip` WHERE id IN (10453,10454,10455,10456,10457,10458,10459,10460,10461,10462); +/* +DELETE FROM gossip_menu_option WHERE menu_id IN (10453,10454,10455,10456,10457,10458,10459,10460,10461,10462); +INSERT INTO `gossip_menu_option`(`menu_id`,`id`,`option_icon`,`option_text`,`option_id`,`npc_option_npcflag`, +`action_menu_id`,`action_poi_id`,`action_script_id`,`box_coded`,`box_money`,`box_text`) VALUES +(10453,0,0,'I am ready to fight!',1,1,-1,0,10453,0,0,NULL ,1,62853,0,6,469,0,0,0,0), +(10454,0,0,'I am ready to fight!',1,1,-1,0,10454,0,0,NULL ,1,62853,0,6,469,0,0,0,0), +(10455,0,0,'I am ready to fight!',1,1,-1,0,10455,0,0,NULL ,1,62853,0,6,469,0,0,0,0), +(10456,0,0,'I am ready to fight!',1,1,-1,0,10456,0,0,NULL ,1,62853,0,6,469,0,0,0,0), +(10457,0,0,'I am ready to fight!',1,1,-1,0,10457,0,0,NULL ,1,62853,0,6,67,0,0,0,0), +(10458,0,0,'I am ready to fight!',1,1,-1,0,10458,0,0,NULL ,1,62853,0,6,67,0,0,0,0), +(10459,0,0,'I am ready to fight!',1,1,-1,0,10459,0,0,NULL ,1,62853,0,6,67,0,0,0,0), +(10460,0,0,'I am ready to fight!',1,1,-1,0,10460,0,0,NULL ,1,62853,0,6,469,0,0,0,0), +(10461,0,0,'I am ready to fight!',1,1,-1,0,10461,0,0,NULL ,1,62853,0,6,67,0,0,0,0), +(10462,0,0,'I am ready to fight!',1,1,-1,0,10462,0,0,NULL ,1,62853,0,6,67,0,0,0,0); +*/ +INSERT INTO `dbscripts_on_gossip`(`id`,`delay`,`command`,`datalong`,`datalong2`,`buddy_entry`,`search_radius`, `data_flags`,`dataint`,`dataint2`,`dataint3`,`dataint4`,`x`,`y`,`z`,`o`,`comments`) VALUES +(10453,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10453,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10454,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10454,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10455,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10455,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10456,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10456,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10457,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10457,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10458,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10458,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10459,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10459,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10460,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10460,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10461,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10461,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''), +(10462,1,22,14,2,0,0,4,0,0,0,0,0,0,0,0,''), +(10462,0,0,0,0,0,0,4,2000000449,2000000450,2000000451,0,0,0,0,0,''); + +UPDATE `dbscripts_on_gossip` SET buddy_entry = 0, search_radius = 0, data_flags = 4 WHERE command = 22 AND id IN (10469,10468,10470,10472,10473,10466,10464,10471,10465,10467); + +-- valiants +UPDATE creature_template SET UnitFlags = 0, AIName = '', ScriptName = 'npc_valiants' WHERE entry IN (33285,33306,33382,33383,33384,33558,33559,33561,33562,33564); + +-- Champions +UPDATE creature_template SET ScriptName = 'npc_champions', AIName = '' WHERE entry IN +(33738,33739,33740,33743,33744,33745,33746,33747,33748,33749); + +DELETE FROM `creature_spell` WHERE `guid` IN (33217,33316,33317,33318,33319,33320,33321,33322,33323,33324); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(33217, 63010, 0, 0, 0, 0), +(33217, 64342, 1, 0, 0, 0), +(33316, 63010, 0, 0, 0, 0), +(33316, 64342, 1, 0, 0, 0), +(33316, 63034, 6, 0, 0, 0), +(33317, 63010, 0, 0, 0, 0), +(33317, 64342, 1, 0, 0, 0), +(33317, 63034, 6, 0, 0, 0), +(33318, 63010, 0, 0, 0, 0), +(33318, 64342, 1, 0, 0, 0), +(33318, 63034, 6, 0, 0, 0), +(33319, 63010, 0, 0, 0, 0), +(33319, 64342, 1, 0, 0, 0), +(33319, 63034, 6, 0, 0, 0), +(33320, 63010, 0, 0, 0, 0), +(33320, 64342, 1, 0, 0, 0), +(33320, 63034, 6, 0, 0, 0), +(33321, 63010, 0, 0, 0, 0), +(33321, 64342, 1, 0, 0, 0), +(33321, 63034, 6, 0, 0, 0), +(33322, 63010, 0, 0, 0, 0), +(33322, 64342, 1, 0, 0, 0), +(33322, 63034, 6, 0, 0, 0), +(33323, 63010, 0, 0, 0, 0), +(33323, 64342, 1, 0, 0, 0), +(33323, 63034, 6, 0, 0, 0), +(33324, 63010, 0, 0, 0, 0), +(33324, 64342, 1, 0, 0, 0), +(33324, 63034, 6, 0, 0, 0); + + +-- ------------------ +-- Quest 12065/12066 +-- ------------------ +-- Just a side note i dont think the mobs are correctly spawned/Placed around this area need to research or get someone to screen shot in live + +-- Added Quest credit +DELETE FROM `creature_ai_scripts` WHERE (`id`='2677351'); +INSERT INTO `creature_ai_scripts` VALUES ('2677351', '26773', '8', '0', '100', '1', '50546', '-1', '1000', '1000', '11', '47390', '6', '6', '33', '26773', '6', '0', '0', '0', '0', '0', 'ytdb/R2'); +-- npc 26773 -- not selectable -- kill bunny credit +UPDATE `creature_template` SET `UnitFlags` = 33554688 WHERE `entry` = 26773; + +-- ------------------ +-- Quest 12860/12927- +-- ------------------ + +-- correct target and take quest item away when quest is done and remove uneeded reqspellcast +UPDATE `quest_template` SET `ReqSourceId1` = 41179, `ReqSourceCount1` = 1, `ReqCreatureOrGOId1` = 29746 WHERE `entry` = 12860; + +-- correct target and take quest item away when quest is done and remove uneeded reqspellcast +UPDATE `quest_template` SET `ReqSourceId1` = 41179, `ReqSourceCount1` = 1, `ReqCreatureOrGOId1` = 29746 WHERE `entry` = 12927; + +-- --------------- +-- Quest 12813 --- +-- --------------- + +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 29329; +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 29330; +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 29333; +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 29338; + +-- fixed spawn of onslaught harbor guards +INSERT IGNORE INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600153, 29330, 571, 1, 1, 0, 989, 7459.84, 4851.9, 54.1595, 0.00143623, 600, 0, 0, 12600, 0, 0, 0), +(600154, 29330, 571, 1, 1, 0, 989, 7459.58, 4840.95, 54.1595, 0.0367786, 600, 0, 0, 12387, 0, 0, 0); + +-- ACID scripts (ytdb and R2 acid combined 8P ) and related fixes + +-- Still needs texts if any +-- Timers could use adjusting + +-- onslaught Paladin +UPDATE `creature_template` SET `MaxLevelMana` = 7988 WHERE `entry` = 29329; +DELETE FROM `creature_ai_scripts` WHERE `id` = 2932951; -- not found in YTDB and ScriptName = spell_dummy_npc in creature_template (cause disabling) +INSERT INTO `creature_ai_scripts` VALUES ('2932951', '29329', '8', '0', '100', '0', '52741', '-1', '0', '0', '11', '54415', '0', '22', '33', '29398', '6', '0', '41', '0', '0', '0', 'ytdb-q12813'); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2932952'); +INSERT INTO `creature_ai_scripts` VALUES ('2932952', '29329', '0', '0', '100', '0', '4000', '6000', '10000', '14000', '11', '19131', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast shield charge'); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2932953'); +INSERT INTO `creature_ai_scripts` VALUES ('2932953', '29329', '0', '0', '100', '0', '7000', '9000', '13000', '16000', '11', '32774', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast Avengers shield'); + +-- onslaught gryphon rider +UPDATE `creature_template_spells` SET `spell2` = 40652, `spell3` = 0 WHERE `entry` = 29333; -- removed incorrect and dupe throw spear spell +UPDATE `creature_template` SET `MaxLevelMana` = 7988, `MaxLevelHealth` = 12600 WHERE `entry` = 29333; +DELETE FROM `creature_ai_scripts` WHERE (`id`='2933351'); +INSERT INTO `creature_ai_scripts` VALUES ('2933351', '29333', '8', '0', '100', '0', '52741', '-1', '0', '0', '11', '54415', '0', '22', '33', '29398', '6', '0', '41', '0', '0', '0', 'ytdb_q12813'); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2933352'); +INSERT INTO `creature_ai_scripts` VALUES ('2933352', '29333', '9', '0', '100', '0', '10', '40', '5000', '7000', '11', '54617', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast throw spear '); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2933353'); +INSERT INTO `creature_ai_scripts` VALUES ('2933353', '29333', '9', '0', '100', '0', '1', '5', '5000', '7000', '11', '40652', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast wing clip'); + +-- onslaught harbor guard +DELETE FROM `creature_ai_scripts` WHERE `id` = 2933051; -- not found in YTDB and ScriptName = spell_dummy_npc in creature_template (cause disabling) +INSERT INTO `creature_ai_scripts` VALUES ('2933051', '29330', '8', '0', '100', '0', '52741', '-1', '0', '0', '11', '54415', '0', '22', '33', '29398', '6', '0', '41', '0', '0', '0', 'ytdb-q12813'); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2933052'); +INSERT INTO `creature_ai_scripts` VALUES ('2933052', '29330', '9', '0', '100', '0', '5', '30', '5000', '6000', '11', '6660', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast shoot'); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2933053'); +INSERT INTO `creature_ai_scripts` VALUES ('2933053', '29330', '9', '0', '100', '0', '5', '30', '7000', '8000', '11', '18802', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast frost shoot'); + +-- just some area related fixes + +-- onslauhgt raven bishop +UPDATE `creature_template` SET `MaxLevelMana` = 17628 WHERE `entry` = 29338; +DELETE FROM `creature_ai_scripts` WHERE `id` = 2933801; -- not found in YTDB and ScriptName = spell_dummy_npc and AIName = '' in creature_template (cause disabling) +INSERT INTO `creature_ai_scripts` VALUES ('2933801', '29338', '0', '0', '100', '0', '6000', '7500', '8000', '10000', '11', '50740', '1', '4', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast raven flock'); +DELETE FROM `creature_ai_scripts` WHERE (`id`='2933802'); +INSERT INTO `creature_ai_scripts` VALUES ('2933802', '29338', '2', '0', '100', '0', '40', '30', '20', '40', '11', '50750', '0', '21', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - cast raven heal'); +-- need to implent blessing of the light need to do more research on this spell -- server side script effevt + +-- onslaught darkweaver +UPDATE `creature_template` SET `MaxLevelMana` = 35256 WHERE `entry` = 29614; + +-- --------------- +-- Quest 14107 --- +-- --------------- + +-- still needs support to grip of scourge server side effect and immue to the spell for quest + +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_fallen_hero_spirit' WHERE `entry` = 32149; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_scourge_conventor' WHERE `entry` = 32257; + +UPDATE `gameobject_template` SET `castBarCaption` = 'Discarded Soul Crytal' WHERE `entry` = 195344; +UPDATE `creature_template` SET `KillCredit1` = 35055 WHERE `entry` = 32149; -- set fallen proxy +UPDATE `creature_template` SET `FactionAlliance` = 7, `FactionHorde` = 7 WHERE `entry` = 32149; -- Fallens arent suppose to attack unless attacked +UPDATE `creature_template` SET `MaxLevelMana` = 7786 WHERE `entry` = 32149; -- updated fallen mana to 3.3.5 standard +UPDATE `creature_template` SET `MaxLevelMana` = 7988 WHERE `entry` = 32257; -- updated scourgeconv mob mana to 3.3.5 +UPDATE `creature_template` SET `ModelId1` = 27651, `ModelId2` = 27651, `ModelId3` = 27651 WHERE `entry` = 32257; -- conventors are skeletons +-- --------------------- +-- Quest::14111--------- +-- --------------------- +UPDATE `quest_template` SET `RewSpell` = 0, `RewSpellCast` = 0 WHERE `entry` = 14111; + +-- ---------------------------------------- +-- Quest 12470 ---------------------------- +-- ---------------------------------------- +UPDATE creature_template SET ScriptName='npc_hourglass', AIName = '' WHERE entry=27840; +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 27840; +UPDATE `creature_template` SET `UnitFlags` = 516, `DynamicFlags` = 8 WHERE `entry` = 27840; -- added root, disable movement, passive + +-- spawn more sands (really should be able to use the whole area) +INSERT IGNORE INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(600006, 300209, 571, 1, 1, 4102.71, -444.36, 124.134, 1.774, 0, 0, 0.775178, 0.631742, -300, 0, 1), +(600007, 300209, 571, 1, 1, 4076.75, -441.368, 120.635, 0.995666, 0, 0, 0.477523, 0.878619, -300, 0, 1), +(600008, 300209, 571, 1, 1, 4070.94, -418.43, 120.234, 6.23349, 0, 0, 0.0248472, -0.999691, -300, 0, 1), +(600009, 300209, 571, 1, 1, 4128.17, -436.042, 125.947, 3.17357, 0, 0, 0.999872, -0.0159903, -300, 0, 1), +(600010, 300209, 571, 1, 1, 4145.28, -419.433, 124.344, 3.38956, 0, 0, 0.992324, -0.123666, -300, 0, 1), +(600011, 300209, 571, 1, 1, 4150.45, -390.681, 120.723, 3.66602, 0, 0, 0.965819, -0.259218, -300, 0, 1), +(600012, 300209, 571, 1, 1, 4126.18, -391.728, 119.142, 5.33813, 0, 0, 0.455137, -0.890421, -300, 0, 1); +-- ---------------------------------------- +-- Bury Those Cockroaches Quest 11608 ----- +-- ---------------------------------------- + +UPDATE creature_template SET ScriptName='npc_seaforium_depth_charge' WHERE entry=25401; + +-- ---------------------------------------- +-- Quest 11466 fixes and improvements ----- +-- ---------------------------------------- + +DELETE FROM creature_addon WHERE guid = 115895; +INSERT INTO creature_addon (guid,mount,bytes1,b2_0_sheath,b2_1_pvp_state,emote) VALUES +(115895,0,0,0,0,10); + +UPDATE creature_template SET ScriptName = 'npc_olga', AIName = '' WHERE entry = 24639; +UPDATE creature_template SET ScriptName = 'npc_jack_adams', AIName = '' WHERE entry = 24788; + +-- ------------------------- +-- -Quest:: 11656 ---------- +-- ------------------------- +-- better support + +DELETE FROM `creature_ai_scripts` WHERE (`id`='2551051'); +INSERT INTO `creature_ai_scripts` VALUES ('2551051', '25510', '8', '0', '100', '1', '45692', '-1', '0', '0', '33', '25510', '6', '0', '11', '64561', '0', '22', '41', '240000', '0', '0', 'ytdb-q11656'); + +DELETE FROM `creature_ai_scripts` WHERE (`id`='2551151'); +INSERT INTO `creature_ai_scripts` VALUES ('2551151', '25511', '8', '0', '100', '1', '45692', '-1', '0', '0', '33', '25511', '6', '0', '11', '64561', '0', '22', '41', '240000', '0', '0', 'ytdb-q11656'); + +DELETE FROM `creature_ai_scripts` WHERE (`id`='2551251'); +INSERT INTO `creature_ai_scripts` VALUES ('2551251', '25512', '8', '0', '100', '1', '45692', '-1', '0', '0', '33', '25512', '6', '0', '11', '64561', '0', '22', '41', '240000', '0', '0', 'ytdb-q11656'); + +DELETE FROM `creature_ai_scripts` WHERE (`id`='2551351'); +INSERT INTO `creature_ai_scripts` VALUES ('2551351', '25513', '8', '0', '100', '1', '45692', '-1', '0', '0', '33', '25513', '6', '0', '11', '64561', '0', '22', '41', '240000', '0', '0', 'ytdb-q11656'); + +-- ------------------------- +-- Quest :: 12644 +-- ------------------------- + +UPDATE creature_template SET ScriptName='npc_tipsy_mcmanus' WHERE entry=28566; + +UPDATE `creature_template` SET `MinLevelHealth` = 0, `MaxLevelHealth` = 1 WHERE `entry` = 28537; + +DELETE from spell_script_target WHERE entry in(51932,51931,51933); +INSERT into `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(51932, 1, 28537), +(51931, 1, 28537), +(51933, 1, 28537); + +UPDATE creature_template SET ExtraFlags = ExtraFlags |128 WHERE entry=28537; + +-- ------------------------- +-- Quest :: 12645 +-- ------------------------- + +UPDATE item_template SET ScriptName = 'item_jungle_punch_sample' WHERE entry = 38697; +UPDATE creature_template SET ScriptName = 'mob_taste_test' WHERE entry IN (28047,28568,27986); + +-- ------------------------- +-- quest 11542/11543 +-- ------------------------- + +UPDATE `creature_template` SET `Scale` = 4, `ModelId1` = 11686, `ModelId2` = 11686 WHERE `entry` IN (25090, 25091, 25092); + +-- Kill credits +INSERT IGNORE INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600127, 25090, 530, 1, 1, 0, 0, 13252.6, -7054.9, 22.4681, 3.5688, 25, 0, 0, 1, 0, 0, 0), +(600128, 25090, 530, 1, 1, 0, 0, 13229.6, -7052.88, 4.3433, 2.60276, 25, 0, 0, 1, 0, 0, 0), +(600129, 25090, 530, 1, 1, 0, 0, 13213.4, -7053.09, 18.7827, 1.69955, 25, 0, 0, 1, 0, 0, 0), +(600130, 25090, 530, 1, 1, 0, 0, 13226.3, -7052.35, 17.7073, 2.66795, 25, 0, 0, 1, 0, 0, 0), +(600131, 25090, 530, 1, 1, 0, 0, 13256.7, -7056.42, 23.4799, 6.09779, 25, 0, 0, 1, 0, 0, 0), +(600132, 25090, 530, 1, 1, 0, 0, 13241, -7054.83, 19.4747, 3.12191, 25, 0, 0, 1, 0, 0, 0), +(600133, 25090, 530, 1, 1, 0, 0, 13272, -7058.13, 27.1397, 2.9664, 25, 0, 0, 1, 0, 0, 0); + +INSERT IGNORE INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600134, 25091, 530, 1, 1, 0, 0, 13328.7, -6993.48, 11.8975, 1.60531, 25, 0, 0, 1, 0, 0, 0), +(600135, 25091, 530, 1, 1, 0, 0, 13346, -6993.5, 3.21209, 1.40346, 25, 0, 0, 1, 0, 0, 0), +(600136, 25091, 530, 1, 1, 0, 0, 13323, -6989.96, 18.1137, 5.29668, 25, 0, 0, 1, 0, 0, 0), +(600137, 25091, 530, 1, 1, 0, 0, 13309.5, -6987.26, 16.2246, 4.39818, 25, 0, 0, 1, 0, 0, 0), +(600138, 25091, 530, 1, 1, 0, 0, 13354.3, -6990.59, 19.2655, 1.4121, 25, 0, 0, 1, 0, 0, 0), +(600139, 25091, 530, 1, 1, 0, 0, 13360.6, -6991.35, 20.7843, 6.2588, 25, 0, 0, 1, 0, 0, 0), +(600140, 25091, 530, 1, 1, 0, 0, 13339.9, -6989.69, 17.719, 6.27843, 25, 0, 0, 1, 0, 0, 0), +(600141, 25091, 530, 1, 1, 0, 0, 13379.1, -6991.55, 25.1392, 3.19418, 25, 0, 0, 1, 0, 0, 0), +(600142, 25091, 530, 1, 1, 0, 0, 13328.7, -6993.48, 11.8975, 1.60531, 25, 0, 0, 1, 0, 0, 0); + +INSERT IGNORE INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(600143, 25092, 530, 1, 1, 0, 0, 13261.8, -7144.76, 29.6207, 3.73767, 25, 0, 0, 1, 0, 0, 0), +(600144, 25092, 530, 1, 1, 0, 0, 13313.5, -7149.11, 23.029, 0.326681, 25, 0, 0, 1, 0, 0, 0), +(600145, 25092, 530, 1, 1, 0, 0, 13263.9, -7144.98, 18.0722, 2.95227, 25, 0, 0, 1, 0, 0, 0), +(600146, 25092, 530, 1, 1, 0, 0, 13271.3, -7146.79, 19.1243, 5.98391, 25, 0, 0, 1, 0, 0, 0), +(600147, 25092, 530, 1, 1, 0, 0, 13289.9, -7151.84, 20.5758, 2.77005, 25, 0, 0, 1, 0, 0, 0), +(600148, 25092, 530, 1, 1, 0, 0, 13300.4, -7149.66, 3.98094, 1.67521, 25, 0, 0, 1, 0, 0, 0), +(600149, 25092, 530, 1, 1, 0, 0, 13305.6, -7147.99, 19.165, 2.99467, 25, 0, 0, 1, 0, 0, 0), +(600150, 25092, 530, 1, 1, 0, 0, 13331.7, -7150.1, 25.3583, 3.09835, 25, 0, 0, 1, 0, 0, 0), +(600151, 25092, 530, 1, 1, 0, 0, 13348.8, -7151.36, 29.4228, 3.06536, 25, 0, 0, 1, 0, 0, 0); + +-- EventAI -- one additional has been made to YTDB acid a despawn so quest graphics and effects reset for next player at the moment its 2 mins to despawn and 30 secs to respawn (credit triggers are invis) quest might take longer then 2 mins +DELETE FROM `creature_ai_scripts` WHERE `id` IN ('2509051', '2509151', '2509251'); +INSERT INTO `creature_ai_scripts` VALUES +('2509051', '25090', '8', '0', '100', '1', '45115', '-1', '0', '0', '33', '25090', '6', '0', '11', '73119', '0', '22', '41', '120000', '0', '0', 'ytdb-q11542,11543&R2'), +('2509151', '25091', '8', '0', '100', '1', '45115', '-1', '0', '0', '33', '25091', '6', '0', '11', '73119', '0', '22', '41', '120000', '0', '0', 'ytdb-q11542,11543&R2'), +('2509251', '25092', '8', '0', '100', '1', '45115', '-1', '0', '0', '33', '25092', '6', '0', '11', '73119', '0', '22', '41', '120000', '0', '0', 'ytdb-q11542,11543&R2'); + +UPDATE creature_template SET AIName = 'EventAI' WHERE entry = 25090; +UPDATE creature_template SET AIName = 'EventAI' WHERE entry = 25091; +UPDATE creature_template SET AIName = 'EventAI' WHERE entry = 25092; + +-- ------------------------- +-- fix quest toxic_test 9051 -- still not working is kill credit +-- ------------------------- +UPDATE `quest_template` SET `ReqCreatureOrGOId1` = 6498, `ReqCreatureOrGOCount1` = 1 WHERE `entry` = 9051; -- fixes spell credit +UPDATE `quest_template` SET `ReqSourceId1` = 22432, `ReqSourceCount1` = 1 WHERE `entry` = 9051; -- take item out of player inventory upon completetion + +-- ------------------------------ +-- Quest: Drake Hunt (11940/11919) +-- ------------------------------ +UPDATE `creature_template` SET ScriptName='npc_nexus_drake', AIName='' WHERE entry = 26127; + +-- ------------------------------- +-- Quest: Merciful Freedom (11676) +-- ------------------------------- +UPDATE gameobject_template SET ScriptName='go_scourge_cage' WHERE entry IN (187854,187855,187856,187857,187858,187859,187860,187862,187863,187864,187865,187866,187867,187868,187870,187871,187872,187873,187874,187861,190803); + +-- ------------------------ +-- Quest: Abduction (11590) +-- ------------------------ + +UPDATE `creature_template` SET MinLevelHealth = 6387, MaxLevelMana = 7185, MinLevel = 64, MaxLevel = 70, MinLevelMana = 7031, MaxLevelMana = 7196 WHERE entry = 25474; +UPDATE `creature_template` SET `ScriptName`='npc_beryl_sorcerer' , AIName='' WHERE entry=25316; + +-- --------------------------------------------------- +-- Mob support for Quest: Powering Our Defenses (8490) +-- --------------------------------------------------- +-- Enraged Wraith +UPDATE `creature_template` SET AIName='EventAI', ExtraFlags = ExtraFlags | 64 WHERE entry=17086; + +DELETE FROM `creature_ai_scripts` WHERE creature_id = 17086; +INSERT INTO `creature_ai_scripts` VALUES +(1708601,17086,2,0,100,0,25,0,0,0,11,8599,0,1,1,-106,0,0,0,0,0,0,'R2 - Enraged Wraith - Cast Enrage on 50% HP'); + +-- --------------- +-- Gamel the Cruel +-- --------------- +UPDATE creature SET spawntimesecs = 30 WHERE id = 26449; + +UPDATE creature_template SET AIName = 'EventAI', DamageMultiplier = 2 WHERE entry = 26449; +DELETE FROM creature_ai_scripts WHERE creature_id = 26449; +INSERT INTO creature_ai_scripts VALUES +(2644901, 26449, 0,0,80,1, 2000,2000,5000,5000, 11,19643,1,0, 0,0,0,0, 0,0,0,0,'R2 - Gamel the Cruel - mortal strike'); + +-- -------------------------------------------------- +-- fixes for Quest Kickin'Nass and Takin manes (12630) +-- -------------------------------------------------- +UPDATE `creature_template` SET `ExtraFlags` = 64 WHERE `entry` = 28523; +DELETE FROM creature WHERE id=28523; -- deletes nass kc bunny credit needs to be summoned not already spawn + +-- ----------------------------- +-- Quest Fixes to Hard_to_sallow +-- ----------------------------- +DELETE FROM `creature_ai_scripts` WHERE (`id`='2629302'); +INSERT INTO `creature_ai_scripts` VALUES ('2629302', '26293', '2', '0', '100', '0', '70', '50', '0', '0', '1', '-262930', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'R2 - Hulking Jormungar - emote between 70% and 50% '); + +DELETE FROM `creature_ai_texts` WHERE entry IN ('-262930'); +INSERT INTO `creature_ai_texts` (`entry`, `content_default`, `sound`, `type`, `language`, `emote`, `comment`) VALUES +('-262930', 'The Hulking Jormungar falters for a moment, opening its mouth wide.', '3', '0', '0', '0', 'R2 - Hulking Jormungar-raid emote'); + +-- ------------------------------------------ +-- Support for quest The Denouncement (12273) +-- ------------------------------------------ + +-- Texts +DELETE FROM creature_ai_texts WHERE entry IN (-272371,-272351,-272341,-272361); +INSERT INTO creature_ai_texts (`entry`, `content_default`, `sound`, `type`, `language`, `emote`, `comment`) VALUES +(-272371,'High general Abbendis personally told me that it was a mistake to come north and that we\'re doomed! I urge you all to lay down your weapons and leave before it\'s too late!',0,1,0,0,'R2 - Commander Jordan yell'), +(-272351,'Renounce the Scarlet Onslaught! Don\'t listen to the lies of the high general and the grand admiral any longer!',0,1,0,0,'R2 - Lead Cannoneer Zierhut yell'), +(-272341,'You are being misled! The Onslaught is all lies! The Scourge and the Forsaken are not our enemies! Wake up!',0,1,0,0,'R2 - Blacksmith Goodman yell'), +(-272361,'Abbendis is nothing but a harlot and Grand Admiral Westwind is selling her cheap like he sold us out!',0,1,0,0,'R2 - Stable Master Mercer yell'); + +-- ACID +DELETE FROM creature_ai_scripts WHERE id IN (2723701,2723702,2723703,2723704,2723705,2723501,2723502,2723503,2723504,2723401,2723402,2723403,2723404,2723405,2723601,2723602,2723603,2723604); +INSERT INTO creature_ai_scripts VALUES + +-- Commander Jordan (27237) + +-- yell +(2723701,27237,4,0,100,6,0,0,0,0,1,-272371,0,0,0,0,0,0,0,0,0,0,'R2 - Commander Jordan - Yell on Aggro'), +-- Avenging Wrath (50837) +(2723702,27237,0,0,100,1,1000,3000,25000,30000,11,50837,0,0,0,0,0,0,0,0,0,0,'R2 - Commander Jordan - Cast Avenging Wrath'), +-- Consecration (32773) +(2723703,27237,9,0,100,1,0,10,18000,23000,11,32773,0,1,0,0,0,0,0,0,0,0,'R2 -Commander Jordan - Cast Consecration'), +-- Kill credit (48723/48724) +(2723704,27237,8,0,100,0,48712,-1,0,0,22,1,0,0,0,0,0,0,0,0,0,0,'R2 - Commander Jordan - Set Phase 2 after spell hit'), +(2723705,27237,6,1,100,0,0,0,0,0,33,27426,6,3,0,0,0,0,0,0,0,0,'R2 -Commander Jordan - Kill Credit on Death (Phase 2)'), + + +-- Lead Cannoneer Zierhut (27235) + +-- yell +(2723501,27235,4,0,100,6,0,0,0,0,1,-272351,0,0,0,0,0,0,0,0,0,0,'R2 - Lead Cannoneer Zierhut - Yell on Aggro'), +-- Torch Toss (50832) +(2723502,27235,0,0,100,1,3000,7000,12000,15000,11,50832,4,0,0,0,0,0,0,0,0,0,'R2 - Lead Cannoneer Zierhut - Cast Torch Toss'), +-- Kill Credit (48725/48726) +(2723503,27235,8,0,100,0,48712,-1,0,0,22,1,0,0,0,0,0,0,0,0,0,0,'R2 - Lead Cannoneer Zierhut - Set Phase 2 after spell hit'), +(2723504,27235,6,1,100,0,0,0,0,0,33,27427,6,3,0,0,0,0,0,0,0,0,'R2 - Lead Cannoneer Zierhut - Kill Credit on Death (Phase 2)'), + +-- Blacksmith Goodman (27234) + +-- yell +(2723401,27234,4,0,100,6,0,0,0,0,1,-272341,0,0,0,0,0,0,0,0,0,0,' R2 - Blacksmith Goodman - Yell on Aggro'), +-- Crush Armor (33661) +(2723402,27234,0,0,100,1,2000,5000,5000,7000,11,33661,1,0,0,0,0,0,0,0,0,0,'R2 - Blacksmith Goodman - Cast Crush Armor'), +-- Skull Crack (15621) +(2723403,27234,0,0,100,1,6000,9000,10000,14000,11,15621,1,1,0,0,0,0,0,0,0,0,'R2 - Blacksmith Goodman - Cast Skull Crack'), +-- Kill credit (48727/48728) +(2723404,27234,8,0,100,0,48712,-1,0,0,22,1,0,0,0,0,0,0,0,0,0,0,'R2 - Blacksmith Goodman - Set Phase 2 after spell hit'), +(2723405,27234,6,1,100,0,0,0,0,0,33,27428,6,3,0,0,0,0,0,0,0,0,'R2 - Blacksmith Goodman - Kill Credit on Death (Phase 2)'), + +-- Stable Master Mercer (27236) + +-- yell +(2723601,27236,4,0,100,6,0,0,0,0,1,-272361,0,0,0,0,0,0,0,0,0,0,'R2 - Stable Master Mercer - Yell on Aggro'), +-- Summon Warhorse (50829) +(2723602,27236,4,0,100,0,0,0,0,0,11,50829,0,1,12,28187,6,0,0,0,0,0,'R2 - Stable Master Mercer - Summon Warhorse on Aggro'), +-- Kill credit (48729/48730) +(2723603,27236,8,0,100,0,48712,-1,0,0,22,1,0,0,0,0,0,0,0,0,0,0,'R2 - Stable Master Mercer - Set Phase 2 after spell hit'), +(2723604,27236,6,1,100,0,0,0,0,0,33,27429,6,3,0,0,0,0,0,0,0,0,'R2 - Stable Master Mercer - Kill Credit on Death (Phase 2)'); + +-- ---------------------------------------------- +-- Support for quest Defiling Uther's Tomb (9444) +-- ---------------------------------------------- +DELETE FROM creature_ai_scripts WHERE creature_id=27002; +INSERT INTO creature_ai_scripts VALUES +(2700201,27002,11,0,100,0,0,0,0,0,1,-270021,0,0,0,0,0,0,0,0,0,0,'Grom\'thar the Thunderbringer - Yell on Spawn'), +(2700202,27002,9,0,100,1,5,45,19000,25000,11,52167,1,0,0,0,0,0,0,0,0,0,'Grom\'thar the Thunderbringer - Cast Magnataur Charge'), +(2700203,27002,0,0,100,1,7000,14000,12000,16000,11,52166,0,1,0,0,0,0,0,0,0,0,'Grom\'thar the Thunderbringer - Cast Thunder'), +(2700204,27002,6,0,100,0,0,0,0,0,1,-270022,0,0,0,0,0,0,0,0,0,0,'Grom\'thar the Thunderbringer - Yell on Death'); + +DELETE FROM creature_ai_texts WHERE entry IN (-270021,-270022); +INSERT INTO creature_ai_texts (entry, content_default, type, comment) VALUES +(-270021,'I\'ll consume your flesh and pick my teeth with your bones!',1,'R2 - Grom\'thar the Thunderbringer yell1'), +(-270022,'You\'re no magnataur! Where... did you... find... such strength?',1,'R2 - Grom\'thar the Thunderbringer yell2'); + +-- ---------- +-- Quest 9076 +-- ---------- +UPDATE `creature` SET `equipment_id` = 160, `spawndist` = 0, `MovementType` = 0 WHERE `id` = 16294; + +-- ------------------------------------------------- +-- Support for quest A Necessary Distraction (10637) +-- ------------------------------------------------- + +-- Azaloth (21506) + +-- TODO ( really tired right now) +-- still need to make him attack and make the circle of casters around him being channeled a dumby spell -> only visual stuff is missing + +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 21506; + +DELETE FROM creature_ai_scripts WHERE creature_id=21506; +INSERT INTO creature_ai_scripts VALUES +(2150601, 21506, 8, 0, 100, 1, 37834, -1, 0, 0, 1, -21506, 0, 0, 28, 0, 37833, 0, 33, 21892, 6, 0, 'Azaloth - Yell and Start Combat Movements -R2'), +(2150602,21506,0,0,100,1,4000,4000,8000,8000,11,40504,1,0,0,0,0,0,0,0,0,0,'Azaloth - Cast Cleave-R2'), +(2150603,21506,0,0,100,1,3000,3000,17000,17000,11,11443,1,1,0,0,0,0,0,0,0,0,'Azaloth Cast Cripple-R2'), +(2150604,21506,0,0,100,1,10000,12000,33000,33000,11,38741,4,3,0,0,0,0,0,0,0,0,'Azaloth - Cast Rain of Fire-R2'), +(2150605,21506,0,0,100,1,6000,6000,14000,14000,11,38750,1,3,0,0,0,0,0,0,0,0,'Azaloth - Cast War Stomp-R2'); + + +DELETE FROM creature_ai_texts WHERE entry=-21506; +INSERT INTO creature_ai_texts (entry,content_default,type,comment) VALUES +(-21506,'Illidan\s lapdogs! You will pay for my imprisonment with your lives!',1,'Azaloth yell1'); + +UPDATE `creature_template_addon` SET `b2_0_sheath` = 0, `auras` = '' WHERE `entry` = 21506; diff --git a/sql_mr/mr00490_mangos_draktharon.sql b/sql_mr/mr00490_mangos_draktharon.sql new file mode 100644 index 0000000000..658184f8c7 --- /dev/null +++ b/sql_mr/mr00490_mangos_draktharon.sql @@ -0,0 +1,19 @@ + +DELETE FROM `creature_template` WHERE `entry` = 26710; +INSERT INTO `creature_template` (`Entry`, `Name`, `SubName`, `IconName`, `MinLevel`, `MaxLevel`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `FactionAlliance`, `FactionHorde`, `Scale`, `Family`, `CreatureType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `NpcFlags`, `UnitFlags`, `DynamicFlags`, `ExtraFlags`, `CreatureTypeFlags`, `SpeedWalk`, `SpeedRun`, `UnitClass`, `Rank`, `Expansion`, `HealthMultiplier`, `PowerMultiplier`, `DamageMultiplier`, `DamageVariance`, `ArmorMultiplier`, `ExperienceMultiplier`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `MinMeleeDmg`, `MaxMeleeDmg`, `MinRangedDmg`, `MaxRangedDmg`, `Armor`, `MeleeAttackPower`, `RangedAttackPower`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `DamageSchool`, `MinLootGold`, `MaxLootGold`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `KillCredit1`, `KillCredit2`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MechanicImmuneMask`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MovementType`, `MovementTemplateId`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `TrainerTemplateId`, `VendorTemplateId`, `EquipmentTemplateId`, `VehicleTemplateId`, `GossipMenuId`, `AIName`, `ScriptName`) VALUES +('26710','Channel Target','','','1','1','0','0','0','2536','1160','9829','14952','190','190','1','0','10','4','3','0','0','33587200','0','0','0','1','1.14286','1','0','-1','0.2','1','7.5','1','1','1','8','8','0','0','2','2','1','1','7','24','100','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','100','0','0','0','0','0','0','0','0','0','',''); + + +DELETE FROM `creature_template` WHERE `entry` = 26714; +INSERT INTO `creature_template` (`Entry`, `Name`, `SubName`, `IconName`, `MinLevel`, `MaxLevel`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `FactionAlliance`, `FactionHorde`, `Scale`, `Family`, `CreatureType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `NpcFlags`, `UnitFlags`, `DynamicFlags`, `ExtraFlags`, `CreatureTypeFlags`, `SpeedWalk`, `SpeedRun`, `UnitClass`, `Rank`, `Expansion`, `HealthMultiplier`, `PowerMultiplier`, `DamageMultiplier`, `DamageVariance`, `ArmorMultiplier`, `ExperienceMultiplier`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `MinMeleeDmg`, `MaxMeleeDmg`, `MinRangedDmg`, `MaxRangedDmg`, `Armor`, `MeleeAttackPower`, `RangedAttackPower`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `DamageSchool`, `MinLootGold`, `MaxLootGold`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `KillCredit1`, `KillCredit2`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MechanicImmuneMask`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MovementType`, `MovementTemplateId`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `TrainerTemplateId`, `VendorTemplateId`, `EquipmentTemplateId`, `VehicleTemplateId`, `GossipMenuId`, `AIName`, `ScriptName`) VALUES +('26714','Dead Crystal Holder','','','1','1','0','0','0','2536','1160','9829','14952','190','190','1','0','10','4','3','0','0','32768','0','0','0','1','1.14286','1','0','-1','0.2','1','7.5','1','1','1','8','8','0','0','2','2','1','1','7','24','100','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','100','0','0','0','0','0','0','0','0','0','',''); + +/*King Dred*/ + +/* +DELETE FROM `spell_script_target` WHERE `entry` = 49555 AND `targetEntry` != 27753; + +UPDATE `creature_template` SET AIName = '', ScriptName = '' where entry = 26627; +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=26627); +*/ +UPDATE `creature_template` SET AIName = '', ScriptName = 'boss_dred' where entry = 27483; diff --git a/sql_mr/mr00491_mangos_razorfen_downs.sql b/sql_mr/mr00491_mangos_razorfen_downs.sql new file mode 100644 index 0000000000..80a9485683 --- /dev/null +++ b/sql_mr/mr00491_mangos_razorfen_downs.sql @@ -0,0 +1,41 @@ +-- ------------------------------ +-- Instance Razorfen Downs - +-- ------------------------------ + +-- -------------------------- +-- tuten Gong Event Support - +-- -------------------------- + +-- tuten'kash + -- acid Cleanup +DELETE FROM `creature_ai_scripts` WHERE creature_id = 7355; + -- creature template +UPDATE `creature_template` SET `MinLevelHealth` = 46200, `ModelId2` = 7845, `MaxLevelHealth` = 46200, `AIName` = '' WHERE `entry` = 7355; +UPDATE `creature_template` SET `MinLevel` = 45, `MaxLevel` = 45, `Rank` = 3 WHERE `entry` = 7355; + -- missing itm from loot table +DELETE FROM `creature_loot_template` WHERE (`entry`=7355) AND (`item`=4637); +INSERT INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES (7355, 4637, 0.1647, 0, 1, 1); + -- delete static spawn he is spawned on third gong ring +DELETE FROM `creature` WHERE `id`=7355; + -- OLD YTDB DATA + -- DELETE FROM `creature` WHERE `id`=7355; + -- INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES + -- (49670, 7355, 129, 1, 1, 0, 0, 2485.29, 816.253, 43.2455, 1.78733, 43200, 5, 0, 10688, 0, 0, 1); + -- Increase dmg ( might need more im being generous ) +UPDATE `creature_template` SET `MinMeleeDmg` = 58, `MaxMeleeDmg` = 82 WHERE `entry` = 7355; + -- assigned script name +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_tuten_kash' WHERE `entry` = 7355; + +-- -> end of tuten'kask + +DELETE FROM `creature` WHERE `id`=7351; +DELETE FROM `creature` WHERE `id`=7349; +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=7349); + +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=7351); +UPDATE `creature_template` SET `MinLevel` = 44, `MaxLevel` = 44, `MaxLevelHealth` = 7831, `MinMeleeDmg` = 52, `MaxMeleeDmg` = 72, `AIName` = '', `ScriptName` = 'npc_tomb_reaver' WHERE `entry` = 7351; + +UPDATE `creature_template` SET `MinLevelHealth` = 3342, `MaxLevelHealth` = 3342, `AIName` = '', `ScriptName` = 'npc_tomb_fiend' WHERE `entry` = 7349; + +UPDATE `gameobject_template` SET `ScriptName` = 'go_gong_razor' WHERE `entry` = 148917; +UPDATE `gameobject_template` SET `flags` = 32 WHERE `entry` = 148917; diff --git a/sql_mr/mr00492_scriptdev2_ebon_hold_dk_quest.sql b/sql_mr/mr00492_scriptdev2_ebon_hold_dk_quest.sql new file mode 100644 index 0000000000..a051976dad --- /dev/null +++ b/sql_mr/mr00492_scriptdev2_ebon_hold_dk_quest.sql @@ -0,0 +1,63 @@ +-- ------------------------------ +-- Quest:: ambush at the overlook +-- ------------------------------ +DELETE FROM `script_texts` WHERE `entry` IN ('-1609531','-1609532'); +INSERT INTO `script_texts` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`, `sound`, `type`, `language`, `emote`, `comment`) VALUES +(-1609531, 'Hrm, what a strange tree. I must investigate.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 'Scarlet Courier SAY_TREE1'), +(-1609532, 'What\'s this!? This isn\'t a tree at all! Guards! Guards!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 'Scarlet Courier SAY_TREE2'); + +-- ---------------------------------------------- +-- Quest how to win friends and influence enemies +-- ---------------------------------------------- +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1609119 AND -1609101; +INSERT INTO `script_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`emote`,`comment`) VALUES +(-1609101, 'I\'ll tear the secrets from your soul! Tell me about the "Crimson Dawn" and your life may be spared!',0,0,0,0,'player SAY_PERSUADE1'), +(-1609102, 'Tell me what you know about "Crimson Dawn" or the beatings will continue!',0,0,0,0,'player SAY_PERSUADE2'), +(-1609103, 'I\'m through being courteous with your kind, human! What is the "Crimson Dawn?"',0,0,0,0,'player SAY_PERSUADE3'), +(-1609104, 'Is your life worth so little? Just tell me what I need to know about "Crimson Dawn" and I\'ll end your suffering quickly.',0,0,0,0,'player SAY_PERSUADE4'), +(-1609105, 'I can keep this up for a very long time, Scarlet dog! Tell me about the "Crimson Dawn!"',0,0,0,0,'player SAY_PERSUADE5'), +(-1609106, 'What is the "Crimson Dawn?"',0,0,0,0,'player SAY_PERSUADE6'), +(-1609107, '"Crimson Dawn!" What is it! Speak!',0,0,0,0,'player SAY_PERSUADE7'), +(-1609108, 'You\'ll be hanging in the gallows shortly, Scourge fiend!',0,0,0,0,'crusader SAY_CRUSADER1'), +(-1609109, 'You\'ll have to kill me, monster! I will tell you NOTHING!',0,0,0,0,'crusader SAY_CRUSADER2'), +(-1609110, 'You hit like a girl. Honestly. Is that the best you can do?',0,0,0,0,'crusader SAY_CRUSADER3'), +(-1609111, 'ARGH! You burned my last good tabard!',0,0,0,0,'crusader SAY_CRUSADER4'), +(-1609112, 'Argh... The pain... The pain is almost as unbearable as the lashings I received in grammar school when I was but a child.',0,0,0,0,'crusader SAY_CRUSADER5'), +(-1609113, 'I used to work for Grand Inquisitor Isillien! Your idea of pain is a normal mid-afternoon for me!',0,0,0,0,'crusader SAY_CRUSADER6'), +(-1609114, 'I\'ll tell you everything! STOP! PLEASE!',0,0,0,20,'break crusader SAY_PERSUADED1'), +(-1609115, 'We... We have only been told that the "Crimson Dawn" is an awakening. You see, the Light speaks to the High General. It is the Light...',0,0,0,20,'break crusader SAY_PERSUADED2'), +(-1609116, 'The Light that guides us. The movement was set in motion before you came... We... We do as we are told. It is what must be done.',0,0,0,20,'break crusader SAY_PERSUADED3'), +(-1609117, 'I know very little else... The High General chooses who may go and who must stay behind. There\'s nothing else... You must believe me!',0,0,0,20,'break crusader SAY_PERSUADED4'), +(-1609118, 'LIES! The pain you are about to endure will be talked about for years to come!',0,0,0,0,'break crusader SAY_PERSUADED5'), +(-1609119, 'NO! PLEASE! There is one more thing that I forgot to mention... A courier comes soon... From Hearthglen. It...',0,0,0,20,'break crusader SAY_PERSUADED6'); + +-- Scourge Gryphon +DELETE FROM `script_waypoint` WHERE `entry`='28864'; +INSERT INTO `script_waypoint` (`entry`, `pointid`, `location_x`, `location_y`, `location_z`, `waittime`) VALUES +('28864', '0', '2199.4602', '-6125.4033', '35.6491', '1000'), +('28864', '1', '2237.8930', '-6007.2319', '73.6170', '0'), +('28864', '2', '2292.5766', '-5931.1767', '109.880', '0'), +('28864', '3', '2337.958496', '-5776.514648', '171.126999', '0'), +('28864', '4', '2363.8535', '-5715.2338', '153.921', '0'); + +-- Scarlet Miner +DELETE FROM `script_waypoint` WHERE `entry` = 28841; +INSERT INTO `script_waypoint` (`entry`, `pointid`, `location_x`, `location_y`, `location_z`, `waittime`) VALUES +('28841', '0', '2389.030000', '-5902.740000', '109.014000', '5000'), +('28841', '1', '2341.812012', '-5900.484863', '102.619743', '0'), +('28841', '2', '2306.561279', '-5901.738210', '91.7924190', '0'), +('28841', '3', '2300.098389', '-5912.618652', '86.0148850', '0'), +('28841', '4', '2294.142090', '-5927.274414', '75.3168490', '0'), +('28841', '5', '2286.984375', '-5944.955566', '63.7149660', '0'), +('28841', '6', '2280.001709', '-5961.186035', '54.2282830', '0'), +('28841', '7', '2259.389648', '-5974.197754', '42.3593480', '0'), +('28841', '8', '2242.882812', '-5984.642578', '32.8278500', '0'), +('28841', '9', '2222.845625', '-6017.849473', '10.153750', '0'), +('28841', '10', '2202.595947', '-6061.325684', '5.8820180', '0'), +('28841', '11', '2188.974609', '-6080.866699', '3.3700270', '0'), +('28841', '12', '2176.483887', '-6110.407227', '1.8551810', '0'), +('28841', '13', '2172.516602', '-6146.752441', '1.0742350', '0'), +('28841', '14', '2138.918457', '-6158.920898', '1.3429260', '0'), +('28841', '15', '2129.866699', '-6174.107910', '4.3807790', '0'), +('28841', '16', '2122.426270', '-6185.311035', '14.052804', '0'), +('28841', '17', '2117.739014', '-6193.830079', '13.354200', '10000'); diff --git a/sql_mr/mr00518_mangos_ebon_hold_dk_quest.sql b/sql_mr/mr00518_mangos_ebon_hold_dk_quest.sql new file mode 100644 index 0000000000..a02e1653db --- /dev/null +++ b/sql_mr/mr00518_mangos_ebon_hold_dk_quest.sql @@ -0,0 +1,307 @@ +-- first clean +-- YTDB cleanup +DELETE FROM `creature` WHERE `map` = 609 AND `guid` IN (116863); +DELETE FROM `creature` WHERE `map` = 609 AND `id` IN (29219,29206,29190); +UPDATE `creature_template` SET `UnitFlags` = 0, `CreatureTypeFlags` = 8 WHERE entry IN (29174,29182,29186,29190,29206,29176,29177,29181); +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'generic_creature' WHERE `entry` = 29178; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'generic_creature' WHERE `entry` = 29179; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'generic_creature' WHERE `entry` = 29180; + +-- ------------ +-- Special npcs +-- ------------ + +UPDATE `creature_template` SET `ScriptName` = 'npc_valkyr_battle_maiden' WHERE `entry` = '28534'; + +-- ------------------------ +-- QUEST::DAWN OF THE LIGHT +-- ------------------------ +-- remove the four static uneeded spawn around chapel -- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29174; + +-- remove static rayne-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29181; + +-- remove static rimblat-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29182; + +-- remove static krofax-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29176; + +-- remove static eligor-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29177; + +-- remove static tyrosus-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29178; + +-- remove static leon-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29179; + +-- remove stativ duke-- spawned during event not static plus they respawn during event +DELETE FROM `creature` WHERE `id`=29180; + +UPDATE `creature_template` SET `AIName` = '', `ScriptName`='npc_minibosses_dawn_of_light' WHERE `entry` IN (29199,29204,29200); +UPDATE `creature_template` SET `AIName` = '', `ScriptName`='mob_acherus_ghoul' WHERE `entry`='29219'; +UPDATE `creature_template` SET `AIName` = '', `ScriptName`='mob_warrior_of_the_frozen_wastes' WHERE `entry`='29206'; + +-- ---------------------------- +-- Quest:: An End To All Things +-- ---------------------------- + +-- Frostbrood Vanquisher +DELETE FROM `creature_spell` WHERE `guid` IN (28670); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(28670, 53114, 0, 0, 0, 0), +(28670, 53110, 1, 0, 0, 0); + +-- ----------------------------- +-- Quest::Ambush at the overlook +-- ----------------------------- +UPDATE `creature_template` SET `ScriptName`='mob_scarlet_courier' WHERE `entry`='29076'; + +-- ---------------------- +-- Quest::Bloody Breakout +-- ---------------------- +UPDATE `creature_template` SET `MechanicImmuneMask` = 12582928 WHERE `entry` = 28912; +UPDATE `creature_template` SET `MechanicImmuneMask` = 12582928 WHERE `entry` = 28447; + +-- tweak Valroth EAI +DELETE FROM `creature_ai_scripts` WHERE `id` IN (2900101, 2900112); +INSERT INTO `creature_ai_scripts` VALUES +('2900101', '29001', '1', '0', '100', '0', '0', '0', '0', '0', '21', '1', '1', '0', '22', '0', '0', '0', '0', '0', '0', '0', 'High Inquisitor Valroth - Set Phase to 0 on Spawn'), +('2900112', '29001', '0', '0', '100', '1', '2000', '10000', '7500', '10000', '11', '52922', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'High Inquisitor Valroth - Cast Inquisitor_penance'); + +UPDATE `gameobject_template` SET `castBarCaption` = 'Valroth\'s Remains' WHERE `entry` = 191092; -- caption bar message when looting remains + +UPDATE `creature_template` SET `EquipmentTemplateId` = 0 WHERE `entry` = 28912; -- tabled half dead version shouldnt be carrying a axe +UPDATE `creature_template` SET `EquipmentTemplateId` = 488 WHERE `entry` = 28447; -- this is model with axe + +UPDATE `creature_equip_template` SET `equipentry1` = 38633, `equipentry2` = 0 WHERE `entry` = 488; -- make sure axe is right + +UPDATE `creature_template_addon` SET `auras` = '52894' WHERE `entry` = 28447; -- spawned entry should have anti zone magic field + +-- tweaked crimsons EAIs +DELETE FROM `creature_ai_scripts` WHERE `id` IN (2900701, 2900702, 2900703); +INSERT INTO `creature_ai_scripts` VALUES ('2900701', '29007', '4', '0', '100', '0', '0', '0', '0', '0', '11', '15498', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', ''); +INSERT INTO `creature_ai_scripts` VALUES ('2900702', '29007', '0', '0', '100', '1', '1000', '4000', '1000', '4000', '11', '15498', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', ''); +INSERT INTO `creature_ai_scripts` VALUES ('2900703', '29007', '11', '0', '100', '1', '0', '0', '0', '0', '11', '34809', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', ''); + +-- ----------------------------------------------------- +-- Quest how to win friends and how to influence enemies +-- ----------------------------------------------------- +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_crusade_persuaded' WHERE `entry` IN (28939,28610); -- 28640 scarlet crusader needs to be added + +-- --------------------------------------------------------------- +-- Quest Death comes From a High +-- --------------------------------------------------------------- +-- Eye of acherus + +-- Use proper Hunter's Mark Visual Only +REPLACE INTO `creature_template_addon` (`entry`,`auras`) VALUES +(28525, '64328'), +(28542, '64328'), +(28543, '64328'), +(28544, '64328'); -- aura=51859 and b2_0_sheath=1 in YTDB + +UPDATE `creature_template` SET `ScriptName` = 'npc_eye_of_acherus' WHERE `entry` = 28511; + +-- ----------------------------------------------------------------------------- +-- Quest Death's Changelle -- +-- ----------------------------------------------------------------------------- + +-- bug olrun - is out of interaction reach for smaller races -- +UPDATE `creature` SET `position_x` = 2371.77, `position_y` = -5788.7, `position_z` = 155.61 WHERE `guid` = 96309; + +-- -------------------------------------------------------------------- +-- Quest Fix Noth Special Brew (dk starting area quest fix 12716/12717 +-- --------------------------------------------------------------------- +UPDATE `quest_template` SET `ExclusiveGroup` = 12716 WHERE `entry` = 12716; -- in YTDB is -12716 + +-- ------------------------------- +-- Quest Into the Realm of Shadows +-- ------------------------------- + +UPDATE `creature_template` SET `UnitFlags` = 0 WHERE `entry` = 28782; + +UPDATE `quest_template` SET `SrcSpell` = 52359, `ReqCreatureOrGOId1` = 28768, `ReqCreatureOrGOCount1` = 1, `ReqSpellCast1` = 0 WHERE `entry` = 12687; + +-- DELETE FROM creature_involvedrelation WHERE quest IN (12687); -- this cause drop id 28653 from YTDB +INSERT IGNORE INTO creature_involvedrelation (id, quest) VALUES +(28788, 12687); + +UPDATE creature_template SET `NpcFlags` = 2 WHERE entry = 28788; + +-- EventAI +UPDATE creature_template SET AIName='EventAI' WHERE entry = 28768; + +DELETE FROM creature_ai_scripts WHERE creature_id = 28768; +INSERT INTO creature_ai_scripts VALUES +('2876801','28768','4','0','100','0','0','0','0','0','1','-780','0','0','0','0','0','0','0','0','0','0','Dark Rider of Acherus - Yell on Aggro'), +('2876802','28768','0','0','100','1','0','1500','6000','9000','11','52372','1','0','0','0','0','0','0','0','0','0','Dark Rider of Acherus - Cast Icy Touch'), +('2876803','28768','0','0','100','1','3000','7000','6000','9000','11','50688','1','0','0','0','0','0','0','0','0','0','Dark Rider of Acherus - Cast Plague Strike'), +('2876804','28768','0','0','100','1','6000','10000','6000','9000','11','52374','1','0','0','0','0','0','0','0','0','0','Dark Rider of Acherus - Cast Blood Strike'), +('2876805','28768','9','0','100','1','5','30','2000','2000','11','52356','1','0','0','0','0','0','0','0','0','0','Dark Rider of Acherus - Cast Throw'), +('2876806','28768','6','0','100','0','0','0','0','0','12','28782','0','10000','15','12687','6','0','43','0','0','0','Dark Rider of Acherus - Spawn Deathcharger of Acherus and Set Quest Event Complete and Dismount on Death'); + +-- quest 12687 +-- riders are on vehicle accessory +DELETE FROM `creature` WHERE id = 28768; +DELETE FROM vehicle_accessory WHERE vehicle_entry = 28782; +INSERT INTO vehicle_accessory (`vehicle_entry`, `seat`, `accessory_entry`,`comment`) VALUES +(28782, 0, 28768, 'Acherus Deathcharger - Dark Rider of Acherus'); + +DELETE FROM spell_script_target WHERE entry = 52349; +INSERT INTO spell_script_target (`entry`, `type`, `targetEntry`) VALUES +(52349,1,28782); + +DELETE FROM npc_spellclick_spells where npc_entry = 28782; +INSERT INTO npc_spellclick_spells (npc_entry, spell_id, quest_start, cast_flags) values +(28782, 52349, 0, 2); + +DELETE FROM dbscripts_on_spell where id = 52361; +INSERT INTO dbscripts_on_spell (id, command, datalong, data_flags, comments) values +(52361, 14, 52349, 6, 'remove Overtake aura'), +(52361, 14, 52693, 6, 'remove Realm of Shadows aura'); + +DELETE FROM `creature` WHERE id = 28782; +DELETE FROM `creature_template_addon` WHERE entry = 28782; + +UPDATE `npc_spellclick_spells` SET `spell_id` = 46598, `quest_start` = 0, `quest_start_active` = 0, `quest_end` = 0 WHERE `npc_entry` = 28782; -- cause corrupt Q12687 from YTDB + +-- ----------------------------------- +-- Quest The Gift That Keeps On Giving +-- ----------------------------------- + +-- item spell script targets (Scarlet Miners) +DELETE FROM `spell_script_target` WHERE entry = 52479; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(52479, 1, 28819), +(52479, 1, 28822), +(52479, 1, 28891); + +DELETE FROM `spell_script_target` WHERE entry = 52514; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(52514, 1, 28845); + +-- EventAI for ghost needs tweaked and double checked +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = 28846; + +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = 28846; +INSERT INTO `creature_ai_scripts` VALUES +(2884601, 28846, 11, 0, 100, 0, 0, 0, 0, 0, 1, -286100, -286101, -286102, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Ghost - Random say at spawn"); + +DELETE FROM `creature_ai_texts` WHERE `entry` IN (-286102, -286101, -286100); +INSERT INTO `creature_ai_texts` (`entry`, `content_default`, `content_loc8`, `sound`, `type`, `language`, `emote`, `comment`) VALUES +(-286100, "Die, Scourge filth!", "Сдохни, отродье Плети!", 0, 0, 0, 0, "Scarlet Ghost SAY1"), +(-286101, "It won't be that easy, friend!", "Это не будет просто, друг!", 0, 0, 0, 0, "Scarlet Ghost SAY2"), +(-286102, "I'll take you with me!", "Я заберу тебя с собой!", 0, 0, 0, 0, "Scarlet Ghost SAY3"); + +-- fix to take Quest Item Away at end of quest +UPDATE `quest_template` SET `ReqItemId1` = 39253, `ReqItemCount1` = 1 WHERE `entry` = 12698; + +/* Q:12678 If Chaos Drives, Let Suffering Hold The Reins */ +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_scarlet_miner' WHERE `entry` = 28841; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_mine_car' WHERE `entry` = 28817; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_scourge_gryphon' WHERE `entry` = 28864; +UPDATE `gameobject_template` SET `ScriptName` = 'go_inconspicous_mine_car' WHERE `entry` = 190767; +UPDATE `creature_template` SET `MechanicImmuneMask` = 0, `ExtraFlags` = 0 WHERE `entry` = 28864; + +-- fixed dispaly of mine car +UPDATE `creature_template` SET `ModelId2` = 25703 WHERE `entry` = 28817; + +/* Scourge Gryphon */ +UPDATE `creature_template` SET `SpeedRun` = 2 WHERE `entry` = 28864; + +DELETE FROM `creature_template_addon` WHERE `entry` = 28864; +INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `b2_0_sheath`, `b2_1_pvp_state`, `emote`, `moveflags`, `auras`) VALUES +(28864, 0, 0, 0, 0, 0, 0, '61453'); + +/* Scarlet Cannon */ +UPDATE `creature_template` SET `VehicleTemplateId` = 79 WHERE `entry` IN (28833); +DELETE FROM `creature_spell` WHERE `guid` IN (28833); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(28833, 52435, 0, 0, 0, 0), +(28833, 52576, 1, 0, 0, 0), +(28833, 52588, 4, 0, 0, 0); + +DELETE FROM `creature_spell` WHERE `guid` IN (28887); +INSERT INTO `creature_spell` (`guid`, `spell`, `index`, `active`, `disabled`, `flags`) VALUES +(28887, 52435, 0, 0, 0, 0), +(28887, 52576, 1, 0, 0, 0), +(28887, 52588, 4, 0, 0, 0); + +UPDATE `creature_template` SET `UnitFlags` = 772, `MinMeleeDmg` = 685, `MaxMeleeDmg` = 715, `Armor` = 3232, `MeleeAttackPower` = 214 WHERE `entry` = 28833; +UPDATE `creature_template` SET `MinLevelHealth` = 26140, `MaxLevelHealth` = 26140, `MinLevelMana` = 0, `MaxLevelMana` = 0, `UnitFlags` = 772, `MinLevel` = 55, `MaxLevel` = 55, `MinMeleeDmg` = 685, `MaxMeleeDmg` = 715, `Armor` = 3232, `MeleeAttackPower` = 214 WHERE `entry` = 28887; +INSERT IGNORE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(52576, 1, 28834), +(52576, 1, 28886), +(52576, 1, 28850); + +-- ------------------------------------- +-- ACID scripts for Scarlet Enclave mobs +-- ------------------------------------- + +-- EventAI scripts name set +UPDATE `creature_template` SET `AIName` = "EventAI", `ScriptName` = "" WHERE entry IN (28834, 28892, 28856, 28850, 29104, 28941, 28942, 28577, 28576, 28557); + +-- script_texts +DELETE FROM `creature_ai_texts` WHERE `entry` BETWEEN -286099 AND -286092; +INSERT INTO `creature_ai_texts` (`entry`, `content_default`, `comment`) VALUES +(-286099, "You don't have to do this! Nobody has to die!", "Scarlet Peasant - Say Fear01"), +(-286098, "Let me live! I'll do whatever you say!", "Scarlet Peasant - Say Fear02"), +(-286097, "Ugh... I... I think I pooped...", "Scarlet Peasant - Say Fear03"), +(-286096, "I picked the wrong day to quit drinkin'!", "Scarlet Peasant - Say Fear04"), +(-286095, "Don't kill me! I only took this job for benefits!", "Scarlet Peasant - Say Fear05"), +(-286094, "Have mercy, sir!", "Citizen of Heavenshire - Say Aggro1"), +(-286093, "You may take my life, but you won't take my freedom!", "Citizen of Heavenshire - Say Enrage1"), +(-286092, "DIE!", "Citizen of Heavenshire - Say Enrage2"); + +-- EVENTAI scripts +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (28834, 28856, 28850, 29104, 28941, 28942, 28577, 28576, 28557, 28892); +INSERT INTO `creature_ai_scripts` VALUES +-- Scarlet Defender +(2883401, 28834, 0, 0, 100, 1, 0, 0, 3000, 3000, 11, 52566, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Defender - Cast Shoot"), +-- Scarlet Guardian +(2885601, 28856, 4, 0, 100, 0, 0, 0, 0, 0, 21, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 0, "Scarlet Guardian - Stop moving and set Phase 2 on aggro"), +(2885602, 28856, 9, 1, 100, 0, 10, 150, 0, 0, 21, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 0, "Scarlet Guardian - Stop moving and set Phase 2 at 10yd range"), +(2885603, 28856, 0, 1, 100, 1, 3000, 3000, 3000, 3000, 11, 25710, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Guardian - Cast Heroic Strike(Phase 1)"), +(2885604, 28856, 0, 2, 100, 1, 0, 0, 3000, 3000, 11, 52566, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Guardian - Cast Shoot(Phase 2)"), +(2885605, 28856, 9, 2, 100, 0, 0, 10, 0, 0, 21, 1, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, "Scarlet Guardian - Set Phase 1 at less then 10yd (Phase 2)"), +(2885606, 28856, 9, 0, 100, 0, 150, 300, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Guardian - Evade 150yd"), +-- Scarlet Land Cannon +(2885001, 28850, 0, 0, 100, 1, 0, 0, 3000, 3000, 11, 52539, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Cannon - Cast Cannonball"), +(2885002, 28850, 9, 0, 100, 0, 150, 300, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Cannon - Evade 150yd"), +-- Scarlet Balista +(2910401, 29104, 0, 0, 100, 1, 0, 0, 3000, 3000, 11, 53117, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Balista - Cast Ballista assault"), +(2910402, 29104, 9, 0, 100, 0, 150, 300, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Balista - Evade 150yd"), +-- Citizens of New Avalon -- needs tweaked +(2894101, 28941, 11, 0, 100, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Citizen of New Avalon - Spawn set Phase 1"), +(2894102, 28941, 0, 0, 80, 1, 0, 0, 10000, 10000, 11, 52716, 1, 1, 22, 2, 0, 0, 1, -286094, -286099, -286095, "Citizen of New Avalon - On Aggro: Escape in fear and set Phase 2"), +(2894103, 28941, 0, 0, 20, 1, 0, 0, 10000, 10000, 11, 52262, 1, 1, 22, 2, 0, 0, 1, -286093, -286092, 0, "Citizens of New Avalon - On Aggro: Enrage and set Phase 2"), +(2894201, 28942, 11, 0, 100, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Citizen of New Avalon - Spawn set Phase 1"), +(2894202, 28942, 0, 0, 80, 1, 0, 0, 10000, 10000, 11, 52716, 1, 1, 22, 2, 0, 0, 1, -286094, -286099, -286096, "Citizen of New Avalon - On Aggro: Escape in fear and set Phase 2"), +(2894203, 28942, 0, 0, 20, 1, 0, 0, 10000, 10000, 11, 52262, 1, 1, 22, 2, 0, 0, 1, -286093, -286092, 0, "Citizens of New Avalon - On Aggro: Enrage and set Phase 2"), +-- Citizens of Havenshire -- needs tweaked +(2857601, 28576, 11, 0, 100, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Citizen of New Havenshire - Spawn set Phase 1"), +(2857602, 28576, 4, 0, 80, 0, 0, 0, 0, 0, 11, 52716, 1, 1, 1, -286094, -286099, -286096, 0, 0, 0, 0, "Citizen of Havenshire - On Aggro: Beg for mercy"), +(2857603, 28576, 0, 0, 100, 1, 0, 0, 1000, 1000, 20, 0, 0, 0, 21, 0, 0, 0, 5, 20, 0, 0, "Citizen of Havenshire - Cower (Phase 3)"), +(2857604, 28576, 4, 0, 20, 0, 0, 0, 0, 0, 11, 52262, 1, 1, 1, -286093, -286092, 0, 0, 0, 0, 0, "Citizens of Havenshire - On Aggro: Enrage"), +(2857605, 28576, 7, 0, 100, 0, 0, 0, 0, 0, 5, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, "Citizens of Havenshire - Reset State"), + +(2857701, 28577, 11, 0, 100, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Citizen of Havenshire - Spawn set Phase 1"), +(2857702, 28577, 4, 0, 80, 0, 0, 0, 0, 0, 11, 52716, 1, 1, 1, -286094, -286099, -286095, 22, 3, 0, 0, "Citizen of Havenshire - On Aggro: Beg for mercy"), +(2857703, 28577, 0, 0, 100, 1, 0, 0, 1000, 1000, 20, 0, 0, 0, 5, 431, 0, 0, 21, 0, 0, 0, "Citizen of Havenshire - Cower (Phase 3)"), +(2857704, 28577, 4, 0, 20, 0, 0, 0, 0, 0, 11, 52262, 1, 1, 1, -286093, -286092, 0, 0, 0, 0, 0, "Citizens of Havenshire - On Aggro: Enrage"), +(2857705, 28577, 7, 0, 100, 0, 0, 0, 0, 0, 5, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, "Citizens of Havenshire - Reset State"), +-- Scarlet Peasant -- needs tweaked +(2855701, 28557, 11, 0, 100, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Peasant - Spawn set Phase 1"), +(2855702, 28557, 4, 1, 80, 0, 0, 0, 0, 0, 11, 52716, 1, 1, 1, -286099, -286098, -286097, 22, 2, 0, 0, "Scarlet Peasant - On Aggro: Beg for mercy"), +(2855703, 28557, 0, 0, 100, 1, 0, 0, 1000, 1000, 20, 0, 0, 0, 5, 20, 0, 0, 21, 0, 0, 0, "Scarlet Peasant - Cower (Phase 2)"), +(2855704, 28557, 7, 0, 100, 0, 0, 0, 0, 0, 5, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, "Scarlet Peasant - Reset State"), +(2889201, 28892, 11, 0, 100, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Scarlet Peasant - Spawn set Phase 1"), +(2889202, 28892, 4, 1, 80, 0, 0, 0, 0, 0, 11, 52716, 1, 1, 1, -286099, -286098, -286097, 22, 2, 0, 0, "Scarlet Peasant - On Aggro: Beg for mercy"), +(2889203, 28892, 0, 0, 100, 1, 0, 0, 1000, 1000, 20, 0, 0, 0, 5, 20, 0, 0, 21, 0, 0, 0, "Scarlet Peasant - Cower (Phase 2)"), +(2889204, 28892, 7, 0, 100, 0, 0, 0, 0, 0, 5, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 0, "Scarlet Peasant - Reset State"); + +-- end of EventAI +-- ----------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/sql_mr/mr00519_mangos_npc_special.sql b/sql_mr/mr00519_mangos_npc_special.sql new file mode 100644 index 0000000000..1448b454c0 --- /dev/null +++ b/sql_mr/mr00519_mangos_npc_special.sql @@ -0,0 +1,14 @@ +-- Snakes trap +UPDATE `creature_template` SET `ScriptName`='npc_snake_trap_serpents' WHERE `entry` IN (19921, 19833); +-- Rune blade +UPDATE `creature_template` SET `ModelId1` = 11686, `ModelId3` = 11686, `AIName` = '', `ScriptName`='npc_runeblade' WHERE `entry` = 27893; +-- Explosive decoy +UPDATE `creature_template` SET `ScriptName` = 'npc_explosive_decoy' WHERE `entry` = '29134'; +-- Eye of Kilrogg +UPDATE `creature_template` SET `ScriptName` = 'npc_eye_of_kilrogg' WHERE `entry` = '4277'; +-- Greater fire elemental +UPDATE `creature_template` SET `ScriptName` = 'pet_greater_fire_elemental' WHERE `entry` = '15438'; +-- Greater earth elemental +UPDATE `creature_template` SET `ScriptName` = 'pet_greater_earth_elemental' WHERE `entry` = '15352'; +-- Behsten & Slahtz +UPDATE `creature_template` SET `ScriptName` = 'npc_experience', `GossipMenuId` = 0 WHERE `entry` IN (35364, 35365); diff --git a/sql_mr/mr00537_mangos_spell_hacks_from_sd2.sql b/sql_mr/mr00537_mangos_spell_hacks_from_sd2.sql new file mode 100644 index 0000000000..eddcec9052 --- /dev/null +++ b/sql_mr/mr00537_mangos_spell_hacks_from_sd2.sql @@ -0,0 +1,84 @@ +-- Replace for old hardcore spells hack in SD2 + +-- boss_varos + +-- Replace DBC values for spell 61407 - "Energize Cores" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 61407; +INSERT INTO `spell_dbc` +( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) +VALUES (61407, 0, 0, 0, 65920, 136, 0, 0, 0, 524672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, -1, 0, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, "Energize Cores", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 64, 0 ); + +UPDATE `spell_dbc` SET +`EffectImplicitTargetA1` = 18, -- old value 54 +`MaxAffectedTargets` = 4, -- old value 0 +`Comment` = 'Replacement for spell 61407 ("Energize Cores")' +WHERE `Id` = 61407; + +-- Replace DBC values for spell 54069 - "Energize Cores" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 54069; +INSERT INTO `spell_dbc` +( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) +VALUES (54069, 0, 0, 0, 65920, 136, 0, 0, 0, 524288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, -1, 0, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, "Energize Cores", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 64, 0 ); + +UPDATE `spell_dbc` SET +`EffectImplicitTargetA1` = 18, -- old value 54 +`Comment` = 'Replacement for spell 54069 ("Energize Cores")' +WHERE `Id` = 54069; + +-- Replace DBC values for spell 50785 - "Energize Cores" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 50785; +INSERT INTO `spell_dbc` +( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) +VALUES (50785, 0, 0, 0, 65536, 136, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 9, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, -1, 0, 0, 2, 64, 64, 625, 0, 0, 0, 0, 0, 5937, 0, 0, 0, 0, 0, 54, 1, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54069, 56251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, "Energize Cores", 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 64, 0 ); + +UPDATE `spell_dbc` SET +`EffectImplicitTargetA1` = 18, -- old value 54 +`EffectImplicitTargetA2` = 18, -- old value 1 +`EffectImplicitTargetA3` = 18, -- old value 1 +`Comment` = 'Replacement for spell 50785 ("Energize Cores")' +WHERE `Id` = 50785; + +-- Replace DBC values for spell 59372 - "Energize Cores" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 59372; +INSERT INTO `spell_dbc` +( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) +VALUES (59372, 0, 0, 0, 65536, 136, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 9, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, -1, 0, 0, 2, 64, 64, 801, 0, 0, 0, 0, 0, 7599, 0, 0, 0, 0, 0, 54, 1, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54069, 56251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, "Energize Cores", 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 64, 0 ); + +UPDATE `spell_dbc` SET +`EffectImplicitTargetA1` = 18, -- old value 54 +`EffectImplicitTargetA2` = 18, -- old value 1 +`EffectImplicitTargetA3` = 18, -- old value 1 +`Comment` = 'Replacement for spell 59372 ("Energize Cores")' +WHERE `Id` = 59372; + +-- boss_sartharion +-- Replace DBC values for spell 58835 - "Twilight Torment" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 58835; +INSERT INTO `spell_dbc` +( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) +VALUES (58835, 0, 0, 0, 536873216, 136, 4, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 69972, 100, 999999, 0, 0, 0, 21, 0, 0, 0, 0, 0, 13, 0, 99, -1, 0, 0, 6, 6, 0, 1, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 22, 22, 0, 15, 15, 0, 28, 28, 0, 87, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 57988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, "Twilight Torment", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 32, 0 ); + +UPDATE `spell_dbc` SET +`StackAmount` = 1, -- old value 99 +`ProcCharges` = 1, -- old value 999999 +`Comment` = 'Replacement for spell 58835 ("Twilight Torment")' +WHERE `Id` = 58835; + +-- Replace DBC values for spell 57935 - "Twilight Torment" +-- +DELETE FROM `spell_dbc` WHERE `Id` = 57935; +INSERT INTO `spell_dbc` +( `Id`, `Category`, `Dispel`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `Stances`, `StancesNot`, `Targets`, `RequiresSpellFocus`, `CasterAuraState`, `TargetAuraState`, `CasterAuraStateNot`, `TargetAuraStateNot`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ProcFlags`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `StackAmount`, `EquippedItemClass`, `EquippedItemSubClassMask`, `EquippedItemInventoryTypeMask`, `Effect1`, `Effect2`, `Effect3`, `EffectDieSides1`, `EffectDieSides2`, `EffectDieSides3`, `EffectRealPointsPerLevel1`, `EffectRealPointsPerLevel2`, `EffectRealPointsPerLevel3`, `EffectBasePoints1`, `EffectBasePoints2`, `EffectBasePoints3`, `EffectMechanic1`, `EffectMechanic2`, `EffectMechanic3`, `EffectImplicitTargetA1`, `EffectImplicitTargetA2`, `EffectImplicitTargetA3`, `EffectImplicitTargetB1`, `EffectImplicitTargetB2`, `EffectImplicitTargetB3`, `EffectRadiusIndex1`, `EffectRadiusIndex2`, `EffectRadiusIndex3`, `EffectApplyAuraName1`, `EffectApplyAuraName2`, `EffectApplyAuraName3`, `EffectAmplitude1`, `EffectAmplitude2`, `EffectAmplitude3`, `EffectMultipleValue1`, `EffectMultipleValue2`, `EffectMultipleValue3`, `EffectItemType1`, `EffectItemType2`, `EffectMiscValue1`, `EffectMiscValue2`, `EffectMiscValue3`, `EffectMiscValueB1`, `EffectMiscValueB2`, `EffectMiscValueB3`, `EffectTriggerSpell1`, `EffectTriggerSpell2`, `EffectTriggerSpell3`, `EffectSpellClassMaskA1`, `EffectSpellClassMaskA2`, `EffectSpellClassMaskA3`, `EffectSpellClassMaskB1`, `EffectSpellClassMaskB2`, `EffectSpellClassMaskB3`, `EffectSpellClassMaskC1`, `EffectSpellClassMaskC2`, `EffectSpellClassMaskC3`, `SpellIconID`, `Comment`, `ManaCostPercentage`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellFamilyName`, `SpellFamilyFlags1`, `SpellFamilyFlags2`, `SpellFamilyFlags3`, `MaxAffectedTargets`, `DmgClass`, `PreventionType`, `DmgMultiplier1`, `DmgMultiplier2`, `DmgMultiplier3`, `AreaGroupId`, `SchoolMask`, `RuneCostID` ) +VALUES (57935, 0, 0, 0, 536873216, 136, 4, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 69972, 100, 999999, 0, 0, 0, 21, 0, 0, 0, 0, 0, 13, 0, 99, -1, 0, 0, 6, 6, 0, 1, 1, 0, 0, 0, 0, 74, -1, 0, 0, 0, 0, 22, 22, 0, 15, 15, 0, 28, 28, 0, 87, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 57988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, "Twilight Torment", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 32, 0 ); + +UPDATE `spell_dbc` SET +`StackAmount` = 1, -- old value 99 +`ProcCharges` = 1, -- old value 999999 +`Comment` = 'Replacement for spell 57935 ("Twilight Torment")' +WHERE `Id` = 57935; + diff --git a/sql_mr/mr00539_scriptdev2_ulduar.sql b/sql_mr/mr00539_scriptdev2_ulduar.sql new file mode 100644 index 0000000000..c965a15ded --- /dev/null +++ b/sql_mr/mr00539_scriptdev2_ulduar.sql @@ -0,0 +1,309 @@ +/* ULDUAR from Xfurry*/ +-- -1 603 000 ULDUAR + +DELETE FROM `script_texts` WHERE `entry` = -1603013; +-- translate from lanc +INSERT INTO `script_texts` (entry, content_default, content_loc1, content_loc2, content_loc3, content_loc4, content_loc5, content_loc6, content_loc7, content_loc8, sound, type, language, emote, comment) VALUES +(-1603013,'Freya casts Strenghtened Iron Roots!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_iron roots'); + +/* +-- Ignis: +(-1603020, "Insolent whelps! Your blood will temper the weapons used to reclaim this world!", "","","","","","","","Мерзкие глупцы! Ваша кровь закалит оружие, которым был завоеван этот мир!",15564, 1, 0, 0, 'IgnisAggro'), +(-1603021, "Let the inferno consume you!", "","","","","","","","Да поглотит вас пламя преисподней!",15567, 1, 0, 0, 'Ignis Scorch1'), +(-1603022, "BURN! Burn in the makers fire!", "","","","","","","","Горите! Горите в огне творца!",15568, 1, 0, 0, 'Ignis scroch2'), +(-1603023, "I will burn away your impurities!", "","","","","","","","Пройдите очищение огнем!",15566, 1, 0, 0, 'Ignis Slagpot'), +(-1603024, 'Ignis the Furnace Master begins to cast Flame Jets!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_FLAME_JETS'), +(-1603025, "Arise, soldiers of the Iron Crucible! The Makers\' will be done!", "","","","","","","","Вперед, воины Железного Тетинга! Да свершиться воля творца!",15565, 1, 0, 0, 'Ignis summon'), +(-1603026, "More scraps for the scrapheap!", "","","","","","","","Тебе место в мусорной куче!",15569, 1, 0, 0, 'IgnisSlay1'), +(-1603027, "Your bones will serve as kindling!", "","","","","","","","Твой кости пойдут на растопку!",15570, 1, 0, 0, 'IgnisSlay2'), +(-1603028, "Let it be finished!", "","","","","","","","Покончим с этим!",15571, 1, 0, 0, 'IgnisBerserk'), +(-1603029, "I. Have. Failed.", "","","","","","","","Я... Проиграл...",15572, 1, 0, 0, 'Ignis death'), + +-- razorscale +(-1603030,'Welcome, champions! All of our attempts at grounding her have failed. We could use a hand in bring her down with these harpoon guns.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Приветствую вас герои! Все наши попытки сбить ее не увенчались успехом. Нам бы пригодилась ваша помощь, гарпунных пушек на всех хватит.",15647,0,0,0,'razorscale intro - commander'), +(-1603031,'Give us a moment to prepare to build the turrets.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,0,'razor aggro 1 - eng'), +(-1603032,'Be on the lookout! Mole machines will be surfacing soon with those nasty Iron dwarves aboard!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,0,'razor aggro 2 - commander'), +(-1603033,'Ready to move out, keep those dwarves off of our backs!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,0,'razor aggro 3 - eng'), +(-1603034,'Move! Quickly! She won\'t remain grounded for long.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Быстрее! Она скоро снова взлетит.",0,1,0,0,'razor ground - commander'), +(-1603035,'Razorscale takes a deep breath...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'razor deep breath'), +(-1603036,'Fires out! Let\'s rebuild those turrets!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,0,'razor extinguish fires'), +(-1603337,'Harpoon Turret is ready for use!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_harpoon'), +(-1603338,'Razorscale grounded permanently!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_ground'), + +-- Xt002 +(-1603040,"You are bad... Toys... Very... Baaaaad!","","","","","","","","Плохие игрушки... Очень... Плохие!",15731,1,0,0,"XT-002 Death"), +(-1603041,"I'm tired of these toys. I don't want to play anymore!","","","","","","","","Какие скучные игрушки. Надоело играть!",15730,1,0,0,"XT-002 Berserk"), +(-1603042,"Time for a new game! My old toys will fight my new toys!","","","","","","","","Новые правила! Старые игрушки против новых!",15732,1,0,0,"XT-002 Adds"), +(-1603043,"I'm ready to play!","","","","","","","","Продолжаем игру!",15726,1,0,0,"XT-002 Heart Closed"), +(-1603044,"So tired. I will rest for just a moment!","","","","","","","","Я так устал. Отдохну чуток!",15725,1,0,0,"XT-002 Heart Opened"), +(-1603045,"I guess it doesn't bend that way.","","","","","","","","Наверное в эту сторону голова не гнулась.",15729,1,0,0,"XT-002 Slay 2"), +(-1603046,"I... I think I broke it.","","","","","","","","Кажется... Я сломал эту игрушку.",15728,1,0,0,"XT-002 Slay 1"), +(-1603047,"NO! NO! NO! NO! NO!","","","","","","","","Неееет! Нет! Нет! Нет! Нет!",15727,1,0,0,"XT-002 Tympanic Tantrum"), +(-1603048,"New toys? For me? I promise I won't break them this time!","","","","","","","","Новые игрушки? Для меня? Обещаю, в этот раз я их не поламаю!",15724,1,0,0,"XT-002 Aggro"), +(-1603049,'XT-002 Deconstructor\'s heart is exposed and leaking energy!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_expose_heart'), +(-1603050,'XT-002 Deconstructor consumes a scrapbot to repair himself.' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_repair'), + +-- Iron Council +-- Molgeim +(-1603060,"Nothing short of total decimation will suffice!","","","","","","","","",15657,1,0,0,"MolgeimAggro"), +(-1603061, "The legacy of storms shall not be undone...", "","","","","","","","",15662, 1, 0, 0, "MolgeimDeath1"), +(-1603062, "What have you gained from my defeat? You are no less doomed, mortals...", "","","","","","","","",15663, 1, 0, 0, 'MolgeimDeath2'), +(-1603063, "Decipher this!", "","","","","","","","",15660, 1, 0, 0, 'MolgeimDeathRune'), +(-1603064, "Face the lightning surge!", "","","","","","","","",15661, 1, 0, 0, 'MolgeimSummon'), +(-1603065, "The world on suffers yet another insignificant loss!", "","","","","","","","",15658, 1, 0, 0, 'MolgeimSlay1'), +(-1603066, "Death is the price of your arrogance.", "","","","","","","","",15659, 1, 0, 0, 'MolgeimSlay2'), +(-1603067, "This meeting of the Assembly of Iron is adjourned!", "","","","","","","","",15664, 1, 0, 0, 'MolgeimBerserk'), +-- Steelbreaker +(-1603070, "You will not defeat the Assembly of Iron so easily, invaders!", "","","","","","","","",15674, 1, 0, 0, 'SteelAggro'), +(-1603071, "My death only serves to hasten your demise.", "","","","","","","","",15678, 1, 0, 0, 'SteelDeath1'), +(-1603072, "Impossible!", "","","","","","","","",15679, 1, 0, 0, 'SteelDeath2'), +(-1603073, "So fragile and weak!", "","","","","","","","",15675, 1, 0, 0, 'SteelSlay1'), +(-1603074, "Flesh... such a hindrance.", "","","","","","","","",15676, 1, 0, 0, 'SteelSlay2'), +(-1603075, "You seek the secrets of Ulduar? Then take them!", "","","","","","","","",15677, 1, 0, 0, 'SteelOverwhelming'), +(-1603076, "This meeting of the Assembly of Iron is adjourned!", "","","","","","","","",15680, 1, 0, 0, 'SteelBerserk'), +-- Brudir +(-1603080, "Whether the world\'s greatest gnats or the world\'s greatest heroes, you\'re still only mortal.", "","","","","","","","",15684, 1, 0, 0, 'BrundirAggro'), +(-1603081, "Stand still and stare into the light!", "","","","","","","","",15687, 1, 0, 0, 'BrundirWhirl'), +(-1603082, "The power of the storm lives on...", "","","","","","","","",15689, 1, 0, 0, 'BrundirDeath1'), +(-1603083, "You rush headlong into the maw of madness!", "","","","","","","","",15690, 1, 0, 0, 'BrundirDeath2'), +(-1603084, "A merciful kill!", "","","","","","","","",15685, 1, 0, 0, 'BrundirSlay1'), +(-1603085, "HAH!", "","","","","","","","",15686, 1, 0, 0, 'BrundirSlay2'), +(-1603086, "This meeting of the Assembly of Iron is adjourned!", "","","","","","","","",15691, 1, 0, 0, 'BrundirBerserk'), +(-1603087, "Let the storm clouds rise and rain down death from above!", "","","","","","","","",15688, 1, 0, 0, 'BrundirFly'), + +-- Kologarn: +(-1603090, "None shall pass!", "","","","","","","","Вам не пройти!",15586, 1, 0, 0, 'KologarnAggro'), +(-1603091, "OBLIVION!", "","","","","","","","Забвение",15591, 1, 0, 0, 'Kologarn shockweave'), +(-1603092, "I will squeeze the life from you!", "","","","","","","","Я лишу тебя жизни!",15592, 1, 0, 0, 'Kologarn grab'), +(-1603093, "Just a scratch!", "","","","","","","","Царапина!",15589, 1, 0, 0, 'left arm lost'), +(-1603094, "Only a flesh wound!", "","","","","","","","Всего лиш плоть!",15590, 1, 0, 0, 'right arm lost'), +(-1603095, "KOL-THARISH!", "","","","","","","","Кол-Таариш!",15587, 1, 0, 0, 'KologarnSlay1'), +(-1603096, "YOU FAIL!", "","","","","","","","Тебе конец!",15588, 1, 0, 0, 'KologarnSlay2'), +(-1603097, "I am invincible!", "","","","","","","","Я не победим!",15594, 1, 0, 0, 'KologarnBerserk'), +(-1603098, "Master, they come...", "","","","","","","","Повелитель, они идут...",15593, 1, 0, 0, 'Kologarndeath'), +(-1603099,'The Right Arm has regrown!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_right hand'), +(-1603100,'The Left Arm has regrown!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_left hand'), +(-1603101,'Kologarn casts Stone Grip!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_stone grip'), + +-- Auriaya: +(-1603110,"Some things are better left alone!","","","","","","","","Вы зря сюда заявились!",15473,1,0,0,"auriaya aggro"), +(-1603112,"The secret dies with you!","","","","","","","","Эта тайна умрет вместе с тобой!",15474,1,0,0,"auriaya Slay 1"), +(-1603111,"There is no escape!","","","","","","","","Спасения нет!",15475,1,0,0,"auriaya Slay 2"), +(-1603113,"You waste my time!","","","","","","","","Вы попусту тратите мое время!",15477,1,0,0,"auriaya berserk"), +(-1603114,"Auriaya screams in agony.","","","","","","","","Ааааааааааааааааааааа!",15476,2,0,0,"auriaya death"), +(-1603115,'Auriaya begins to cast Terrifying Screech.' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_screech'), +(-1603116,'Auriaya begins to activate the Feral Defender!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_defender'), + +-- Hodir +(-1603120,"","","","","","","","","",15556,2,0,0,"Hodir Frozen Blows"), +(-1603121,"Winds of the north consume you!","","","","","","","","Да поглотят вас северные ветры!",15555,1,0,0,"Hodir Flash Freeze"), +(-1603122,"Welcome to the endless winter.","","","","","","","","Отправляйся туда, где вечная зима.",15554,1,0,0,"Hodir Slay 2"), +(-1603123,"Tragic. To come so far, only to fail.","","","","","","","","Как трагично. Проделать такой путь, чтобы умереть.",15553,1,0,0,"Hodir Slay 1"), +(-1603124,"I... I am released from his grasp... at last.","","","","","","","","Наконецто... Я... Свободен... От его оков.",15557,1,0,0,"Hodir Death"), +(-1603125,"You will suffer for this trespass!","","","","","","","","Вы будете наказаны за это вторжение!",15552,1,0,0,"Hodir Aggro"), +(-1603126,"The veil of winter will protect you, champions!","","","","","","","","Герои, вас защитит покров зимы!",15559,1,0,0,"Hodir yogg"), +(-1603127,"Enough! This ends now!","","","","","","","","Ну хватит! Больше вам не жить!",15558,1,0,0,"Hodir berserk"), +(-1603128,'Hodir begins to cast Flash Freeze!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_flash freeze'), +(-1603129,'Hodir gains Frozen Blows!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_frozen blows'), +-- (-1603130,????????????????,'EMOTE_SPEEDKILL'), + +-- Freya: +(-1603140,"The Conservatory must be protected!","","","","","","","","Нужно защитить оранжерею!",15526,1,0,0,"freya aggro"), +(-1603141,"Elders, grant me your strength!","","","","","","","","Древние, дайте мне силы!",15527,1,0,0,"freya aggro hard"), +(-1603142,"Eonar, your servant requires aid!","","","","","","","","Эонар, твоей прислужнице нужна помощь!",15528,1,0,0,"summon conservator"), +(-1603143,"Children, assist me!","","","","","","","","Помогите мне, дети мои!",15533,1,0,0,"summon trio"), +(-1603144,"The swarm of the elements shall overtake you!","","","","","","","","Вас захлестнет сила стихий!",15534,1,0,0,"summon lashers"), +(-1603145,"Forgive me.","","","","","","","","Прости меня.",15529,1,0,0,"freya slay1"), +(-1603146,"From your death springs life anew!","","","","","","","","Твоя смерть даст начало новой жизни!",15530,1,0,0,"freya slay2"), +(-1603147,"His hold on me dissipates. I can see clearly once more. Thank you, heroes.","","","","","","","","Он больше не властен надо мной. Мой взор снова ясен. Благадорю вас, герои.",15531,1,0,0,"freya Death"), +(-1603148,"You have strayed too far, wasted too much time!","","","","","","","","Вы проделали весь этот путь, впустую!",15532,1,0,0,"freya berserk"), +(-1603149,"Eonar, your servant calls for your blessing!","","","","","","","","Эонар, прошу тебя даруй свое благословение!",15535,1,0,0,"freya yogg"), + +-- Brightleaf +(-1603160,"Matron, the Conservatory has been breached!","","","","","","","","",15483,1,0,0,"brightleaf aggro"), +(-1603161,"Fertilizer.","","","","","","","","",15485,1,0,0,"brightleaf slay1"), +(-1603162,"Your corpse will nourish the soil!","","","","","","","","",15486,1,0,0,"brightleaf slay2"), +(-1603163,"Matron, one has fallen!","","","","","","","","",15487,1,0,0,"brightleaf dead"), +-- Ironbranch +(-1603170,"Mortals have no place here!","","","","","","","","",15493,1,0,0,"ironbranch aggro"), +(-1603171,"I return you whence you came!","","","","","","","","",15494,1,0,0,"ironbranch slay1"), +(-1603172,"BEGONE!","","","","","","","","",15495,1,0,0,"ironbranch slay2"), +(-1603173,"Freya! They come for you.","","","","","","","","",15496,1,0,0,"summon trio"), +-- Stonebark +(-1603180,"This place will serve as your graveyard.","","","","","","","","",15500,1,0,0,"stonebark aggro"), +(-1603181,"","","","","","","","","",15501,1,0,0,"stonebark slay1"), +(-1603182,"Such a waste.","","","","","","","","",15502,1,0,0,"stonebark slay2"), +(-1603183,"Matron, flee! They are ruthless....","","","","","","","","",15503,1,0,0,"stonebark death"), + +-- Leviathan: needs intro & outro +(-1603002,"Threat assessment routine modified. Current target threat level: zero. Acquiring new target.","","","","","","","","Изменение в протоколе оценки угрозы. Уровень угрозы текущей цели: нулевой. Поиск новой цели.",15521,1,0,0,"Flame Leviathan Slay"), +(-1603003,"Total systems failure. Defense protocols breached. Leviathan Unit shutting down.","","","","","","","","Общий системный сбой. Отказ защитных протоколов. Боевая единица Левиафан завершает свою работу.",15520,1,0,0,"Flame Leviathan Death"), +(-1603004,"Hostile entities detected. Threat assessment protocol active. Primary target engaged. Time minus thirty seconds to re-evaluation.","","","","","","","","Обнаружены противники. Запуск протокола оценки угрозы. Главная цель выявлена. Повторный анализ через тридцать секунд.",15506,1,0,0,"Flame Leviathan Aggro"), +(-1603005,"Threat re-evaluated. Target assessment complete. Changing course.","","","","","","","","Повторный анализ угрозы - завершен. Оценка цели - проведена. Смена курса.",15507,1,0,0,"Flame Leviathan change1"), +(-1603006,"Pursuit objective modified. Changing course.","","","","","","","","Изменение цели преследования. Смена курса.",15508,1,0,0,"Flame Leviathan change2"), +(-1603007,"Hostile entity stratagem predicted. Rerouting battle function. Changing course.","","","","","","","","Вражеский маневр предупрежден. Перерасчет параметра боевых функций. Смена курса.",15509,1,0,0,"Flame Leviathan change3"), +(-1603008,"Unauthorized entity attempting circuit overload. Activating anti-personnel countermeasures.","","","","","","","","Несанкционированное вмешательство в работу. Активация системы подавления живой силы.",15516,1,0,0,"Flame Leviathan player on top"), +(-1603009,"System malfunction. Diverting power to support systems.","","","","","","","","Функциональный сбой. Активация резервных систем.",15517,1,0,0,"Flame Leviathan overload1"), +(-1603010,"Combat matrix overload. Powering do-o-o-own...","","","","","","","","Боевая матрица перегружена. Отключи....",15518,1,0,0,"Flame Leviathan overload2"), +(-1603011,"System restart required. Deactivating weapon systems.","","","","","","","","Требуется перезапуск. Отключение систем вооружения.",15519,1,0,0,"Flame Leviathan overload3"), +(-1603012,"Orbital countermeasures enabled.","","","","","","","","Система орбитального подавления - включена.",15510,1,0,0,"Flame Leviathan hard mode"), +(-1603013,"Alert! Static defense system failure. Orbital countermeasures disabled.","","","","","","","","Тревога! Сбой стационарных средств защиты. Система орбитального подавления - отключена.",15511,1,0,0,"Flame Leviathan towers down"), +(-1603014,"'Hodir's Fury' online. Acquiring target.","","","","","","","","Ярость Ходира - активирована. Поиск цели.",15512,1,0,0,"Flame Leviathan frost"), +(-1603015,"'Mimiron's Inferno' online. Acquiring target.","","","","","","","","Адский огонь Мимирона - активировано. Поиск цели.",15513,1,0,0,"Flame Leviathan fire"), +(-1603016,"'Thorim's Hammer' online. Acquiring target.","","","","","","","","Молот Торима - активирован. Поиск цели.",15515,1,0,0,"Flame Leviathan energy"), +(-1603017,"'Freya's Ward' online. Acquiring target.","","","","","","","","Оберег Фреи - активировано. Поиск цели.",15514,1,0,0,"Flame Leviathan nature"), +(-1603018,'PursueWarn' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_pursue'), + +-- Thorim: +(-1603190,"Interlopers! You mortals who dare to interfere with my sport will pay... Wait--you...","","","","","","","","",15733,1,0,0,"thorim aggro 1"), +(-1603191,"I remember you... In the mountains... But you... what is this? Where am--","","","","","","","","",15734,1,0,0,"thorim aggro 2"), +(-1603192,"Behold the power of the storms and despair!","","","","","","","","",15735,1,0,0,"thorim special 1"), +(-1603193,"Do not hold back! Destroy them!","","","","","","","","",15736,1,0,0,"thorim special 2"), +(-1603194,"Have you begun to regret your intrusion?","","","","","","","","",15737,1,0,0,"thorim special 3"), +(-1603195,"Impertinent whelps! You dare challenge me atop my pedestal! I will crush you myself!","","","","","","","","",15738,1,0,0,"thorim jump"), +(-1603196,"Can't you at least put up a fight!?","","","","","","","","",15739,1,0,0,"thorim slay1"), +(-1603197,"Pathetic!","","","","","","","","",15740,1,0,0,"thorim slay2"), +(-1603198,"My patience has reached its limit!","","","","","","","","",15741,1,0,0,"Thorim berserk"), +(-1603199,"Failures! Weaklings!","","","","","","","","",15742,1,0,0,"thorim arena wipe"), +(-1603200,"Stay your arms! I yield!","","","","","","","","",15743,1,0,0,"thorim defeat"), +(-1603201,"I feel as though I am awakening from a nightmare, but the shadows in this place yet linger.","","","","","","","","",15744,1,0,0,"thorim outro n1"), +(-1603202,"Sif... was Sif here? Impossible--she died by my brother's hand. A dark nightmare indeed....","","","","","","","","",15745,1,0,0,"thorim outro n2"), +(-1603203,"I need time to reflect.... I will aid your cause if you should require it. I owe you at least that much. Farewell.","","","","","","","","",15746,1,0,0,"thorim outro n3"), +(-1603204,"You! Fiend! You are not my beloved! Be gone!","","","","","","","","",15747,1,0,0,"thorim outro hard1"), +(-1603205,"Behold the hand behind all the evil that has befallen Ulduar! Left my kingdom in ruins, corrupted my brother and slain my wife!","","","","","","","","",15748,1,0,0,"thorim outro hard2"), +(-1603206,"And now it falls to you, champions, to avenge us all! The task before you is great, but I will lend you my aid as I am able. You must prevail!","","","","","","","","",15749,1,0,0,"thorim outro hard3"), +-- (-1603207,"Golganneth, lend me your strengh! Grant my mortal allies the power of thunder!","","","","","","","","",15750,1,0,0,"thorim yogg"), + +-- Sif: +(-1603210,"Thorim, my lord, why else would these invaders have come into your sanctum but to slay you? They must be stopped!","","","","","","","","",15668,1,0,0,"sif start"), +(-1603211,"Impossible! Lord Thorim, I will bring your foes a frigid death!","","","","","","","","",15670,1,0,0,"sif event"), +(-1603212,"These pathetic mortals are harmless, beneath my station. Dispose of them!","","","","","","","","",15669,1,0,0,"sif despawn"), +-- (-1603213,'Runic Colossus surrounds itself with a crackling Runic Barrier!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_barrier'), +-- (-1603214,'Ancient Rune Giant fortifies nearby allies with runic might!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_barrier'), + +-- Mimiron: +(-1603220,"Oh, my! I wasn't expecting company! The workshop is such a mess! How embarrassing!","","","","","","","","Вот те на! Я не ждал гостей! Тут везде такой безпорядок! Как не ловко!",15611,1,0,0,"mimiron aggro"), +(-1603221,"Now why would you go and do something like that? Didn't you see the sign that said 'DO NOT PUSH THIS BUTTON!'? How will we finish testing with the self-destruct mechanism active?","","","","","","","","Так, зачем вы это сделали? Разве вы не видели табличку 'НЕ НАЖИМАЙТЕ ЭТУ КНОПКУ!'? Ну как мы сумеем завершить испытания при включенном механизме самоликвидации, ааа?",15629,1,0,0,"mimiron hard mode"), +(-1603222,"Oh, my! It would seem that we are out of time, my friends!","","","","","","","","Ааа! Очевидно наше время истекло, друзья мои!",15628,1,0,0,"mimiron berserk"), +(-1603223,"We haven't much time, friends! You're going to help me test out my latest and greatest creation. Now, before you change your minds, remember, that you kind of owe it to me after the mess you made with the XT-002.","","","","","","","","У нас мало времени, друзья! Вы поможете испытать новейшие и величайшие из моих изобретений, и учтите, после того что вы натворили с ХТ002, отказыватся просто не красиво.",15612,1,0,0,"tank active"), +(-1603224,"MEDIC!","","","","","","","","ДОКТОРА!",15613,1,0,0,"tank kill1"), +(-1603225,"I can fix that... or, maybe not! Sheesh, what a mess...","","","","","","","","Я могу починить это... а может и не могу! Ну и бардак...",15614,1,0,0,"tank kill2"), +(-1603226,"WONDERFUL! Positively marvelous results! Hull integrity at 98.9 percent! Barely a dent! Moving right along.","","","","","","","","Превосходно! Просто восхитительный результат! Целостность обшивки 98.9 процента! Почти что не царапинки! Продолжаем.",15615,1,0,0,"tank dead"), +(-1603227,"Behold the VX-001 Anti-personnel Assault Cannon! You might want to take cover.","","","","","","","","Представляю вам противопехотную штормовую пушку - VX-001! советую поискать укрытие.",15616,1,0,0,"torso active"), +(-1603228,"Fascinating. I think they call that a 'clean kill'.","","","","","","","","Потрясающе. Помоему это называется 'Прямо в яблочко'.",15617,1,0,0,"torso kill1"), +(-1603229,"Note to self: Cannon highly effective against flesh.","","","","","","","","Надо запомнить: Пушка крайне эффективна против созданий из плоти и крови.",15618,1,0,0,"torso kill2"), +(-1603230,"Thank you, friends! Your efforts have yielded some fantastic data! Now, where did I put-- oh, there it is!","","","","","","","","Спасибо друзья! Благодаря вам я получил ценнейшие сведения! Так, куда же я дел... ах, вот куда!",15619,1,0,0,"torso dead"), +(-1603231,"Isn't it beautiful? I call it the magnificent aerial command unit!","","","","","","","","Ха! Ха! Ха! Ха! Красота правда? Я называю это непревзойденной воздушной боевой единицей!",15620,1,0,0,"head active"), +(-1603232,"Outplayed!","","","","","","","","Обхитрил!",15621,1,0,0,"head kill1"), +(-1603233,"You can do better than that!","","","","","","","","Плохо стараешся!",15622,1,0,0,"head kill2"), +(-1603234,"Preliminary testing phase complete. Now comes the true test!!","","","","","","","","Фаза предварительной проверки завершена. Пора начать главный тест! Ха! Ха! Ха! Ха!",15623,1,0,0,"head defeat"), +(-1603235,"Gaze upon its magnificence! Bask in its glorious, um, glory! I present you... V-07-TR-0N!","","","","","","","","Насладитесь его великолепием! Грейтесь в его сияющем, эмм, сиянии! Перед вами потрясающий - V-07-ДР-ОН",15624,1,0,0,"robot active"), +(-1603236,"Prognosis: Negative!","","","","","","","","Прогноз: Негативный!",15625,1,0,0,"robot kill1"), +(-1603237,"You're not going to get up from that one, friend.","","","","","","","","От этого тебе не оправится, дружок.",15626,1,0,0,"robot kill2"), +(-1603238,"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,"robot defeat"), +-- (-1603239,"Combat matrix enhanced. Behold wonderous rapidity!","","","","","","","","Боевая матрица разширена. Оо, какая невероятная скорость!",15630,1,0,0,"mimiron yogg"), +(-1603240,"Leviathan Mk II begins to cast Plasma Blast!" ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_plasma_blast'), +-- (-1606241,"Self-destruct sequence initiated.","","","","","","","","Отсчет времени до самоуничтожения начат.",15413,1,0,0,""), +-- (-1606242,"This area will self-destruct in ten minutes.","","","","","","","","Самоуничтожение области через десять минут.",15415,1,0,0,"mimiron "), +-- (-1606243,"This area will self-destruct in nine minutes.","","","","","","","","Самоуничтожение области через девять минут.",15416,1,0,0,"mimiron "), +-- (-1606244,"This area will self-destruct in eight minutes.","","","","","","","","Самоуничтожение области через восемь минут.",15417,1,0,0,"mimiron "), +-- (-1606245,"This area will self-destruct in seven minutes.","","","","","","","","Самоуничтожение области через семь минут.",15418,1,0,0,"mimiron "), +-- (-1606246,"This area will self-destruct in six minutes.","","","","","","","","Самоуничтожение области через шесть минут.",15419,1,0,0,"mimiron "), +-- (-1606247,"This area will self-destruct in five minutes.","","","","","","","","Самоуничтожение области через пять минут.",15420,1,0,0,"mimiron "), +-- (-1606248,"This area will self-destruct in four minutes.","","","","","","","","Самоуничтожение области через четыре минуты.",15421,1,0,0,"mimiron "), +-- (-1606249,"This area will self-destruct in three minutes.","","","","","","","","Самоуничтожение области через три минуты.",15422,1,0,0,"mimiron "), +-- (-1606250,"This area will self-destruct in two minutes.","","","","","","","","Самоуничтожение области через две минуты.",15423,1,0,0,"mimiron "), +-- (-1606251,"This area will self-destruct in one minute.","","","","","","","","Самоуничтожение области через одну минуту.",15424,1,0,0,"mimiron "), +-- (-1606252,"The self-destruction timer is over. Have a nice day.","","","","","","","","Отсчет времени до самоуничтожения завершен. Всего хорошего.",15425,1,0,0,"mimiron "), +-- (-1606253,"The self-destruction timer canceled. Exit code A905.","","","","","","","","Отсчет времени до самоуничтожения прерван. Код отмены А905.",15414,1,0,0,"mimiron "), + +-- vezax +(-1603350,'Your destruction will herald a new age of suffering!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Ваша смерть возвестит новую эру страданий!",15542,1,0,0,'vezax aggro'), +(-1603351,'You thought to stand before the legions of death... and survive?',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Тебе не выстоять перед легионом смерти...",15543,1,0,0,'vezax kill1'), +(-1603352,'Defiance... a flaw of mortality.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Неповиновение... Ха, ха, ха, ха, это слабость смертных.",15544,1,0,0,'vezax kill2'), +(-1603353,'The black blood of Yogg-Saron courses through me! I. AM. UNSTOPPABLE!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Во мне течет черная кровь Йогг-Сарона! Меня не остановить!",15545,1,0,0,'vezaz surge'), +(-1603354,'Oh, what horrors await....',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Ха! Ха! Ха! Ха... Какие ужасы вас ожидают...",15546,1,0,0,'vezax death'), +(-1603355,'Your defeat was inevitable!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Ваше поражение, было неизбежно!",15547,1,0,0,'vezax enrage'), +(-1603356,'Behold, now! Terror, absolute!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Познайте, же! Абсолютный, ужас!",15548,1,0,0,'vezax hard'), +(-1603357,'A cloud of saronite vapors coalesces nearby!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_vapors'), +(-1603358,'General Vezax roars and surges with dark might!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_surge'), +(-1603359,'The saronite vapors mass and swirl violently, merging into a monstrous form!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_animus'), + +-- Yogg: +-- Sara: +(-1603360,'The time to strike at the head of the beast will soon be upon us! Focus your anger and hatred on his minions!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Скоро мы сразимся с главарем этих извергов! Обратите гнев и ненависть против его прислужников!",15775,1,0,0,'sara aggro'), +(-1603361,'Yes! YES! Show them no mercy! Give no pause to your attacks!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Да! ДА! Не щадите их! Бейте без промахов!",15773,1,0,0,'sara help1'), +(-1603362,'Let hatred and rage guide your blows!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Пусть ненависть и ярость направляют ваши удары!",15774,1,0,0,'sara help2'), +(-1603363,'Could they have been saved?',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Был ли у них шанс на спасение?",15779,1,0,0,'sara kill1'), +(-1603364,'Powerless to act...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Какое безсилие...",15778,1,0,0,'sara kill 1'), +(-1603365,'Suffocate upon your own hate!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Задохнитесь в собственной ненависти!",15776,1,0,0,'sara yell1 p1'), +(-1603366,'Tremble, mortals, before the coming of the end!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Трепищите, смертные, конец близок!",15777,1,0,0,'sara yell2 p2'), +(-1603367,'Aaaaaaaaaaaaaaaaa... Help me!!! Please got to help me!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Ааааааааа... На помощь! Помогите отделаться от них!",15771,1,0,0,'sara prefight'), +(-1603368,'What do you want from me? Leave me alone!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Что вам нужно? Прочь от меня!",15772,1,0,0,'sara prefight2'), +(-1603369,'Weak-minded fools!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Вот тупица!",15780,4,0,0,'sara slay phase1'), + +-- Yogg: +(-1603370,'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!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Я... Это сон на яву. Чудовище из ваших кошмаров. Демон с тысячью лиц. Трепещите, ибо Я обретаю истинную форму. ПАДИТЕ ВНИЗ ПЕРЕД БОГОМ СМЕРТИ!",15754,1,0,0,'yogg p2 intro'), +(-1603371,'MADNESS WILL CONSUME YOU!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Безумие поглотит вас!",15756,1,0,0,'yogg vision'), +(-1603372,'Look upon the true face of death and know that your end comes soon!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Взгляните в истинное лицо смерти и знайте, что ваш конец близок!",15755,1,0,0,'yogg phase 3'), +(-1603373,'Hoohehehahahaha... AHAHAHAHAHAHA!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Уммхехехахахаха... ХАХАХАХАХАХАХАХА!",15757,1,0,0,'yogg slay1'), +(-1603374,'Eternal suffering awaits!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Впереди вечные страдания!",15758,1,0,0,'yogg slay2'), +(-1603375,'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.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Хахахахахаха! Вы обречены. Не вы, никто другой, не в силах избежать близящегося конца света. Ульви ифи Халаш гага вонг ущь.",15761,1,0,0,'yogg death'), +(-1603376,'Your will is no longer you own...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Вы теперь в моей власти...",15759,4,0,0,'yogg insanity1'), +(-1603377,'Destroy them minion, your master commands it!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Слуга убей их, исполни приказ хозяина!",15760,4,0,0,'yogg insanity2'), +(-1603378,'Portals open into Yogg-Saron\'s mind!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_vision_blast'), +(-1603379,'The illusion shatters and a path to the central chamber opens!' ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,3,0,0,'EMOTE_shatter_blast'), +-- Visions: +-- stormwind v1 +(-1603400,'Bad news sire. The clans are united under Blackhand in this assault. They will stand together until Stormwind has fallen.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15538,0,0,0,'v3 garona1'), +(-1603401,'Gul\'dan is bringing up his warlocks by nightfall. Until then, the Blackrock clan will be trying to take the Eastern Wall.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15539,0,0,0,'v3 garona2'), +(-1603402,'The orc leaders agree with your assessment.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'v3 garona3'), +-- (-1603403,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'v3 garona4'), +(-1603404,'A thousand deaths... ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15762,0,0,0,'v3 yogg1'), +(-1603405,'or one murder.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15763,0,0,0,'v3 yogg2'), +(-1603346,'Your petty quarrels only make me stronger!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15764,0,0,0,'v3 yogg3'), +(-1603347,'We will hold until the reinforcements come. As long as men with stout hearts are manning the walls and throne Stormwind will hold.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'v3 king llane1'), +-- dragons v2 +(-1603390,'It is done... All have been given that which must be given. I now seal the Dragon Soul forever...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15631,0,0,0,'v2 neltharion1'), +(-1603391,'That terrible glow... should that be?',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15784,0,0,0,'v2 ysera1'), +(-1603392,'For it to be as it must, yes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15632,0,0,0,'v2 neltharion2'), +(-1603393,'It is a weapon like no other. It must be like no other.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15610,0,0,0,'v2 malygos1'), +(-1603394,'His brood learned their lesson before too long, you shall soon learn yours!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15765,0,0,0,'v2 yogg1'), +-- lich king v3 +(-1603380,'Your resilience is admirable.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15598,0,0,0,'v1 lich king1'), +(-1603381,'Arrrrrrgh!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15470,1,0,0,'v1 champ1'), +(-1603382,'I\'m not afraid of you!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15471,0,0,0,'v1 champ2'), +(-1603383,'I will break you as I broke him.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15599,0,0,0,'v1 lich king2'), +(-1603384,'Yrr n\'lyeth... shuul anagg!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15766,0,0,0,'v1 yogg1'), +(-1603385,'He will learn... no king rules forever; only death is eternal!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,15767,0,0,0,'v1 yogg2'), +-- keepers yells +-- (-1603126,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'SAY_HODIR_ACTIVE'), +-- (-1603149,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'SAY_FREYA_ACTIVE'), +-- (-1603207,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'SAY_THORIM_ACTIVE'), +-- (-1603239,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0,'SAY_MIMIRON_ACTIVE'), + +-- Alagon: +(-1603250,'Your actions are illogical. All possible results for this encounter have been calculated. The pantheon will receive the observer\'s message regardless outcome.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Ваши действия не логичны. Все возможные исходы этой схватки просчитаны. Пантеон получит сообщение от наблюдателя в любом случае.",15386,1,0,0,'Agro_algalon the observer'), +(-1603251,'See your world through my eyes. A universe so vast as to be immeasurable. Incomprehensible even to your greatest minds.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Взгляните на мир моими глазами. Узрите необьятную вселенную. Непостежимую даже для величайших умов.",15390,1,0,0,'Engaged for the first time algalon'), +(-1603252,'Witness the fury of cosmos!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Космос покарает вас!",15396,1,0,0,'BIG BANG 1_Algalon'), +(-1603253,'Behold the tools of creation!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Узрите чудо созидания!",15397,1,0,0,'BIG BANG 2_Algalon\r\n'), +(-1603254,'Beware!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Берегитесь!",15391,1,0,0,'Phase2_algalon\r\n'), +(-1603255,'Loss of life, unavoidable.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Жизнь, не может быть вечной.",15387,1,0,0,'Killing a player_alagalon\r\n'), +(-1603256,'I do what I must.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Я делаю то, что должен.",15388,1,0,0,'killing a player2_algalon\r\n'), +(-1603257,'You are... out of time.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Ваше время... Вышло.",15394,1,0,0,'BERSEKER_ALGALON'), +(-1603258,'The stars come to my aid.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"Звезды помогут мне.",15392,1,0,0,'Summoning Collapsing Stars_Algalon1'), +(-1603259,'I lack the strength to transmit this signal. You must hurry. Find a place of power, close to the skies.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,"У меня нет сил, чтобы передать сигнал. Поторопитесь, найдите истоичник энергии. Ищите в небесах.",15403,1,0,0,'Summoning Collapsing Stars_Algalon2'), +(-1603260,"Trans-location complete. Commencing planetary analysis of Azeroth.","","","","","","","","Перемещение завершено. Запуск планитарного анализа Азерота.",15405,1,0,0,"Algalon intro1"), +(-1603261,"Stand back, mortals. I am not here to fight you.","","","","","","","","Смертные. Я здесь не для того, чтобы сражаться с вами.",15406,1,0,0,"Algalon intro2"), +(-1603262,"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 intro3"), +(-1603263,"Analysis complete. There is partial corruption in the plane's life-support systems as well as complete corruption in most of the planet's defense mechanisms.","","","","","","","","Анализ завершен. Система жизнеобеспечения планеты частично поражена, большинство защитных механизмов поражены полностью.",15398,1,0,0,"algalon despawn1"), +(-1603264,"Begin uplink: Reply Code: 'Omega'. Planetary re-origination requested.","","","","","","","","Выход на связь. Код отклика: 'Омега'. Запрос на пересоздание планеты.",15399,1,0,0,"algalon despawn 2"), +(-1603265,"Farewell, mortals. Your bravery is admirable, for such flawed creatures.","","","","","","","","Прощайте, смертные. Я восхищаюсь вашей отвагой, несовершенные существа.",15400,1,0,0,"algalon despwnd 3"), +(-1603266,"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 outro1"), +(-1603267,"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 outro 2"), +(-1603268,"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 outro 3"), +(-1603269,"Do not worry about my fate . If the signal is not transmitted in time re-origination will proceed regardless. Save. Your. World.","","","","","","","","",15404,1,0,0,"algalon outro 5"); +*/ +-- Archivum dialogue: TODO: +-- Brann +-- Archivum diff --git a/sql_mr/mr00544_mangos_grizzlyhills_quests.sql b/sql_mr/mr00544_mangos_grizzlyhills_quests.sql new file mode 100644 index 0000000000..e186d4bc11 --- /dev/null +++ b/sql_mr/mr00544_mangos_grizzlyhills_quests.sql @@ -0,0 +1,18 @@ +-- The Conquest Pit - Quests from Venom +REPLACE INTO `creature_ai_scripts` VALUES ('2771556', '27715', '6', '0', '100', '0', '0', '0', '0', '0', '26', '12427', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Quest Complete 12427'); +UPDATE `creature_template` SET `AIName` = 'EventAI' WHERE `entry` = '27715'; + +REPLACE INTO `creature_ai_scripts` VALUES ('2771656', '27716', '6', '0', '100', '0', '0', '0', '0', '0', '26', '12428', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Quest Complete 12428'); +UPDATE `creature_template` SET `AIName` = 'EventAI' WHERE `entry` = '27716'; + +REPLACE INTO `creature_ai_scripts` VALUES ('2771756', '27717', '6', '0', '100', '0', '0', '0', '0', '0', '26', '12429', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Quest Complete 12429'); +UPDATE `creature_template` SET `AIName` = 'EventAI' WHERE `entry` = '27717'; + +REPLACE INTO `creature_ai_scripts` VALUES ('2771856', '27718', '6', '0', '100', '0', '0', '0', '0', '0', '26', '12430', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Quest Complete 12430'); +UPDATE `creature_template` SET `AIName` = 'EventAI' WHERE `entry` = '27718'; + +REPLACE INTO `creature_ai_scripts` VALUES ('2772756', '27727', '6', '0', '100', '0', '0', '0', '0', '0', '26', '12431', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'Quest Complete 12431'); +UPDATE `creature_template` SET `AIName` = 'EventAI' WHERE `entry` = '27727'; + +UPDATE `creature_template` SET `FactionAlliance` = 14 WHERE `entry` = 27727; +UPDATE `creature_template` SET `FactionHorde` = 14 WHERE `entry` = 27727; \ No newline at end of file diff --git a/sql_mr/mr00544_mangos_zuldrak_quests.sql b/sql_mr/mr00544_mangos_zuldrak_quests.sql new file mode 100644 index 0000000000..585871e966 --- /dev/null +++ b/sql_mr/mr00544_mangos_zuldrak_quests.sql @@ -0,0 +1,178 @@ +-- Zul'Drak Arena (by koksneo) +-- Gurgthock (30007) +UPDATE `creature_template` SET `ScriptName` = "npc_gurgthock" WHERE `entry`=30007; +UPDATE `quest_template` SET `StartScript`=12932 WHERE `entry`=12932; +UPDATE `quest_template` SET `StartScript`=12954 WHERE `entry`=12954; +UPDATE `quest_template` SET `StartScript`=12933 WHERE `entry`=12933; +UPDATE `quest_template` SET `StartScript`=12935 WHERE `entry`=12935; +UPDATE `quest_template` SET `StartScript`=12936 WHERE `entry`=12936; +UPDATE `quest_template` SET `StartScript`=12948 WHERE `entry`=12948; + +-- support for quest chain The Amphitheater of Anguish(12932,12954,12933,12935,12936,12948) + +-- NPC YGGDRAS (30014) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = `MechanicImmuneMask`|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +AIName='EventAI' WHERE `entry`=30014; + +DELETE from creature_ai_scripts WHERE creature_id=30014; +INSERT into creature_ai_scripts VALUES +(3001400,30014,0,0,100,1,1000,1000,4000,4000,11,40504,1,0,0,0,0,0,0,0,0,0,'Yggdras- Cast cleave'), +(3001401,30014,0,0,100,1,2500,2500,6000,6000,11,57076,4,1,0,0,0,0,0,0,0,0,'Yggdras- Cast Corrode Flesh'), +(3001402,30014,6,0,100,0,0,0,0,0,11,55859,0,3,0,0,0,0,0,0,0,0,'Yggdras- Jormungar Spawn upon death'), +(3001403,30014,6,0,100,0,0,0,0,0,26,12932,0,0,0,0,0,0,0,0,0,0,'Yggdras- Complete Quest upon death'); + +-- NPC STINKBEARD (30017) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = `MechanicImmuneMask`|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +AIName='EventAI' WHERE `entry`=30017; + +DELETE from creature_ai_scripts WHERE creature_id=30017; +INSERT into creature_ai_scripts VALUES +(3001700,30017,0,0,100,0,100,100,0,0,11,55866,0,1,0,0,0,0,0,0,0,0,'Stinkbeard- Cast Thunderblade'), +(3001701,30017,0,0,100,1,1000,1000,4000,4000,11,15588,1,1,0,0,0,0,0,0,0,0,'Stinkbeard- Cast Thunderclap'), +(3001702,30017,0,0,100,1,3000,3000,4000,4000,11,55867,1,1,0,0,0,0,0,0,0,0,'Stinkbeard- Cast Stinkbeard'), +(3001703,30017,0,0,100,1,2000,2000,4000,4000,11,31389,1,1,0,0,0,0,0,0,0,0,'Stinkbeard- Cast Knock Back'), +(3001704,30017,2,0,100,0,30,0,0,0,11,50420,0,1,0,0,0,0,0,0,0,0,'Stinkbeard- Cast Enrage at 30% HP'), +(3001705,30017,6,0,100,0,0,0,0,0,26,12933,0,0,0,0,0,0,0,0,0,0,'Stinkbeard- Complete Quest upon death'); + +-- NPC AZ BARIN (30026) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = `MechanicImmuneMask`|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +AIName='EventAI' WHERE entry=30026; + +DELETE from creature_ai_scripts WHERE creature_id=30026; +INSERT into creature_ai_scripts VALUES +(3002600,30026,0,0,100,1,1000,1000,4000,4000,11,55912,0,3,0,0,0,0,0,0,0,0,'Az\'Barin-Cast Blast of Air'), +(3002601,30026,0,0,100,1,2000,2000,10000,10000,12,30045,1,0,0,0,0,0,0,0,0,0,'Az\'Barin-Summon Fiend of Air'), +(3002602,30026,6,0,100,0,0,0,0,0,26,12934,0,0,0,0,0,0,0,0,0,0,'Az\'Barin- Complete Quest upon death'); + +-- Fiend of air (30045) +UPDATE `creature_template` SET AIName='EventAI' WHERE entry=30045; + +DELETE from creature_ai_scripts WHERE creature_id=30045; +INSERT into creature_ai_scripts VALUES +(3004500,30045,0,0,100,1,1000,1000,5000,5000,11,55882,1,1,0,0,0,0,0,0,0,0,'Fiend of Air-Cast Orb of Storms'), +(3004501,30045,0,0,100,1,3000,3000,5000,5000,11,55881,1,1,0,0,0,0,0,0,0,0,'Fiend of Air-Cast Hurricane'); + +-- NPC DUKE SINGEN (30019) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = MechanicImmuneMask|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +`AIName`='EventAI' WHERE entry=30019; + +DELETE from creature_ai_scripts WHERE creature_id=30019; +INSERT into creature_ai_scripts VALUES +(3001900,30019,0,0,100,1,1000,1000,4000,4000,11,55916,1,1,0,0,0,0,0,0,0,0,'Duke Singen-Cast Magma Wave'), +(3001901,30019,0,0,100,1,2000,2000,10000,10000,12,30042,1,0,0,0,0,0,0,0,0,0,'Duke Singen -Summon Fiend of Fire'), +(3001902,30019,6,0,100,0,0,0,0,0,26,12934,0,0,0,0,0,0,0,0,0,0,'Duke Singen- Complete Quest upon death'); + +-- Fiend of Fire (30042) +UPDATE `creature_template` SET AIName='EventAI' WHERE entry=30042; + +DELETE from creature_ai_scripts WHERE creature_id=30042; +INSERT into creature_ai_scripts VALUES +(3004200,30042,0,0,100,1,1000,1000,5000,5000,11,55872,1,1,0,0,0,0,0,0,0,0,'Fiend of Fire-Cast Orb of Flame'); + +-- NPC ERATHIUS (30025) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = `MechanicImmuneMask`|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +AIName='EventAI' WHERE `entry`=30025; + +DELETE from creature_ai_scripts WHERE creature_id=30025; +INSERT into creature_ai_scripts VALUES +(3002500,30025,0,0,100,1,1000,1000,20000,20000,11,55918,1,7,0,0,0,0,0,0,0,0,'Erathius-Cast Shockwave'), +(3002501,30025,0,0,100,1,2000,2000,10000,10000,12,30043,1,0,0,0,0,0,0,0,0,0,'Erathius -Summon Fiend of Earth'), +(3002502,30025,6,0,100,0,0,0,0,0,26,12934,0,0,0,0,0,0,0,0,0,0,'Erathius- Complete Quest upon death'); + +-- Fiend of Earth (30043) +UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=30043; + +DELETE from creature_ai_scripts WHERE creature_id=30043; +INSERT into creature_ai_scripts VALUES +(3004300,30043,0,0,100,1,1000,1000,5000,5000,11,55887,1,1,0,0,0,0,0,0,0,0,'Fiend of Earth-Cast Boulder'); + +-- NPC GARGORAL (30024) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = MechanicImmuneMask|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +`AIName`='EventAI' WHERE entry=30024; + +DELETE from creature_ai_scripts WHERE creature_id=30024; +INSERT into creature_ai_scripts VALUES +(3002400,30024,0,0,100,1,1000,1000,5000,5000,11,55909,1,1,0,0,0,0,0,0,0,0,'Gargoral-Cast Crashing Wave'), +(3002401,30024,0,0,100,1,2000,2000,10000,10000,12,30044,1,0,0,0,0,0,0,0,0,0,'Gargoral -Summon Fiend of Water'), +(3002402,30024,6,0,100,0,0,0,0,0,26,12934,0,0,0,0,0,0,0,0,0,0,'Gargoral- Complete Quest upon death'); + +-- Fiend of Earth (30044) +UPDATE `creature_template` SET AIName='EventAI' WHERE `entry`=30044; + +DELETE from creature_ai_scripts WHERE creature_id=30044; +INSERT into creature_ai_scripts VALUES +(3004400,30044,0,0,100,1,1000,1000,5000,5000,11,55888,1,1,0,0,0,0,0,0,0,0,'Fiend of Water-Cast Orb of Water'); + +-- NPC ORINOKO (30020) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = MechanicImmuneMask|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +AIName='EventAI' WHERE entry=30020; + +DELETE from creature_ai_scripts WHERE creature_id=30020; +INSERT into creature_ai_scripts VALUES +(3002000,30020,0,0,100,1,1000,1000,40000,40000,11,26099,0,1,0,0,0,0,0,0,0,0,'Orinoko-Cast Battle shout'), +(3002001,30020,0,0,100,1,2000,2000,20000,20000,11,30044,1,7,0,0,0,0,0,0,0,0,'Orinoko-Cast Fishy Scent'), +(3002002,30020,0,0,100,1,22000,22000,20000,20000,12,30110,1,0,12,30110,1,0,12,30110,1,0,'Orinoko-Summon Hungry Penguins'), +(3002003,30020,0,0,100,1,22000,22000,20000,20000,12,30110,1,0,12,30110,1,0,12,30110,1,0,'Orinoko-Summon Hungry Penguins'), +(3002004,30020,2,0,100,0,50,0,0,0,12,30113,1,0,0,0,0,0,0,0,0,0,'Orinoko-Summon Whisker at 30% HP'), +(3002005,30020,6,0,100,0,0,0,0,0,26,12935,0,0,0,0,0,0,0,0,0,0,'Orinoko- Complete Quest upon death'); + +-- WHISKER (30113) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = MechanicImmuneMask|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +`AIName`='EventAI' WHERE `entry`=30113; + +DELETE from creature_ai_scripts WHERE creature_id=30113; +INSERT into creature_ai_scripts VALUES +(3011300,30113,0,0,100,1,1000,1000,4000,4000,11,50169,1,1,0,0,0,0,0,0,0,0,'Whisker-Cast Flipper Thwack'); + +-- Hungry PENGUIN (30110) +-- UPDATE `creature_template` SET faction_A=16, faction_H=16, minLevel=74, maxLevel=74, minhealth=1028, maxhealth= 1028, armor=4681, mindmg=440, maxdmg=560, attackpower=512, dmg_multiplier=4 WHERE entry=30110; + +-- NPC KORRAK (30023) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = MechanicImmuneMask|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +`AIName`='EventAI' WHERE `entry`=30023; + +DELETE from creature_ai_scripts WHERE creature_id=30023; +INSERT into creature_ai_scripts VALUES +(3002300,30023,0,0,100,1,1000,1000,4000,4000,11,24193,4,6,0,0,0,0,0,0,0,0,'Korrak- Cast Charge'), +(3002301,30023,0,0,100,1,2500,2500,5000,5000,11,30471,1,0,0,0,0,0,0,0,0,0,'Korrak- Cast Uppercut'), +(3002302,30023,0,0,100,1,4000,4000,20000,20000,11,42745,0,1,0,0,0,0,0,0,0,0,'Korrak- Cast Enrage'), +(3002303,30023,0,0,100,1,10000,10000,10000,10000,11,55948,0,1,0,0,0,0,0,0,0,0,'Korrak- Cast Grow'), +(3002304,30023,6,0,100,0,0,0,0,0,26,12936,0,0,0,0,0,0,0,0,0,0,'Korrak- Complete Quest upon death'); + + +-- NPC VLADOF THE BUTCHER (30022) +UPDATE `creature_template` SET +-- immune for movement imparing effects, silences etc. +`MechanicImmuneMask` = MechanicImmuneMask|1 |4 |16 |64 |256 |512 |1024 |2048 |65536 |131072 |33554432 , +AIName='EventAI' WHERE `entry`=30022; + +DELETE from creature_ai_scripts WHERE creature_id=30022; +INSERT into creature_ai_scripts VALUES +(3002200,30022,0,0,100,1,1000,1000,4000,4000,11,55973,4,6,0,0,0,0,0,0,0,0,'Vladof- Cast Blood Plauge'), +(3002201,30022,0,0,100,1,2500,2500,15000,15000,11,55974,1,1,0,0,0,0,0,0,0,0,'Vladof- Cast Blood boil'), +(3002202,30022,0,0,100,1,4000,4000,40000,40000,11,55975,0,1,0,0,0,0,0,0,0,0,'Vladof- Cast Hysteria'), +(3002203,30022,0,0,100,1,7000,7000,20000,20000,11,55976,4,6,0,0,0,0,0,0,0,0,'Vladof- Spell Deflection'), +(3002204,30022,0,0,100,1,14000,14000,20000,20000,11,55977,4,6,0,0,0,0,0,0,0,0,'Vladof- Cast Whirlwind'), +(3002305,30022,6,0,100,0,0,0,0,0,26,12948,0,0,0,0,0,0,0,0,0,0,'Vladof- Complete Quest upon death'), +(3002306,30022,0,0,100,0,100,100,0,0,11,50689,0,1,0,0,0,0,0,0,0,0,'Vladof- Cast Blood Presence'); + +INSERT IGNORE INTO creature_ai_scripts VALUES (3002403,30024,4,0,100,0,0,0,0,0,1,-1052,0,0,0,0,0,0,0,0,0,0,'Gargoral the Water Lord - Yell on Aggro'); +INSERT IGNORE INTO creature_ai_scripts VALUES (3002503,30025,4,0,100,0,0,0,0,0,1,-1053,0,0,0,0,0,0,0,0,0,0,'Erathius, King of Dirt - Yell on Aggro'); diff --git a/sql_mr/mr00545_mangos_ulduar_raid.sql b/sql_mr/mr00545_mangos_ulduar_raid.sql new file mode 100644 index 0000000000..80cf07d8da --- /dev/null +++ b/sql_mr/mr00545_mangos_ulduar_raid.sql @@ -0,0 +1,514 @@ +/* ULDUAR from Xfurry*/ +/* +-- --------------- -- +-- Flame Leviathan -- +-- --------------- -- +DELETE FROM `creature` WHERE `id` IN(33060, 33062, 33109); -- Loading vehicles by script +UPDATE `creature_template_addon` SET `auras` = '52455' WHERE `entry` IN(33060, 33109, 33062, 34045); -- Prevent vehicles auto regen health +UPDATE `creature_template` SET `ModelId2` = 28783 WHERE `entry` = 33189; -- Liquid Pyrite +UPDATE `creature_template_addon` SET `mount` = 0 WHERE `entry` = 33214; -- Mechanolift 304-A +UPDATE `creature_template` SET `UnitFlags` = 0, `MinLevel` = 80, `MaxLevel` = 80 WHERE `entry` = 33090; -- Pool of Tar + +UPDATE `creature_template` SET `ScriptName` = 'boss_flame_leviathan' WHERE `entry` = 33113; +UPDATE `creature` SET `position_x` = 432.09, `position_y` = -13.3, `position_z` = 409.9 WHERE `id` = 33113; +UPDATE `creature_template` SET `ScriptName` = 'npc_brann_bronzebeard' WHERE `entry` = 33579; +UPDATE `creature_template` SET `NpcFlags` = `NpcFlags` | 1 WHERE `entry` = 33579; +UPDATE `creature_template` SET `ScriptName` = 'mob_defense_turret' WHERE `entry` = 33142; +UPDATE `creature_template` SET `ScriptName` = 'mob_pool_of_tar' WHERE `entry` = 33090; +UPDATE `creature_template` SET `ScriptName` = 'mob_mechanolift' WHERE `entry` = 33214; +UPDATE `creature_template` SET `ScriptName` = 'mob_freyas_ward' WHERE `entry` = 33367; +UPDATE `creature_template` SET `ScriptName` = 'mob_hodirs_fury' WHERE `entry` = 33212; +UPDATE `creature_template` SET `ScriptName` = 'mob_mimiron_inferno' WHERE `entry` = 33370; +UPDATE `creature_template` SET `ScriptName` = 'mob_thorims_hammer' WHERE `entry` = 33365; +UPDATE `creature_template` SET `ScriptName` = 'mob_lorekeeper' WHERE `entry` = 33686; +UPDATE `creature_template` SET `FactionAlliance` = 1965, `FactionHorde` = 1965, `UnitFlags` = 2|33554432 WHERE `entry` IN (33370, 33365, 33212); +UPDATE `creature_template` SET `MovementTemplateId` = 0, `VehicleTemplateId` = 0, `UnitFlags` = `UnitFlags` | 4 WHERE `entry` = 33369; +UPDATE `creature_template` SET `InhabitType` = 4 WHERE `entry` IN (33366, 33369, 33364, 33108); + +DELETE FROM `spell_script_target` WHERE `entry` IN(62906, 62909, 62911, 62533); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(62906, 1, 33367), -- Freya's Ward +(62909, 1, 33370), -- Mimiron's Inferno +(62911, 1, 33365), -- Thorim's Hammer +(62533, 1, 33212); -- Hodir's Fury + +DELETE FROM `spell_script_target` WHERE `entry` IN(63295, 63294, 63292); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(63295, 1, 33367), -- Freya Dummy Green - Freya's Ward +(63294, 1, 33212), -- Freya Dummy Blue - Hodir's Fury +(63294, 1, 33365), -- Freya Dummy Blue - Thorim's Hammer +(63292, 1, 33370); -- Freya Dummy Yellow - Mimiron's Inferno + +-- ------------------------ -- +-- Ignis the Furnace Master -- +-- ------------------------ -- +UPDATE `creature_template` SET `MechanicImmuneMask` = `MechanicImmuneMask` &~ 33554596, `ScriptName` = 'boss_ignis' WHERE `entry` = 33118; +UPDATE `creature_template` SET `ScriptName` = 'mob_iron_construct' WHERE `entry` = 33121; +UPDATE `creature_template` SET `MinLevel` = 80, `MaxLevel` = 80, `Scale` = 0.5 WHERE `entry` = 33221; + +-- ---------- -- +-- Razorscale -- +-- ---------- -- +UPDATE `creature_template` SET `MechanicImmuneMask` = `MechanicImmuneMask` &~ 33554596, `ScriptName` = 'boss_razorscale' WHERE `entry` = 33186; +UPDATE `creature` SET `position_x` = 590.346741, `position_y` = -226.947647, `position_z` = 442.897583 WHERE `id` = 33186; + +UPDATE `creature_template` SET `FactionAlliance` = 35, `FactionHorde` = 35 WHERE `entry` IN(33287, 33816, 33259, 34257, 34256, 34255); -- Prevent combat with other bosses + +DELETE FROM `spell_script_target` WHERE `entry` IN(63524, 63657, 63658, 63659, 62505); +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(63524, 1, 33282), -- Harpoon Shot - Razorscale Harpoon Fire State +(63657, 1, 33282), -- Harpoon Shot - Razorscale Harpoon Fire State +(63658, 1, 33282), -- Harpoon Shot - Razorscale Harpoon Fire State +(63659, 1, 33282), -- Harpoon Shot - Razorscale Harpoon Fire State +(62505, 1, 33186); -- Harpoon Shot - Razorscale + +UPDATE `gameobject_template` SET `data3` = 180000, `ScriptName` = 'go_repair_harpoon' WHERE `entry` IN (194543, 194542, 194541, 194519); +-- only 2 harpoons for 10 man +UPDATE `gameobject` SET `spawnMask` = 2 WHERE `guid` IN (73595, 73592); +-- mole machines & adds +UPDATE `creature_template` SET `ScriptName` = 'mob_mole_machine' WHERE `entry` = 33245; +UPDATE `creature_template` SET `ScriptName` = 'mob_dark_rune_watcher' WHERE `entry` = 33453; +UPDATE `creature_template` SET `ScriptName` = 'mob_dark_rune_sentinel' WHERE `entry` = 33846; +UPDATE `creature_template` SET `ScriptName` = 'mob_dark_rune_guardian' WHERE `entry` = 33388; +UPDATE `creature_template` SET `ScriptName` = 'npc_expedition_commander' WHERE `entry` = 33210; +UPDATE `creature_template` SET `ScriptName` = 'mob_devouring_flame_target' WHERE `entry` = 34188; + +-- -------------------- -- +-- XT-002 Deconstructor -- +-- -------------------- -- +UPDATE `creature_template` SET `ScriptName` = 'boss_xt_002' WHERE `entry` = 33293; +UPDATE `creature_template` SET `scriptname` = 'mob_xtheart' WHERE `entry` = 33329; +UPDATE `creature_template` SET `ScriptName` = 'mob_pummeler' WHERE `entry` = 33344; +UPDATE `creature_template` SET `ScriptName` = 'npc_scrapbot' WHERE `entry` = 33343; +UPDATE `creature_template` SET `ScriptName` = 'mob_boombot' WHERE `entry` = 33346; +UPDATE `creature_template` SET `ScriptName` = 'mob_voidzone' WHERE `entry` = 34001; +UPDATE `creature_template` SET `ScriptName` = 'mob_lifespark', `MinLevelHealth` = 176400, `MaxLevelHealth` = 176400, `FactionAlliance` = 14, `FactionHorde` = 14 WHERE `entry` = 34004; +DELETE FROM `creature` WHERE `id` = 34004; +UPDATE `creature` SET `spawnMask` = 3 WHERE `id` = 33337; -- XT-Toy Pile + +-- ---------------- -- +-- Assembly of Iron -- +-- ---------------- -- +UPDATE `creature_template` SET `MechanicImmuneMask` = `MechanicImmuneMask` &~ 33554432 &~ 128 &~ 32 &~ 4 WHERE `entry` IN(32927, 32867); +UPDATE `creature_template` SET `ScriptName` = 'npc_ulduar_lightning_elemental' WHERE `entry` = 32958; +UPDATE `creature_template` SET `MechanicImmuneMask` = +536870912|67108864|8388608|4194304|2097152|524288|131072|65536|8192|4096|2048|1024|512|256|128|64|32|16|8|2|1 +WHERE `entry` IN (32857, 33694); -- 619397115 +UPDATE `creature_template` SET `UnitFlags` = 33554432 | 2 WHERE `entry` IN (33051, 33705); + +-- LOOT FOR THESE THREE SHOUDL BE PROGRESSIVE, MAYBE THIS IS NOT THE RIGHT WAY TO DO IT +-- update loot id: +-- brundir +UPDATE `creature_template` SET `LootId` = 32857 WHERE `entry` = 32857; +UPDATE `creature_template` SET `LootId` = 33694 WHERE `entry` = 33694; +-- molgeim = steelbreaker (I dont know exactly which items are missing from molgeim's loot so i'm leaving it the same for now); +UPDATE `creature_template` SET `LootId` = 32867 WHERE `entry` = 32927; +UPDATE `creature_template` SET `LootId` = 33693 WHERE `entry` = 33692; +-- Rewrite loot for council: this will allow us to use hard mode loot because only the last killed boss will be lootable +-- 10 man version +-- Brundir: +DELETE FROM `creature_loot_template` WHERE `entry` = 32857; +INSERT INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(32857, 45322, 0, 2, 1, 1), +(32857, 45324, 0, 1, 1, 1), +(32857, 45329, 0, 2, 1, 1), +(32857, 45330, 0, 1, 1, 1), +(32857, 45331, 0, 2, 1, 1), +(32857, 45332, 0, 1, 1, 1), +(32857, 45333, 0, 2, 1, 1), +(32857, 45378, 0, 2, 1, 1), +(32857, 45418, 0, 1, 1, 1), +(32857, 45423, 0, 1, 1, 1), +-- emblem 100% drop +(32857, 47241, 100, 0, 1, 1); +-- 25 man version +-- Brundir: +DELETE FROM `creature_loot_template` WHERE `entry` = 33694; +INSERT INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(33694, 45224, 0, 3, 1, 1), +(33694, 45228, 0, 3, 1, 1), +(33694, 45233, 0, 3, 1, 1), +(33694, 45234, 0, 3, 1, 1), +(33694, 45236, 0, 3, 1, 1), +(33694, 45226, 0, 2, 1, 1), +(33694, 45235, 0, 2, 1, 1), +(33694, 45237, 0, 2, 1, 1), +(33694, 45238, 0, 2, 1, 1), +(33694, 45239, 0, 2, 1, 1), +(33694, 45193, 0, 1, 1, 1), +(33694, 45225, 0, 1, 1, 1), +(33694, 45227, 0, 1, 1, 1), +(33694, 45232, 0, 1, 1, 1), +(33694, 45240, 0, 1, 1, 1), +(33694, 45038, 10, 0, 1, 1), +(33694, 45087, 33, 0, 1, 2), +(33694, 45089, 5, 0, -45089, 1), +-- emblem 100% drop +(33694, 47241, 100, 0, 1, 1); + +-- -------- -- +-- Kologarn -- +-- -------- -- +UPDATE `creature_template` SET `MechanicImmuneMask` = 617299803, `ScriptName` = 'boss_kologarn', `UnitFlags` = 0 WHERE `entry` = 32930; +UPDATE `creature_template` SET `MechanicImmuneMask` = 652951551, `ScriptName` = 'boss_right_arm' WHERE `entry` = 32934; +UPDATE `creature_template` SET `MechanicImmuneMask` = 652951551, `ScriptName` = 'boss_left_arm' WHERE `entry` = 32933; +UPDATE `creature_template` SET `ScriptName` = 'mob_ulduar_rubble' WHERE `entry` IN (33768, 33809); + +DELETE FROM `creature` WHERE id IN (32933, 32934); -- Arms spawn by vehicle +DELETE FROM `creature` WHERE id IN (33632, 33802); -- Triggers spawn by Spell +UPDATE `creature` SET `position_x` = 1797, `position_z` = 449.718 WHERE `id` = 32930; -- Kologarn position +UPDATE `gameobject` SET `position_y` = -35.6824, `position_x` = 1837.59 WHERE `id` = 195047; -- loot box position + +DELETE FROM `spell_script_target` WHERE `entry` = 63628; +INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(63628, 1, 32933), -- Instakill Kologarn Arm - Left Arm +(63628, 1, 32934); -- Instakill Kologarn Arm - Right Arm + +UPDATE `creature_model_info` SET `bounding_radius` = 0.31, `combat_reach` = 20 WHERE `modelid` IN (28821, 28822); + +UPDATE `creature_template_addon` SET `bytes1` = 7 WHERE `entry` = 34297; -- Dummy death Kologarn +UPDATE `creature` SET `spawnMask` = 3 WHERE `id` = 33661; +UPDATE `spell_script_target` SET `targetentry` = 32930 WHERE `entry` = 63979; + + +-- Auriaya +UPDATE `creature_template` SET `ScriptName` = 'boss_auriaya', `MechanicImmuneMask` = 583745371, `EquipmentTemplateId` = 103000 WHERE `entry` = 33515; +UPDATE `creature_template` SET `ScriptName` = 'mob_feral_defender', `MechanicImmuneMask` = 619395071 WHERE `entry` = 34035; +UPDATE `creature_template` SET `ScriptName` = 'mob_seeping_feral_essence', `MinLevel` = 80, `MaxLevel` = 80, `FactionHorde` = 14, `FactionAlliance` = 14 WHERE `entry` = 34098; +UPDATE creature_template SET ScriptName = 'mob_sanctum_sentry' WHERE entry = 34014; +UPDATE `creature_template` SET `MechanicImmuneMask` = 619397115 WHERE `entry` IN (33515, 34175); +DELETE FROM creature_equip_template WHERE entry = 103000; +INSERT INTO creature_equip_template values (103000, 45315, 0, 0); +-- 2 more defenders for 25 man +DELETE FROM creature WHERE guid IN (800010, 800011); +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(800010, 34014, 603, 2, 65535, 0, 0, 1945.2, 37.2442, 411.356, 3.62107, 7200, 0, 0, 334680, 0, 0, 0), +(800011, 34014, 603, 2, 65535, 0, 0, 1936.11, 49.8233, 411.352, 3.85276, 7200, 0, 0, 334680, 0, 0, 0); + + +DELETE FROM `creature_movement` WHERE `id`=94378; +INSERT INTO `creature_movement` (`id`,`point`,`position_x`,`position_y`,`position_z`,`waittime`,`textid1`,`textid2`,`textid3`,`textid4`,`textid5`,`emote`,`spell`,`wpguid`,`orientation`,`model1`,`model2`) VALUES +-- UPDATED CREATURE MOVEMENT FOR AURIAYA, SHOULD MOVE AROUND THE CENTER SPIRE +#(94378, 4, 1916.56, -69.9669, 417.718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.2268, 0, 0), -- after hodir up +#(94378, 3, 1900.26, -24.0211, 417.722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.15909, 0, 0), -- center kolgoran +#(94378, 2, 1916.97, 21.1583, 417.748, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.86988, 0, 0), -- before yogg up + +(94378, 1, 1925.012, 30.0067, 411.356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.69685, 0, 0), -- before yogg down +(94378, 2, 1957.04, 49.3067, 411.355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.37071, 0, 0), -- after yogg down +(94378, 3, 1967.38, 51.4931, 417.561, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09545, 0, 0), -- after yogg up +(94378, 4, 2013.07, 44.3788, 417.715, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.71365, 0, 0), -- before mimiron up +(94378, 5, 2021.35, 37.9771, 411.387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.25205, 0, 0), -- before mimiron down +(94378, 6, 2046.36, 8.56725, 411.524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.203, 0, 0), -- after mimiron down +(94378, 7, 2053.32, -7.1366, 421.78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.85107, 0, 0), -- before freya up +(94378, 8, 2052.87, -40.8556, 421.706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.4223, 0, 0), -- after freya up +(94378, 9, 2045.00, -56.79369, 411.359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.20538, 0, 0), -- before thorim down +(94378, 10, 2022.18, -86.5468, 411.355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.60096, 0, 0), -- after thorim down +(94378, 11, 2012.94, -92.7106, 417.717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.28968, 0, 0), -- after thorim up +(94378, 12, 1968.83, -101.0946, 417.722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.662873, 0, 0),-- before hodir up +(94378, 13, 1958.08, -96.7855, 411.864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.763719, 0, 0), -- before hodir down +(94378, 14, 1924.12, -78.5404, 411.488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.210024, 0, 0), -- after hodir down + +(94378, 15, 1958.08, -96.7855, 411.864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.763719, 0, 0), -- before hodir down +(94378, 16, 1968.83, -101.0946, 417.722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.662873, 0, 0),-- before hodir up +(94378, 17, 2012.94, -92.7106, 417.717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.28968, 0, 0), -- after thorim up +(94378, 18, 2022.18, -86.5468, 411.355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.60096, 0, 0), -- after thorim down +(94378, 19, 2045.00, -56.79369, 411.359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.20538, 0, 0), -- before thorim down +(94378, 20, 2052.87, -40.8556, 421.706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.4223, 0, 0), -- after freya up +(94378, 21, 2053.32, -7.1366, 421.78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.85107, 0, 0), -- before freya up +(94378, 22, 2046.36, 8.56725, 411.524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.203, 0, 0), -- after mimiron down +(94378, 23, 2021.35, 37.9771, 411.387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.25205, 0, 0), -- before mimiron down +(94378, 24, 2013.07, 44.3788, 417.715, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.71365, 0, 0), -- before mimiron up +(94378, 25, 1967.38, 51.4931, 417.561, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09545, 0, 0), -- after yogg up +(94378, 26, 1957.04, 49.3067, 411.355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.37071, 0, 0); -- after yogg down + + +-- Freya +UPDATE creature_template SET ScriptName = 'boss_freya' WHERE entry = 32906; +UPDATE creature_template SET ScriptName = 'boss_elder_brightleaf' WHERE entry = 32915; +UPDATE creature_template SET ScriptName = 'boss_elder_ironbranch' WHERE entry = 32913; +UPDATE creature_template SET ScriptName = 'boss_elder_stonebark' WHERE entry = 32914; +UPDATE creature_template SET ScriptName = 'mob_iron_roots' WHERE entry IN (33088, 33168); +UPDATE creature_template SET ScriptName = 'mob_freya_ground' WHERE entry IN (33215, 33228, 33170, 33050, 34129); +UPDATE creature_template SET ScriptName = 'mob_freya_spawned' WHERE entry IN (32916, 32919, 33202, 33203, 32918); +-- some aura fixes, this may be wrong +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(62525, 1, 32906), +(62524, 1, 32906), +(62521, 1, 32906), +(62385, 1, 32906), +(62387, 1, 32906), +(62386, 1, 32906); + +-- Added hack for Freya's gift +DELETE FROM `gameobject` WHERE `id` IN (194324, 194325,194326,194327,194328,194329,194330,194331); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(733324, 194324, 603, 1, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733325, 194325, 603, 1, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733326, 194326, 603, 1, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733327, 194327, 603, 1, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733328, 194328, 603, 2, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733329, 194329, 603, 2, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733330, 194330, 603, 2, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1), +(733331, 194331, 603, 2, 65535, 2374.876221, -78.512665, 425.073608, 3.260976, 0, 0, 0.706026, 0.708186, -604800, 100, 1); +-- Delete bugged spell from mobs +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (33430,33732) AND `action1_param1` = 63007; + +-- Hodir +UPDATE creature_template SET ScriptName = 'boss_hodir' WHERE entry = 32845; +UPDATE creature_template SET ScriptName = 'mob_toasty_fire' WHERE entry = 33342; +UPDATE creature_template SET ScriptName = 'mob_flashFreeze' WHERE entry IN (32926); +UPDATE `creature_template` SET `ModelId1` = 15880 WHERE `entry` = 33174; +UPDATE `creature_template` SET `ModelId2` = 28470, ScriptName = 'mob_icicle' WHERE `entry` = 33169; +-- flash freeze that will lock the npcs IN iceblock +UPDATE creature_template SET `ModelId1` = 25865, ScriptName = 'mob_npc_flashFreeze' WHERE entry IN (32938); +UPDATE creature SET spawnMask = 3 WHERE id = 32938; +UPDATE creature SET spawnMask = 2 WHERE id IN (32901, 32900, 32950, 32946,33333, 33330, 33326); +UPDATE creature_template SET ScriptName = 'npc_hodir_helper' WHERE entry IN (32897, 33326, 32948, 33330); +UPDATE creature_template SET ScriptName = 'npc_hodir_helper' WHERE entry IN (33325, 32901, 32941, 33333); +UPDATE creature_template SET ScriptName = 'npc_hodir_helper' WHERE entry IN (33328, 32900, 33332, 32950); +UPDATE creature_template SET ScriptName = 'npc_hodir_helper' WHERE entry IN (32893, 33327, 33331, 32946); + +-- FIXED SOME POSITIONING FOR THE FRIENDLY NPCS, Besides this the freeze aura should also be fixed. +-- fixed npc positioning and added 4 extra flashfreeze for them. +-- 10 man: +-- mage +UPDATE creature SET position_x = 2000.9, position_y = -231.232 WHERE guid = 131930; +-- priest +UPDATE creature SET position_x = 2009.06, position_y = -244.058 WHERE guid = 131933; +DELETE FROM creature WHERE guid IN (800005); +INSERT INTO creature VALUES +(800005, 32897, 603, 3, 128,0,0, 2009.06, -244.058, 432.687, 1.68485, 7200,0,0, 5647, 0, 0, 0); -- aly priest +-- shaman +UPDATE creature SET position_x = 1983.75, position_y = -243.358 WHERE id = 33328; +UPDATE creature SET position_x = 1983.75, position_y = -243.358 WHERE id = 33332; +-- druid +UPDATE creature SET position_x = 2021.12, position_y = -236.648 WHERE id = 32941; +UPDATE creature SET position_x = 2021.12, position_y = -236.648 WHERE id = 33325; +-- 25 man: +-- druid +UPDATE creature SET position_x = 2013.5, position_y = -240.338 WHERE id = 32901; +DELETE FROM creature WHERE guid IN (800006); +INSERT INTO creature VALUES +(800006, 32938, 603, 2, 1,0,0, 2013.5, -240.338, 432.687, 1.68485, 7200,0,0, 5647, 0, 0, 0); +-- shaman: +UPDATE creature SET position_x = 2011.48, position_y = -232.79 WHERE id = 32900; +UPDATE creature SET position_x = 2011.48, position_y = -232.79 WHERE id = 32950; +DELETE FROM creature WHERE guid IN (800007); +INSERT INTO creature VALUES +(800007, 32938, 603, 2, 1,0,0, 2011.48, -232.79, 432.687, 1.68485, 7200,0,0, 5647, 0, 0, 0); +-- mage: +DELETE FROM creature WHERE guid IN (800008, 800010); +INSERT INTO creature VALUES +(800008, 33327, 603, 2, 128,0,0, 1978.49, -241.476, 432.687, 1.68485, 7200,0,0, 5647, 0, 0, 0), -- aly mage +(800010, 32938, 603, 2, 1,0,0, 1978.49, -241.476, 432.687, 1.68485, 7200,0,0, 5647, 0, 0, 0); +-- priest +UPDATE creature SET position_x = 1997.88, position_y = -239.394 WHERE id = 33330; +DELETE FROM creature WHERE guid IN (800009); +INSERT INTO creature VALUES +(800009, 32938, 603, 2, 1,0,0, 1997.88, -239.394, 432.687, 1.68485, 7200,0,0, 5647, 0, 0, 0); + +-- Mimiron +UPDATE `gameobject_template` SET `data0` = '60000' WHERE `entry` =194675; +UPDATE creature_template SET ScriptName = 'boss_mimiron' WHERE entry = 33350; +UPDATE creature_template SET `RegenerateStats`= 0, ScriptName = 'boss_leviathan_mk' WHERE entry = 33432; +UPDATE creature_template SET ScriptName = 'leviathan_turret' WHERE entry = 34071; +UPDATE creature_template SET ScriptName = 'mob_mimiron_flames' WHERE entry IN (34363, 34121); +UPDATE creature_template SET `RegenerateStats`= 0, ScriptName = 'boss_vx001' WHERE entry = 33651; +UPDATE creature_template SET `RegenerateStats`= 0, ScriptName = 'boss_aerial_command_unit' WHERE entry = 33670; +UPDATE creature SET position_x = 2784.35, position_y = 2578.03, orientation = 3.2 WHERE id = 33350; +UPDATE creature SET position_x = 2794.86, position_y = 2597.83, orientation = 3.57, spawnMask = 3 WHERE id = 33432; +UPDATE gameobject_template SET flags = 6553632, data2 = 2000, ScriptName='go_red_button' WHERE entry = 194739; +UPDATE creature_template SET ScriptName = 'mob_proximity_mine' WHERE entry = 34362; +UPDATE creature_template SET ScriptName = 'mob_bomb_bot' WHERE entry IN (33836, 34192); +UPDATE creature_template SET `FactionAlliance` = 14, `FactionHorde` = 14, `MinLevel` = 80, `MaxLevel` = 80, ScriptName = 'mob_emergency_bot' WHERE entry = 34147; +UPDATE creature_template SET ScriptName = 'mob_frost_bomb_ulduar' WHERE entry = 34149; +UPDATE creature_template SET ScriptName = 'mob_mimiron_inferno' WHERE entry = 33370; +UPDATE creature_template SET ScriptName = 'mob_assault_bot' WHERE entry = 34057; -- Script or EventAI ?? +UPDATE creature_template SET ScriptName = 'mob_magnetic_core' WHERE entry = 34068; +UPDATE `gameobject` SET `position_x` = 2734.73 WHERE `id` IN (194789, 194956); +-- spells, may not be correct +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(64444, 1, 33670), +(63414, 1, 33651), +(65101, 1, 33350); + +-- SOME MIMIRON LOOT BOXES ARE MISSING IN YTDB, THIS IS THE FIX FOR IT! +-- mimiron loot fix: +-- INSERT two new boxes +DELETE FROM `gameobject` WHERE `id` IN (194957, 194958); +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(110004, 194957, 603, 1, 65535, 2734.73, 2568.98, 364.314, 0.0139475, 0, 0, 0.00697369, 0.999976, -604800, 100, 1); +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(110005, 194958, 603, 2, 65535, 2734.73, 2568.98, 364.314, 0.0139475, 0, 0, 0.00697369, 0.999976, -604800, 100, 1); +-- 10 man hard: +DELETE FROM `gameobject_loot_template` WHERE (`entry`=194957); +INSERT INTO `gameobject_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(194957, 45089, 5, 0, -45089, 1), +(194957, 45095, 2.0408, 0, 1, 1), +(194957, 45649, 100, 0, -45649, 1), +(194957, 45663, 0.4028, 0, 1, 1), +(194957, 45787, -100, 0, 1, 1), +(194957, 47241, 100, 0, 1, 1), +(194957, 45972, 0, 1, 1, 1), +(194957, 45973, 0, 1, 1, 1), +(194957, 45974, 0, 1, 1, 1), +(194957, 45975, 0, 1, 1, 1), +(194957, 45976, 0, 1, 1, 1), +(194957, 45982, 0, 2, 1, 1), +(194957, 45988, 0, 2, 1, 1), +(194957, 45989, 0, 2, 1, 1), +(194957, 45990, 0, 2, 1, 1), +(194957, 45993, 0, 2, 1, 1); +-- 25 man hard: +DELETE FROM `gameobject_loot_template` WHERE (`entry`=194958); +INSERT INTO `gameobject_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(194958, 45038, 10, 0, 1, 1), +(194958, 45087, 33, 0, 1, 1), +(194958, 45089, 5, 0, -45089, 1), +(194958, 45643, 100, 0, -45643, 1), +(194958, 45816, -100, 0, 1, 1), +(194958, 47241, 100, 0, 1, 1), +(194958, 45489, 0, 1, 1, 1), +(194958, 45490, 0, 1, 1, 1), +(194958, 45491, 0, 1, 1, 1), +(194958, 45492, 0, 1, 1, 1), +(194958, 45493, 0, 1, 1, 1), +(194958, 45494, 0, 2, 1, 1), +(194958, 45495, 0, 2, 1, 1), +(194958, 45496, 0, 2, 1, 1), +(194958, 45497, 0, 2, 1, 1), +(194958, 45663, 0, 2, 1, 1); + +-- Thorim +UPDATE creature_template SET ScriptName = 'boss_thorim' WHERE entry = 32865; +UPDATE creature_template SET ScriptName = 'boss_runic_colossus' WHERE entry = 32872; +UPDATE creature_template SET ScriptName = 'boss_ancient_rune_giant' WHERE entry = 32873; +UPDATE creature_template SET ScriptName = 'npc_lightning_orb' WHERE entry = 33138; +UPDATE creature_template SET ScriptName = 'mob_thorim_trap_bunny' WHERE entry IN (33725, 33054); +UPDATE creature_template SET ScriptName = 'mob_thorim_preadds' WHERE entry IN (32885, 32883, 32907, 32908, 32882); +UPDATE creature SET spawnMask = 3 WHERE id = 32873; +UPDATE creature_template SET ScriptName = 'npc_sif' WHERE entry = 33196; +UPDATE `gameobject` SET `position_y` = -286.67, `position_z` = 419.50 WHERE `id` IN (194312, 194313, 194314, 194315); +UPDATE gameobject_template SET flags = 6553632, ScriptName='go_thorim_lever' WHERE entry = 194264; +-- adds +UPDATE creature_template SET ScriptName = 'mob_dark_rune_acolyte' WHERE entry = 33110; +UPDATE creature_template SET ScriptName = 'mob_dark_rune_champion' WHERE entry = 32876; +UPDATE creature_template SET ScriptName = 'mob_dark_rune_commoner' WHERE entry = 32904; +UPDATE creature_template SET ScriptName = 'mob_dark_rune_warbringer' WHERE entry = 32877; +UPDATE creature_template SET ScriptName = 'mob_dark_rune_ring_guard' WHERE entry = 32874; +UPDATE creature_template SET ScriptName = 'mob_dark_rune_honor_guard' WHERE entry = 33125; + +#DELETE FROM gameobject WHERE id = 194264; +#INSERT INTO gameobject VALUES (110010,194264,603,3,65535,2173.276, -252.805, 420.146, 3.027,0,0,0,0,604800,0,1); +UPDATE `creature` SET `phaseMask` = 128 WHERE `id` IN (32907, 32883); -- horde soldiers: phase 128 for aly: 65535 +UPDATE `creature` SET `phaseMask` = 64 WHERE `id` IN (32885, 32908); -- alliance soldiers: phase 64 for horde +*/ + +-- reset pos to some creatures +-- SOME POSITION ADJUSTMENTS, CHECK YOUR DB FOR THIS +/* +UPDATE creature SET spawnMask = 0 WHERE guid IN (129413, 129412, 129856, 129857); +UPDATE `creature` SET `position_x` = 2222.69 WHERE `guid` = 129413; +UPDATE `creature` SET `position_x` = 2222.69 WHERE `guid` = 129412; +UPDATE `creature` SET `position_x` = 2227.34 WHERE `guid` = 129856; +UPDATE `creature` SET `position_x` = 2227.34 WHERE `guid` = 129857; + +UPDATE `creature` SET `position_y` = -437.73 WHERE `guid` = 129860; +UPDATE `creature` SET `position_y` = -437.73 WHERE `guid` = 129861; +UPDATE `creature` SET `position_y` = -434.64 WHERE `guid` = 129862; +UPDATE `creature` SET `position_y` = -434.64 WHERE `guid` = 129863; +UPDATE `creature` SET `position_y` = -434.64 WHERE `guid` = 129391; +*/ + +/* +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES ('62565', '1', '32865'); + +-- Vezax +UPDATE creature_template SET UnitFlags = 0, ScriptName = 'boss_general_vezax' WHERE entry = 33271; +UPDATE creature_template SET `MinLevelHealth` = 23009250, `MaxLevelHealth` = 23009250 WHERE entry = 33449; +UPDATE `creature_template` SET `MechanicImmuneMask` = 619397115 WHERE `entry` IN (33271, 33449); +UPDATE creature_template SET ScriptName = 'mob_saronite_animus' WHERE entry = 33524; +UPDATE creature_template SET ScriptName = 'event_spell_saronite_barrier', MovementType = 1 WHERE entry = 33488; + +-- Yogg +UPDATE creature_template SET ScriptName = 'boss_yogg_saron' WHERE entry = 33288; +UPDATE creature_template SET `RegenerateStats`= 0, `ExtraFlags` = 1,`CreatureTypeFlags` = 108, ScriptName = 'boss_sara' WHERE entry = 33134; +UPDATE creature SET spawnMask = 3, MovementType = 0 WHERE id = 33134; +UPDATE creature_template SET `RegenerateStats`= 0, ScriptName = 'boss_brain_of_yogg_saron' WHERE entry = 33890; +UPDATE creature SET `spawntimesecs` = 604800 WHERE `id` = 33134; +UPDATE creature_template SET ScriptName = 'mob_corruptor_tentacle' WHERE entry = 33985; +UPDATE creature_template SET ScriptName = 'mob_constrictor_tentacle' WHERE entry = 33983; +UPDATE creature_template SET MinLevelHealth = 40000, MaxLevelHealth = 40000, MinLevel = 80, MaxLevel = 80, ScriptName = 'mob_vision_tentacle' WHERE entry = 33943; +UPDATE creature_template SET MinLevelHealth = 400000, MaxLevelHealth = 400000, ScriptName = 'mob_crusher_tentacle' WHERE entry = 33966; +UPDATE creature_template SET MinLevelHealth = 220000, MaxLevelHealth = 220000, ScriptName = 'mob_guardian_of_yogg_saron' WHERE entry = 33136; +UPDATE creature_template SET ScriptName = 'mob_immortal_guardian' WHERE entry = 33988; +UPDATE creature_template SET `FactionAlliance` = 14, `FactionHorde` = 14, ScriptName = 'mob_death_orb' WHERE entry = 33882; +UPDATE creature_template SET ScriptName = 'mob_sanity_well' WHERE entry = 33991; +UPDATE creature_template SET ScriptName='mob_madness_portal' WHERE `entry`=34072; +UPDATE creature_template SET ScriptName='mob_laughing_skull' WHERE `entry`=33990; +UPDATE creature_template SET ScriptName='mob_ominous_cloud' WHERE `entry`=33292; +UPDATE creature SET spawnMask = 3 WHERE id = 33292; +-- spells +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES ('63886', '1', '33882'); +-- Keepers +UPDATE creature_template SET ScriptName = 'keeper_hodir' WHERE entry = 33213; +UPDATE creature_template SET ScriptName = 'keeper_freya' WHERE entry = 33241; +UPDATE creature_template SET ScriptName = 'keeper_thorim' WHERE entry = 33242; +UPDATE creature_template SET ScriptName = 'keeper_mimiron' WHERE entry = 33244; +-- INSERT doors & yoggs brain INTO the brain room +DELETE FROM gameobject WHERE id IN (194635); +INSERT INTO gameobject VALUES (110000,194635,603,3,65535,2022.490,-25.389,261.961,0,0,0,0,0,604800,0,1); +DELETE FROM gameobject WHERE guid = 110001; +INSERT INTO gameobject VALUES (110001,194462,603,3,65535,2104.555, -25.635,242.646,0,0,0,0,0,604800,100,1); +DELETE FROM creature WHERE id IN (33890); +INSERT INTO creature VALUES (800000,33890,603,3,65535,0,0,1981.422,-22.442,255.011,0,604800,0,0,1371428,0,0,0); + +-- Algalon +UPDATE creature_template SET ScriptName = 'boss_algalon' WHERE entry = 32871; +UPDATE creature_template SET ScriptName = 'npc_collapsing_star' WHERE entry = 32955; +UPDATE creature_template SET ScriptName = 'npc_living_constellation' WHERE entry = 33052; +UPDATE creature_template SET ScriptName = 'npc_black_hole' WHERE entry = 32953; +UPDATE creature_template SET ScriptName = 'npc_worm_hole' WHERE entry IN (33105, 33104); +UPDATE creature_template SET MinLevelHealth = 39099, MaxLevelHealth = 39099 WHERE entry = 33089; +UPDATE gameobject_template SET flags= 6553632, ScriptName = 'go_celestial_access' WHERE entry IN (194628, 194752); + +-- Teleporter +UPDATE `gameobject_template` SET `flags` = 0, `ScriptName` = 'go_ulduar_teleporter' WHERE `entry` IN (194569); + +-- Keepers +-- Keepers images +UPDATE creature_template SET `NpcFlags` = 1, `UnitFlags` = 2, ScriptName = 'hodir_image' WHERE entry = 33411; +UPDATE creature_template SET `NpcFlags` = 1, `UnitFlags` = 2, ScriptName = 'freya_image' WHERE entry = 33410; +UPDATE creature_template SET `NpcFlags` = 1, `UnitFlags` = 2, ScriptName = 'thorim_image' WHERE entry = 33413; +UPDATE creature_template SET `NpcFlags` = 1, `UnitFlags` = 2, ScriptName = 'mimiron_image' WHERE entry = 33412; +-- INSERT keepers imagees INTO the db +DELETE FROM creature WHERE guid IN (800001, 800002, 800003, 800004); +INSERT INTO creature VALUES +(800001, 33410, 603, 3, 65535,0,0, 2036.892, 25.621, 411.358, 3.83, 604800,0,0, 5647, 0, 0, 0), -- Freya +(800002, 33412, 603, 3, 65535,0,0, 1939.215, 42.677, 411.355, 5.31, 604800,0,0, 5647, 0, 0, 0), -- Mimiron +(800003, 33411, 603, 3, 65535,0,0, 1939.195, -90.662, 411.357, 1.06, 604800,0,0, 5647, 0, 0, 0), -- Hodir +(800004, 33413, 603, 3, 65535,0,0, 2036.674, -73.814, 411.355, 2.51, 604800,0,0, 5647, 0, 0, 0); -- Thorim + +-- Doors +UPDATE gameobject_template SET faction = 114 WHERE entry IN (194553, 194554, 194556, 194148, 194634, 194635, 194905, 194441, +194442, 194416, 194774, 194775, 194776, 194560, 194557, 194558, 194750, 194910, 194559, 194635, 194636, 194637, 194631, 194255, 194630, 194767); +UPDATE gameobject_template SET faction = 114, `flags` = 4 WHERE entry IN (192075, 194173); -- snowdrifts +-- consoles +UPDATE gameobject_template SET faction = 0 WHERE entry IN (194555, 194628); + +-- loot chests +UPDATE gameobject_template SET faction = 0, data15 = 1 WHERE entry IN (195046, 195047, 194307, 194308, 194200, 194201, 194312, 194313, 194314, 194315, 194821, +194822, 194823, 194324, 194325, 194326, 194327, 194328, 194329, 194330, 194331, 194789, 194956, 194957, 194958); +UPDATE gameobject SET spawntimesecs = -604800 WHERE id IN (195046, 195047, 194307, 194308, 194200, 194201, 194312, 194313, 194314, 194315, 194821, +194822, 194823, 194324, 194325, 194326, 194327, 194328, 194329, 194330, 194331, 194789, 194956); + +-- NOT SURE IF THE TRASH MOBS ARE SCRIPTED BY EVENTAI +-- Mobs +UPDATE `creature_template` SET `ScriptName` = 'generic_creature' WHERE `entry` IN (34086, 34085, 34069, 33237, 34234, 33236, 33264, 34164, 34196, 34199, 34198, +34190, 34197, 33699, 34134, 34135, 34133, 33430, 33528, 33431, 33527, 33526, 33525, 33355, 33354, 34193, 34183, 33110, +32878, 33822, 33818, 33824, 33823, 33772, 33838, 33819, 33820, 32875, 33346, 34057) AND `ScriptName` = '' AND `AIName` = ''; + +-- some fixes (thx to mns and Reamer) +UPDATE `creature_template` SET `ScriptName` = 'mob_eyebeam_trigger' where `entry` in (33802,33632); +UPDATE `creature_template` SET `ScriptName` = 'mob_kologarn_pit_kill_bunny' where `entry` in (33742); +*/ diff --git a/sql_mr/mr00585_mangos_azjol-nerub.sql b/sql_mr/mr00585_mangos_azjol-nerub.sql new file mode 100644 index 0000000000..dcd1678026 --- /dev/null +++ b/sql_mr/mr00585_mangos_azjol-nerub.sql @@ -0,0 +1,4 @@ +DELETE FROM `achievement_criteria_requirement` WHERE `type` = 18 AND `criteria_id` in ( + 7130 -- Achievement 1860 +,7133 -- Achievement 1862 +); diff --git a/sql_mr/mr00585_mangos_halls_of_lightning.sql b/sql_mr/mr00585_mangos_halls_of_lightning.sql new file mode 100644 index 0000000000..3372d535a8 --- /dev/null +++ b/sql_mr/mr00585_mangos_halls_of_lightning.sql @@ -0,0 +1 @@ +DELETE FROM `achievement_criteria_requirement` WHERE `type` = 18 AND `criteria_id` = 7144; -- Achievement 1867 diff --git a/sql_mr/mr00585_mangos_halls_of_stone.sql b/sql_mr/mr00585_mangos_halls_of_stone.sql new file mode 100644 index 0000000000..57c19d8d99 --- /dev/null +++ b/sql_mr/mr00585_mangos_halls_of_stone.sql @@ -0,0 +1,2 @@ +UPDATE `creature_template` SET `ScriptName` = 'boss_krystallus' WHERE `entry` = 27977; +DELETE FROM `achievement_criteria_requirement` WHERE `criteria_id` = 7143 AND `type` = 18; -- Achievement 1866 diff --git a/sql_mr/mr00592_mangos_sunwell_plateau_AI_fixes.sql b/sql_mr/mr00592_mangos_sunwell_plateau_AI_fixes.sql new file mode 100644 index 0000000000..8a304f45b2 --- /dev/null +++ b/sql_mr/mr00592_mangos_sunwell_plateau_AI_fixes.sql @@ -0,0 +1,32 @@ +-- Despawn at evade and death. Servant Muu'ru (by Ulduar) +-- Creature id: 25772 +UPDATE creature_template SET AIName='EventAI' WHERE entry=25772; +INSERT INTO creature_ai_scripts VALUES +('2577207','25772','7','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'), +('2577208','25772','6','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'); +-- ERROR CreatureEventAI: Creature 25772 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2577207. +-- ERROR CreatureEventAI: Creature 25772 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2577208. + +-- Creature id: 25798 +UPDATE creature_template SET AIName='EventAI' WHERE entry=25798; +INSERT INTO creature_ai_scripts VALUES +('2579803','25798','6','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'), +('2579804','25798','7','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'); +-- ERROR CreatureEventAI: Creature 25798 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2579804. +-- ERROR CreatureEventAI: Creature 25798 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2579803. + +-- Creature id: 25799 +UPDATE creature_template SET AIName='EventAI' WHERE entry=25799; +INSERT INTO creature_ai_scripts VALUES +('2579904','25799','6','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'), +('2579905','25799','7','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'); +-- ERROR CreatureEventAI: Creature 25799 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2579904. +-- ERROR CreatureEventAI: Creature 25799 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2579905. + +-- Creature id: 25824 +UPDATE creature_template SET AIName='EventAI' WHERE entry=25824; +INSERT INTO creature_ai_scripts VALUES +('2582403','25824','6','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'), +('2582404','25824','7','0','100','31','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn'); +-- ERROR CreatureEventAI: Creature 25824 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2582403. +-- ERROR CreatureEventAI: Creature 25824 has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event 2582404. diff --git a/sql_mr/mr00612_mangos_obsidian_sanctum.sql b/sql_mr/mr00612_mangos_obsidian_sanctum.sql new file mode 100644 index 0000000000..77d12b5c64 --- /dev/null +++ b/sql_mr/mr00612_mangos_obsidian_sanctum.sql @@ -0,0 +1,12 @@ +-- Instance Obsidian Sanctum + +-- ScriptNames +UPDATE `creature_template` SET `ScriptName` = "" WHERE `entry` = 30688; +UPDATE `creature_template` SET `ScriptName` = "" WHERE `entry` = 30858; + +DELETE FROM achievement_criteria_requirement WHERE type IN (11, 18) AND criteria_id IN (7326,7327); +INSERT INTO achievement_criteria_requirement VALUES +(7326, 18, 0, 0), +(7327, 18, 0, 0); + +DELETE FROM `creature` WHERE `id`=15989; diff --git a/sql_mr/mr00622_mangos_Ulduar_AI_fixes.sql b/sql_mr/mr00622_mangos_Ulduar_AI_fixes.sql new file mode 100644 index 0000000000..40ec04576c --- /dev/null +++ b/sql_mr/mr00622_mangos_Ulduar_AI_fixes.sql @@ -0,0 +1,91 @@ +-- DB fix in Ulduar (by Ulduar) +-- Creature id: 33772 +UPDATE creature_template SET AIName='EventAI' WHERE entry=33772; +DELETE FROM creature_ai_scripts WHERE creature_id=33772; +INSERT INTO creature_ai_scripts VALUES +('3377201','33772','0','0','100','7','6000','11000','13000','18000','11','64429','4','0','0','0','0','0','0','0','0','0','Faceless Horror - Cast Death Grip'), +('3377202','33772','0','0','100','7','6000','8000','8000','12000','11','63722','8','0','0','0','0','0','0','0','0','0','Faceless Horror - Cast Shadow Crash'), +('3377203','33772','0','0','100','7','15000','18000','25000','36000','11','63703','0','0','0','0','0','0','0','0','0','0','Faceless Horror - Cast Void Wave'), +('3377204','33772','2','0','100','6','40','0','0','0','11','63710','0','2','11','63708','0','6','0','0','0','0','Faceless Horror - Cast Void Barrier at 40% HP and summon Void Beast'); + +-- Script id: 33806 +DELETE FROM dbscripts_on_creature_death WHERE id=33806; +INSERT INTO dbscripts_on_creature_death VALUES +(33806,1,15,63723,0,0,0,0,0,0,0,0,0,0,0,0,''), +(33806,1,14,63710,0,33772,50000,0,0,0,0,0,0,0,0,0,''); + +-- Script id: 33136 +DELETE FROM dbscripts_on_creature_death WHERE id=33136; +INSERT INTO dbscripts_on_creature_death VALUES +(33136,0,18,1000,0,0,0,0,0,0,0,0,0,0,0,0,''); + +-- Script id: 33988 +DELETE FROM dbscripts_on_creature_death WHERE id=33988; +INSERT INTO dbscripts_on_creature_death VALUES +(33988,0,18,1000,0,0,0,0,0,0,0,0,0,0,0,0,''); + +-- Summon Yogg-Saron guardian +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +('62978', '1', '33292'); + +-- Linked creatures (from Ulduar) +DELETE FROM `creature_linking_template` WHERE `map` = 603 AND `master_entry` = 32845; +INSERT INTO `creature_linking_template` (`entry`, `map`, `master_entry`, `flag`, `search_range`) VALUES +('32893','603','32845','5140','0'), +('32897','603','32845','5140','0'), +('32900','603','32845','5140','0'), +('32901','603','32845','5140','0'), +('32941','603','32845','5140','0'), +('32946','603','32845','5140','0'), +('32948','603','32845','5140','0'), +('32950','603','32845','5140','0'), +('33325','603','32845','5140','0'), +('33326','603','32845','5140','0'), +('33327','603','32845','5140','0'), +('33328','603','32845','5140','0'), +('33330','603','32845','5140','0'), +('33331','603','32845','5140','0'), +('33332','603','32845','5140','0'), +('33333','603','32845','5140','0'); + +DELETE FROM `creature_linking_template` WHERE `map` = 603 AND `master_entry` = 33288; +INSERT INTO `creature_linking_template` (`entry`, `map`, `master_entry`, `flag`, `search_range`) VALUES +('33988','603','33288','4112','0'); + +INSERT INTO `creature_linking` (`guid`, `master_guid`, `flag`) VALUES +('129539','126685','15'), +('129540','126686','15'), +('129541','126687','15'), +('129538','126688','15'); + +-- Script id: 62940 +DELETE FROM dbscripts_on_spell WHERE id=62940; +INSERT INTO dbscripts_on_spell VALUES +(62940,0,18,1000,0,0,0,0,0,0,0,0,0,0,0,0,'Despawn at Teleport'); + + +-- Script id: 33699 +DELETE FROM dbscripts_on_creature_death WHERE id=33699; +INSERT INTO dbscripts_on_creature_death VALUES +(33699,0,15,63630,0,33699,100,0,0,0,0,0,0,0,0,0,'Cast Avenger at death'); + + +-- Creature id: 33699 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '33699'; +DELETE FROM creature_ai_scripts WHERE creature_id=33699; +INSERT INTO creature_ai_scripts VALUES +('3369901','33699','0','0','100','31','50000','60000','50000','60000','11','63528','0','34','0','0','0','0','0','0','0','0','Cast Super charge in Combat'), +('3369902','33699','0','0','100','31','12000','13000','17000','20000','11','63541','3','0','0','0','0','0','0','0','0','0',''); + +-- Creature id: 33755 +UPDATE creature_template SET AIName='EventAI' WHERE entry=33755; +DELETE FROM creature_ai_scripts WHERE creature_id=33755; +INSERT INTO creature_ai_scripts VALUES +('3375501','33755','4','0','100','6','0','0','0','0','11','63616','0','0','0','0','0','0','0','0','0','0',''); + +-- Creature id: 33754 +UPDATE creature_template SET AIName='EventAI' WHERE entry=33754; +DELETE FROM creature_ai_scripts WHERE creature_id=33754; +INSERT INTO creature_ai_scripts VALUES +('3375401','33754','4','0','100','2','0','0','0','0','11','63610','0','0','0','0','0','0','0','0','0','0',''), +('3375402','33754','4','0','100','4','0','0','0','0','11','63674','0','0','0','0','0','0','0','0','0','0',''); diff --git a/sql_mr/mr00633_mangos_loot_conditions.sql b/sql_mr/mr00633_mangos_loot_conditions.sql new file mode 100644 index 0000000000..187dae88cc --- /dev/null +++ b/sql_mr/mr00633_mangos_loot_conditions.sql @@ -0,0 +1,72 @@ +SET @ConditionEntry := 1807; + +/* +For use conditions system for limiting loot by SD2 always use: +@ConditionEntry for INSTANCE_CONDITION_ID_NORMAL_MODE +@ConditionEntry + 1 for INSTANCE_CONDITION_ID_HARD_MODE +@ConditionEntry + 2 for INSTANCE_CONDITION_ID_HARD_MODE_2 +@ConditionEntry + 3 for INSTANCE_CONDITION_ID_HARD_MODE_3 +@ConditionEntry + 4 for INSTANCE_CONDITION_ID_HARD_MODE_4 +*/ +-- --------------- -- +-- Flame Leviathan -- +-- --------------- -- +REPLACE INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`, `condition_id`) VALUES +(33113, 45294, 0, 3, 1, 1, 0), -- 10 Player hard 4 +(33113, 45087, 100, 0, 1, 1, 0), -- 10 Player hard 2, 3, 4 +(34003, 45087, 100, 0, 2, 2, 0); -- 25 Player hard 2, 3, 4 +UPDATE `creature_loot_template` SET `groupid` = 3, `ChanceOrQuestChance` = 0 WHERE `item` IN (45293, 45295, 45296, 45297, 45300, 45294); -- 10 Player hard 4 +UPDATE `creature_loot_template` SET `groupid` = 1 WHERE `item` IN (45086, 45106, 45107, 45108, 45109, 45110, 45111, 45112); -- 25 Player normal or hard 1,2,3,4 +UPDATE `creature_loot_template` SET `groupid` = 2 WHERE `item` IN (45113, 45114, 45115, 45116, 45117, 45118, 45119); -- 25 Player normal or hard 1,2,3,4 +UPDATE `creature_loot_template` SET `entry` = 34003, `ChanceOrQuestChance` = 0, `groupid` = 3 WHERE `item` IN (45132, 45133, 45134, 45135, 45136); -- 25 Player hard 4 +-- 10 Player +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 4 WHERE `entry` = 33113 AND `groupid` IN (3); -- Hard mode 4 +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 2 WHERE `entry` = 33113 AND `item` = 45087; -- Hard mode 2,3,4 +-- 25 Player +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 4 WHERE `entry` = 34003 AND `groupid` IN (3); -- Hard mode 4 +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 2 WHERE `entry` = 34003 AND `item` = 45087; -- Hard mode 2,3,4 + +-- -------------------- -- +-- XT-002 Deconstructor -- +-- -------------------- -- +-- 10 Player +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry WHERE `entry` = 33293 AND `groupid` IN (1, 2); -- normal mode +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 1 WHERE `entry` = 33293 AND `groupid` IN (3); -- hard mode +-- 25 Player +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry WHERE `entry` = 33885 AND `groupid` IN (1, 2, 3); -- normal mode +-- Missed loot +REPLACE INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(33885, 45445, 0, 4, 1, 1), +(33885, 45443, 0, 4, 1, 1), +(33885, 45444, 0, 4, 1, 1), +(33885, 45446, 0, 4, 1, 1), +(33885, 45442, 0, 4, 1, 1); +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 1 WHERE `entry` = 33885 AND `groupid` IN (4); -- hard mode + +-- ---------- -- +-- Sartharion -- +-- ---------- -- +-- 10 Player +DELETE FROM `creature_loot_template` WHERE `entry` = 28860 AND `item` = 47241; +UPDATE `creature_loot_template` SET `groupid` = 3, `ChanceOrQuestChance` = 0, `mincountOrRef` = 1, `maxcount` = 1 WHERE `entry` = 28860 AND `item` IN (43345, 43347); +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 1 WHERE `entry` = 28860 AND `groupid` IN (2); -- at least 1 drake +-- Missed loot +REPLACE INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +-- at least 2 drakes (Loot from Schmoozerd) +(28860, 43995, 0, 6, 1, 1), +(28860, 43998, 0, 6, 1, 1), +(28860, 43994, 0, 6, 1, 1), +(28860, 43996, 0, 6, 1, 1), +(28860, 43993, 0, 6, 1, 1), +-- 3 drakes +(28860, 43986, 0, 7, 1, 1); +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 2 WHERE `entry` = 28860 AND `groupid` IN (6); -- at least 2 drake +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 3 WHERE `entry` = 28860 AND `groupid` IN (7); -- at least 3 drake +-- 25 Player +UPDATE `creature_loot_template` SET `groupid` = 2, `ChanceOrQuestChance` = 0, `mincountOrRef` = 1, `maxcount` = 1 WHERE `entry` = 31311 AND `item` IN (40433, 40630, 43345, 43346); +-- ERROR:Table 'reference_loot_template' entry 40630 isn't reference id and not referenced from loot, and then useless. +DELETE FROM `creature_loot_template` WHERE `entry` = 31311 AND `item` = 47241; +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 1 WHERE `entry` = 31311 AND `groupid` IN (4); -- at least 1 drake +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 2 WHERE `entry` = 31311 AND `groupid` IN (1); -- at least 2 drake +UPDATE `creature_loot_template` SET `groupid` = 7, `ChanceOrQuestChance` = 0 WHERE `entry` = 31311 AND `item` = 43954; +UPDATE `creature_loot_template` SET `condition_id` = @ConditionEntry + 3 WHERE `entry` = 31311 AND `groupid` IN (7); -- at least 3 drake diff --git a/sql_mr/mr00636_mangos_icecrown_down.sql b/sql_mr/mr00636_mangos_icecrown_down.sql new file mode 100644 index 0000000000..0c8573aab0 --- /dev/null +++ b/sql_mr/mr00636_mangos_icecrown_down.sql @@ -0,0 +1,513 @@ +-- Frozen halls (3 small instances) additions +-- Forge of souls +-- UPDATE `creature_template` SET `ScriptName`='mob_soul_storm', `AIName` ='' WHERE `entry`=; + +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_jaina_and_sylvana_FSintro' WHERE `entry` IN (37597, 37596); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_jaina_and_sylvana_FSextro' WHERE `entry` IN (38160, 38161); +UPDATE `creature_template` SET `Scale` = 0.8 WHERE `entry` IN (37221, 36955, 36658, 37225, 37223, 37226, 37554); +UPDATE `creature_template` SET `NpcFlags`='3' WHERE `entry` IN (38160, 38161); +UPDATE `creature_template` SET `EquipmentTemplateId` = 1290 WHERE `entry` = 37554; + +UPDATE `creature` SET `position_z` = 628.157 WHERE id = 36658; +DELETE FROM vehicle_accessory WHERE accessory_entry = 36658; + +-- Halls of reflection +UPDATE `instance_template` SET `ScriptName` = 'instance_halls_of_reflection' WHERE map=668; + +UPDATE `gameobject_template` SET `faction`='1375' WHERE `entry` IN (197341, 202302, 201385, 201596); + +UPDATE `creature_template` SET `SpeedWalk` = '1.5', `SpeedRun` = '2.0' WHERE `entry` IN (36954, 37226); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_jaina_and_sylvana_HRintro' WHERE `entry` IN (37221, 37223); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='boss_falric' WHERE `entry` IN (38112); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='boss_marwyn' WHERE `entry` IN (38113); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='boss_lich_king_intro_hor' WHERE `entry` IN (36954); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='boss_lich_king_hr' WHERE `entry` IN (37226); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_jaina_and_sylvana_HRextro' WHERE `entry` IN (36955, 37554); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_undead_hor' WHERE `entry` IN (36940,36941,37069); +UPDATE `creature_template` SET `Scale`='0.8' WHERE `entry` IN (37221, 36955); +UPDATE `creature_template` SET `EquipmentTemplateId` = 1290 WHERE `entry` = 37554; +UPDATE `creature_template` SET `EquipmentTemplateId`='0' WHERE `entry`=36954; +UPDATE `creature_template` SET `Scale`='0.8' WHERE `entry` IN (36658, 37225, 37223, 37226, 37554); +UPDATE `creature_template` SET `UnitFlags`='768', `CreatureTypeFlags`='268435564' WHERE `entry` IN (38177, 38176, 38173, 38172, 38567, 38175); +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_frostworn_general' WHERE `entry`=36723; +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_spiritual_reflection' WHERE `entry`=37068; + +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(70464, 1, 36881), +(69708, 1, 37226), +(70194, 1, 37226); + +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(70224, 1, 37014), +(70225, 1, 37014); + +REPLACE INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES +(69431, 1, 37497), +(69431, 1, 37496), +(69431, 1, 37588), +(69431, 1, 37584), +(69431, 1, 37587); + +DELETE FROM `creature` WHERE `id` IN(38112, 38113, 36955, 37554); +INSERT INTO `creature` (`id`, `map`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `DeathState`, `MovementType`) VALUES + (38112, 668, 3, 1, 0, 0, 5276.81, 2037.45, 709.32, 5.58779, 604800, 0, 0, 377468, 0, 0, 0) +, (38113, 668, 3, 1, 0, 0, 5341.72, 1975.74, 709.32, 2.40694, 604800, 0, 0, 539240, 0, 0, 0) +-- , (36955, 668, 3, 128, 0, 0, 5547.27, 2256.95, 733.011, 0.835987, 7200, 0, 0, 252000, 881400, 0, 0) +-- , (37554, 668, 3, 64, 0, 0, 5547.27, 2256.95, 733.011, 0.835987, 7200, 0, 0, 252000, 881400, 0, 0) +; + +-- INSERT INTO `gameobject` (`id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +-- (201596, 668, 1, 128, 5275.28, 1694.23, 786.147, 0.981225, 0, 0, 0.471166, 0.882044, 25, 0, 1); + +UPDATE `creature` SET `position_x` = 5551.29, `position_y` = 2261.33, `position_z` = 733.012, `orientation` = 4.0452 WHERE `id` = 37226; + +UPDATE `creature_template` SET `ModelId1` = 11686, `ModelId2` = 11686, `ModelId3` = 11686, `ModelId4` = 11686 WHERE `entry` IN (37014,37704); + +DELETE FROM `gameobject` WHERE `id` IN (201385, 201596, 202079); + +UPDATE `gameobject_template` SET `faction` = '114',`data0` = '0' WHERE `gameobject_template`.`entry` IN (197341,197342,197343); +UPDATE `gameobject` SET `state` = 1 WHERE `id` IN (197342,197343); + +-- offlike way for icewalls operation +DELETE FROM `creature` WHERE `id`=37014; +UPDATE `creature_template` SET `AIName`='', `Scriptname`='npc_queldelar_hor' WHERE `entry` IN (37158); +DELETE FROM `creature` WHERE `map` = 668 AND `id` IN (37221,37223,37554,36955); + +-- Captains chest (override) +DELETE FROM `gameobject` WHERE `id` IN (202212,201710,202337,202336); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(600013, 202212, 668, 1, 65535, 5241.047, 1663.4364, 784.295166, 0.54, 0, 0, 0, 0, -604800, 100, 1), +(600014, 201710, 668, 1, 65535, 5241.047, 1663.4364, 784.295166, 0.54, 0, 0, 0, 0, -604800, 100, 1), +(600015, 202337, 668, 2, 65535, 5241.047, 1663.4364, 784.295166, 0.54, 0, 0, 0, 0, -604800, 100, 1), +(600016, 202336, 668, 2, 65535, 5241.047, 1663.4364, 784.295166, 0.54, 0, 0, 0, 0, -604800, 100, 1); +-- Dalaran portal (override) +UPDATE `gameobject` SET `phaseMask` = 65535, `orientation` = 0, `rotation2` = 0, `rotation3` = 0, `spawntimesecs` = -604800, `animprogress` = 100 WHERE `id` = 202079 AND `map` = 668; + +/* Original Icewalls from YTDB +REPLACE INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(3485, 201385, 668, 3, 1, 5540.39, 2086.48, 731.066, 1.00057, 0, 0, 0.479677, 0.877445, 604800, 100, 1), +(3438, 201385, 668, 3, 1, 5494.3, 1978.27, 736.689, 1.0885, 0, 0, 0.517777, 0.855516, 604800, 100, 1), +(3386, 201385, 668, 3, 1, 5434.27, 1881.12, 751.303, 0.923328, 0, 0, 0.445439, 0.895312, 604800, 100, 1), +(3383, 201385, 668, 3, 1, 5323.61, 1755.85, 770.305, 0.784186, 0, 0, 0.382124, 0.924111, 604800, 100, 1); +*/ + +-- EVENT AI + +-- ICC trash mobs from Xfurry +-- ########### +-- LOWER SPIRE +-- ########### + +-- The Damned (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id`=3701101; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3701101,37011,0,0,100,30,10000,15000,10000,15000,11,70960,0,0,0,0,0,0,0,0,0,0, 'The Dammed - cast Bone Flurry'); +DELETE FROM `creature_ai_scripts` WHERE `id`=3701102; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3701102,37011,6,0,100,30,0,0,0,0,11,70961,0,0,0,0,0,0,0,0,0,0, 'The Dammed - cast Shattred Bones'); +-- Nerub'ar Broodkeeper (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3672501, 3672502, 3672503, 3672504); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3672501,36725,10,0,100,31,1,60,0,0,38,0,0,0,0,0,0,0,0,0,0,0, 'Nerubar broodkeeper - set aggressive'), +(3672502,36725,0,0,100,31,5000,7000,5000,7000,11,70965,4,0,0,0,0,0,0,0,0,0, 'Nerubar Broodkeeper - crypt scarabs'), +(3672503,36725,14,0,100,31,50,30,8000,13000,11,36725,6,0,0,0,0,0,0,0,0,0, 'Nerubar broodkeeper - dark mending'), +(3672504,36725,0,0,100,31,7000,11000,7000,11000,11,70980,4,0,0,0,0,0,0,0,0,0, 'Nerubar broodkeeper - web wrap'); +-- Deathbound Ward (need compare with YTDB) +-- Creature id: 37007 +DELETE FROM creature_ai_scripts WHERE creature_id=37007; +INSERT INTO creature_ai_scripts VALUES +('3700701','37007','0','0','100','31','15000','20000','20000','30000','11','71022','0','0','0','0','0','0','0','0','0','0','Deathbound ward - Disrupting Shout'), +('3700702','37007','0','0','100','31','5000','7000','5000','7000','11','71021','1','0','0','0','0','0','0','0','0','0','Deathbound Ward - Saber Lash'), +('3700703','37007','7','0','100','30','0','0','0','0','28','0','70733','0','0','0','0','0','0','0','0','0','Deathbound Ward - Remove Aura Stone Form at Evade.'), +('3700704','37007','21','0','100','30','0','0','0','0','28','0','70733','0','0','0','0','0','0','0','0','0','Deathbound Ward - Remove Aura Stone Form at Just Reached Home.'); + +-- ##################### +-- ORATORY OF THE DAMMED +-- ##################### + +-- Deathspeaker Attendant (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3681101, 3681102, 3681103); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3681101,36811,0,0,100,31,3000,5000,6000,8000,11,69387,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker attendant - shadow bolt'), +(3681102,36811,0,0,100,11,10000,15000,10000,15000,11,69355,0,0,0,0,0,0,0,0,0,0, 'Deathspeaker attendant - shadow nova 10'), +(3681103,36811,0,0,100,21,10000,15000,10000,15000,11,71106,0,0,0,0,0,0,0,0,0,0, 'Deathspeaker attendant - shadow nova 25'); +-- Deathspeaker Disciple (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3680701, 3680702, 3680703, 3680704); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3680701,36807,0,0,100,31,3000,6000,7000,10000,11,69387,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker disciple - shadow bolt'), +(3680702,36807,16,0,100,31,69391,30,5000,9000,11,69391,6,0,0,0,0,0,0,0,0,0, 'Deathspeaker disciple - dark blessing'), +(3680703,36807,14,0,100,11,50,50,7000,11000,11,69389,6,0,0,0,0,0,0,0,0,0, 'Deathspeaker disciple - shadow mend 10'), +(3680704,36807,14,0,100,21,50,50,7000,11000,11,71107,6,0,0,0,0,0,0,0,0,0, 'Deathspeaker disciple - shadow mend 25'); +-- Deathspeaker Servant (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3680501, 3680502, 3680503, 3680504, 3680505); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3680501,36805,0,0,100,31,7000,10000,7000,10000,11,69405,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker Servant - consuming shadows'), +(3680502,36805,0,0,100,11,4000,7000,4000,7000,11,69576,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker servant - chaos bolt 10'), +(3680503,36805,0,0,100,21,4000,7000,4000,7000,11,71108,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker servant - chaos bolt 25'), +(3680504,36805,0,0,100,11,7000,13000,7000,13000,11,69404,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker servant - curse of agony 10'), +(3680505,36805,0,0,100,21,7000,13000,7000,13000,11,71112,4,0,0,0,0,0,0,0,0,0, 'Deathspeaker servant - curse of agony 25'); + +-- ################ +-- RAMPART OF SKULL +-- ################ + +-- Frenzied Abomination (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3754601, 3754602); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3754601,37546,0,0,100,31,3000,5000,3000,5000,11,70191,1,0,0,0,0,0,0,0,0,0, 'Frenzied abomination - abomination cleave'), +(3754602,37546,2,0,100,30,10,9,0,0,11,70371,0,0,0,0,0,0,0,0,0,0, 'Frenzied abomination - enrage'); +-- Spire Minion (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3754501, 3754502); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3754501,37545,0,0,100,31,3000,6000,3000,6000,11,70396,1,0,0,0,0,0,0,0,0,0, 'Spire minion - ghoul slash'), +(3754502,37545,0,0,100,31,30000,30000,30000,30000,11,70363,0,0,0,0,0,0,0,0,0,0, 'Spire minion - cannibalize'); + +-- ########### +-- PLAGUEWORKS +-- ########### + +-- Blighted Abomination (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3702201, 3702202, 3702203); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3702201,37022,0,0,100,31,2000,5000,2000,5000,11,40504,1,0,0,0,0,0,0,0,0,0, 'Blighted abomination - cleave'), +(3702202,37022,0,0,100,31,7000,15000,20000,30000,11,71150,0,0,0,0,0,0,0,0,0,0, 'Blighted abomination - plague cloud'), +(3702203,37022,0,0,100,31,5000,10000,10000,15000,11,71140,4,0,0,0,0,0,0,0,0,0, 'Blighted abomination - scourge hook'); +-- Plague Scientist (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` IN (3702301, 3702302, 3702303); +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3702301,37023,0,0,100,31,10000,10000,10000,10000,11,71103,4,0,0,0,0,0,0,0,0,0, 'Plague scientist - combobulating spray'), +(3702302,37023,0,0,100,31,8000,11000,8000,11000,11,73079,4,0,0,0,0,0,0,0,0,0, 'Plague scientist - plague blast'), +(3702303,37023,0,0,100,31,15000,20000,15000,20000,11,69871,6,0,0,0,0,0,0,0,0,0, 'Plague scientist - plague stream'); +-- ERROR CreatureEventAI: Event 3702303 Action1 uses incorrect Target type 6 for event-type 0 + +-- Vengefull fleshreaper (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id`=3703801; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3703801,37038,0,0,100,31,5000,10000,5000,10000,11,71164,5,0,0,0,0,0,0,0,0,0, 'Vengefull fleshreaper - leaping face maul'); + +-- ############# +-- CRIMSON HALLS +-- ############# + +-- Darkfallen Archmage (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3766401 AND 3766407; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3766401,37664,0,0,100,11,5000,10000,30000,35000,11,70408,0,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - amplify magic 10'), +(3766402,37664,0,0,100,21,5000,10000,30000,35000,11,72336,0,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - amplify magic 25'), +(3766403,37664,0,0,100,11,7000,11000,7000,11000,11,70407,0,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - blast wave 10'), +(3766404,37664,0,0,100,21,7000,11000,7000,11000,11,71151,0,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - blast wave 25'), +(3766405,37664,0,0,100,11,9000,13000,9000,13000,11,70409,4,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - fireball 10'), +(3766406,37664,0,0,100,21,9000,13000,9000,13000,11,71153,4,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - fireball 25'), +(3766407,37664,0,0,100,31,10000,10000,10000,10000,11,70410,5,0,0,0,0,0,0,0,0,0, 'Darkfallen archmage - polymorph spider'); +-- Darkfallen Blood Knight (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3759501 AND 3759503; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3759501,37595,4,0,100,6,0,0,0,0,11,71736,0,0,0,0,0,0,0,0,0,0, 'Darkfallen blood knight - vampiric aura'), +(3759502,37595,0,0,100,31,5000,9000,5000,9000,11,70450,1,0,0,0,0,0,0,0,0,0, 'Darkfallen blood knight - blood mirror'), +(3759503,37595,0,0,100,31,3000,6000,3000,6000,11,70437,1,0,0,0,0,0,0,0,0,0, 'Darkfallen blood knight - unholy strike'); +-- Darkfallen Noble (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3766301 AND 3766303; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3766301,37663,0,0,100,31,7000,11000,7000,11000,11,70645,4,0,0,0,0,0,0,0,0,0, 'Darkfallen noble - chains of shadow'), +(3766302,37663,0,0,100,11,3000,6000,3000,6000,11,72960,4,0,0,0,0,0,0,0,0,0, 'Darkfallen noble - shadow bolt 10'), +(3766303,37663,0,0,100,21,3000,6000,3000,6000,11,72961,4,0,0,0,0,0,0,0,0,0, 'Darkfallen noble - shadow bolt 25'); +-- Darkfallen Advisor (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3757101 AND 3757104; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3757101,37571,0,0,100,11,5000,9000,5000,9000,11,72057,4,0,0,0,0,0,0,0,0,0, 'Darkfallen advisor - lich slap 10'), +(3757102,37571,0,0,100,21,5000,9000,5000,9000,11,72421,4,0,0,0,0,0,0,0,0,0, 'Darkfallen advisor - lich slap 25'), +(3757103,37571,16,0,100,31,72066,40,10000,20000,11,72066,6,0,0,0,0,0,0,0,0,0, 'Darkfallen advisor - shroud of spell warding'), +(3757104,37571,16,0,100,31,72065,50,10000,20000,11,72065,6,0,0,0,0,0,0,0,0,0, 'Darkfallen advisor - shroud of protection'); +-- Darkfallen Lieutenant (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3766501 AND 3766503; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3766501,37665,0,0,100,11,5000,7000,5000,7000,11,70435,1,0,0,0,0,0,0,0,0,0, 'Darkfallen lieutenant - rend flesh 10'), +(3766502,37665,0,0,100,21,5000,7000,5000,7000,11,71154,1,0,0,0,0,0,0,0,0,0, 'Darkfallen lieutenant - rend flesh 25'), +(3766503,37665,0,0,100,31,5000,7000,20000,25000,11,70423,1,0,0,0,0,0,0,0,0,0, 'Darkfallen lieutenant - vampiric curse'); +-- Darkfallen Tactician (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3766601 AND 3766603; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3766601,37666,0,0,100,31,5000,7000,10000,13000,11,70432,1,0,0,0,0,0,0,0,0,0, 'Darkfallen tactitian - blood sap'), +(3766602,37666,0,0,100,31,7000,10000,7000,10000,11,70437,1,0,0,0,0,0,0,0,0,0, 'Darkfallen tactitian - unholy strike'), +(3766603,37666,4,0,100,6,0,0,0,0,11,70431,0,0,0,0,0,0,0,0,0,0, 'Darkfallen tactitian - shadowstep'); +-- Darkfallen Commander (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3766201 AND 3766203; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3766201,37662,4,0,100,6,0,0,0,0,11,70750,0,0,0,0,0,0,0,0,0,0, 'Darkfallen commander - battle shout'), +(3766202,37662,0,0,100,11,3000,5000,5000,7000,11,70449,5,0,0,0,0,0,0,0,0,0, 'Darkfallen commander - vampire rush 10'), +(3766203,37662,0,0,100,21,3000,5000,5000,7000,11,71155,5,0,0,0,0,0,0,0,0,0, 'Darkfallen commander - vampire rush 25'); + +-- ######### +-- FROSTWING +-- ######### + +-- Frostwing whelp (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3753201 AND 3753203; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3753201,37532,0,0,100,31,5000,7000,10000,13000,11,71350,4,0,0,0,0,0,0,0,0,0, 'Frostwing whelp - focus fire'), +(3753202,37532,0,0,100,11,4000,5000,4000,5000,11,71361,4,0,0,0,0,0,0,0,0,0, 'Frostwing whelp - frost blast 10'), +(3753203,37532,0,0,100,21,4000,5000,4000,5000,11,71362,4,0,0,0,0,0,0,0,0,0, 'Frostwing whelp - frost blast 25'); +-- Ymirjar battle maiden (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3713201 AND 3713202; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3713201,37132,0,0,100,31,4000,6000,10000,11000,11,71258,0,0,0,0,0,0,0,0,0,0, 'Ymirjar battle maiden - adrenaline rush'), +(3713202,37132,0,0,100,31,5000,7000,5000,7000,11,71257,3,0,0,0,0,0,0,0,0,0, 'Ymirjar battle maiden - barbaric strike'); +-- Ymirjar deathbringer (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3812501 AND 3812507; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3812501,38125,0,0,100,31,4000,6000,6000,8000,11,71298,4,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - banish'), +(3812502,38125,0,0,100,11,7000,13000,15000,20000,11,71299,0,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - deaths embrace 10'), +(3812503,38125,0,0,100,21,7000,13000,15000,20000,11,71300,0,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - deaths embrace 25'), +(3812504,38125,0,0,100,11,4000,7000,4000,7000,11,71296,4,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - shadow bolt 10'), +(3812505,38125,0,0,100,21,4000,7000,4000,7000,11,71297,4,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - shadow bolt 25'), +(3812506,38125,16,0,100,31,69929,30,35000,50000,11,69929,6,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - spirit steam'), +(3812507,38125,0,0,100,31,20000,25000,25000,30000,11,71303,0,0,0,0,0,0,0,0,0,0, 'Ymirjar deathbringer - summon ymirjar'); +-- Ymirjar huntress (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3713401 AND 3713405; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3713401,37134,0,0,100,31,5000,10000,7000,14000,11,71249,0,0,0,0,0,0,0,0,0,0, 'Ymirjar huntress - ice trap'), +(3713402,37134,0,0,100,31,8000,13000,10000,15000,11,71251,0,0,0,0,0,0,0,0,0,0, 'Ymirjar huntress - rapid shot'), +(3713403,37134,0,0,100,31,2000,4000,2000,4000,11,71253,4,0,0,0,0,0,0,0,0,0, 'Ymirjar huntress - shoot'), +(3713404,37134,0,0,100,31,6000,8000,7000,10000,11,71252,4,0,0,0,0,0,0,0,0,0, 'Ymirjar huntress - volley'), +(3713405,37134,4,0,100,6,0,0,0,0,11,71705,0,0,0,0,0,0,0,0,0,0, 'Ymirjar huntress - summon warhawk'); +-- Ymirjar frostbinder (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712701 AND 3712703; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712701,37127,0,0,100,31,7000,10000,7000,10000,11,71306,5,0,0,0,0,0,0,0,0,0, 'Ymirjar frostbinder - twisted winds'), +(3712702,37127,0,0,100,31,15000,20000,15000,20000,11,71274,5,0,0,0,0,0,0,0,0,0, 'Ymirjar frostbinder - frozen orb'), +(3712703,37127,4,0,100,6,0,0,0,0,11,71270,0,0,0,0,0,0,0,0,0,0, 'Ymirjar frostbinder - arctic chill'); + +#-- ############### +#-- VALITHRIA EVENT +#-- ############### + +#-- Grottnous abomination +#UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=37886; +#DELETE FROM `creature_ai_scripts` WHERE `id`=3788601; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3788601,37886,0,0,100,3,7000,13000,7000,13000,11,70633,0,0,0,0,0,0,0,0,0,0, 'Gluttnous abomination - gut spray 10n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3788602; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3788602,37886,0,0,100,5,7000,13000,7000,13000,11,71283,0,0,0,0,0,0,0,0,0,0, 'Gluttnous abomination - gut spray 25n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3788603; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3788603,37886,0,0,100,9,7000,13000,7000,13000,11,72025,0,0,0,0,0,0,0,0,0,0, 'Gluttnous abomination - gut spray 10h'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3788604; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3788604,37886,0,0,100,17,7000,13000,7000,13000,11,72026,0,0,0,0,0,0,0,0,0,0, 'Gluttnous abomination - gut spray 25h'); +#-- Blistering Zombies +#UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=37934; +#DELETE FROM `creature_ai_scripts` WHERE `id`=3793401; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3793401,37934,4,0,100,31,0,0,0,0,11,70749,0,0,0,0,0,0,0,0,0,0, 'Blistering zombies - corrosion'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3793402; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3793402,37934,6,0,100,3,0,0,0,0,11,70744,0,0,0,0,0,0,0,0,0,0, 'Blistering zombies - acid burst 10n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3793403; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3793403,37934,6,0,100,5,0,0,0,0,11,71733,0,0,0,0,0,0,0,0,0,0, 'Blistering zombies - acid burst 25n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3793404; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3793404,37934,6,0,100,9,0,0,0,0,11,72017,0,0,0,0,0,0,0,0,0,0, 'Blistering zombies - acid burst 10h'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3793405; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3793405,37934,6,0,100,17,0,0,0,0,11,72018,0,0,0,0,0,0,0,0,0,0, 'Blistering zombies - acid burst 25h'); +#-- Suppresser +#UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=37863; +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786301; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786301,37863,4,0,100,31,0,0,0,0,11,70588,1,0,0,0,0,0,0,0,0,0, 'Suppresser - suppression'); +#-- Blazing Skeleton +#UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=36791; +#DELETE FROM `creature_ai_scripts` WHERE `id`=3679101; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3679101,36791,0,0,100,3,5000,10000,5000,10000,11,70754,4,0,0,0,0,0,0,0,0,0, 'Blazin skeleton - fireball 10n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3679102; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3679102,36791,0,0,100,5,5000,10000,5000,10000,11,71748,4,0,0,0,0,0,0,0,0,0, 'Blazin skeleton - fireball 25n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3679103; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3679103,36791,0,0,100,9,5000,10000,5000,10000,11,72023,4,0,0,0,0,0,0,0,0,0, 'Blazin skeleton - fireball 10h'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3679104; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3679104,36791,0,0,100,17,5000,10000,5000,10000,11,72024,4,0,0,0,0,0,0,0,0,0, 'Blazin skeleton - fireball 25h'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3679105; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3679105,36791,0,0,100,11,10000,15000,10000,15000,11,69325,0,0,0,0,0,0,0,0,0,0, 'Blazin skeleton - lay waste 10'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3679106; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3679106,36791,0,0,100,21,10000,15000,10000,15000,11,71730,0,0,0,0,0,0,0,0,0,0, 'Blazin skeleton - lay waste 10'); +-- Mana void +-- UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=38068; +DELETE FROM `creature_ai_scripts` WHERE (`creature_id`=38068); +-- INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +-- (3806801,38068,4,0,100,31,0,0,0,0,11,71085,0,0,0,0,0,0,0,0,0,0, 'Mana void - mana void aura'); +#UPDATE `creature_template` SET `modelid1` = 11686 WHERE `entry` = 38068; +#-- Risen archmage +#UPDATE `creature_template` SET `AIName`='EventAI' WHERE `entry`=37868; +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786801; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786801,37868,0,0,100,3,7000,11000,7000,11000,11,70759,0,0,0,0,0,0,0,0,0,0, 'Risen archmage - frostbolt volley 10n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786802; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786802,37868,0,0,100,5,7000,11000,7000,11000,11,71889,0,0,0,0,0,0,0,0,0,0, 'Risen archmage - frostbolt volley 25n'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786803; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786803,37868,0,0,100,9,7000,11000,7000,11000,11,72015,0,0,0,0,0,0,0,0,0,0, 'Risen archmage - frostbolt volley 10h'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786804; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786804,37868,0,0,100,17,7000,11000,7000,11000,11,72016,0,0,0,0,0,0,0,0,0,0, 'Risen archmage - frostbolt volley 25h'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786805; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786805,37868,0,0,100,11,25000,30000,25000,30000,11,71179,0,0,0,0,0,0,0,0,0,0, 'Risen archmage - mana void 10'); +#DELETE FROM `creature_ai_scripts` WHERE `id`=3786806; +#INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +#(3786806,37868,0,0,100,21,25000,30000,25000,30000,11,71741,0,0,0,0,0,0,0,0,0,0, 'Risen archmage - mana void 10'); + +-- ############ +-- SVALNA EVENT +-- ############ + +-- Captain Rupert (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712501 AND 3712503; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712501,37125,0,0,100,31,5000,7000,7000,11000,11,71787,4,0,0,0,0,0,0,0,0,0, 'Captain Rupert - fel bomb'), +(3712502,37125,0,0,100,31,7000,9000,9000,13000,11,71594,4,0,0,0,0,0,0,0,0,0, 'Captain Rupert - machine gun'), +(3712503,37125,0,0,100,31,10000,13000,15000,17000,11,71786,4,0,0,0,0,0,0,0,0,0, 'Captain Rupert - rocket'); +-- Captain Grondel (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712401 AND 3712404; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712401,37124,0,0,100,31,10000,10000,10000,10000,11,71553,5,0,0,0,0,0,0,0,0,0, 'Captain Groundel - charge'), +(3712402,37124,0,0,100,31,5000,10000,10000,15000,11,71554,3,0,0,0,0,0,0,0,0,0, 'Captain Groundel - sunder armor'), +(3712403,37124,0,0,100,31,5000,7000,5000,7000,11,71552,1,0,0,0,0,0,0,0,0,0, 'Captain Groundel - mortal strike'), +(3712404,37124,0,0,100,31,5000,9000,10000,15000,11,71785,4,0,0,0,0,0,0,0,0,0, 'Captain Groundel - conflagration'); +-- Captain Brandon (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712301 AND 3712304; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712301,37123,0,0,100,31,10000,10000,10000,10000,11,71549,1,0,0,0,0,0,0,0,0,0, 'Captain Brandon - crusader strike'), +(3712302,37123,2,0,100,30,25,24,0,0,11,71550,0,0,0,0,0,0,0,0,0,0, 'Captain Brandon - divine shield'), +(3712303,37123,0,0,100,31,5000,8000,7000,10000,11,71784,4,0,0,0,0,0,0,0,0,0, 'Captain Brandon - hammer of betrayal'), +(3712304,37123,0,0,100,31,7000,10000,8000,12000,11,71551,4,0,0,0,0,0,0,0,0,0, 'Captain Brandon - judgement of command'); +-- Captain Arnath (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712201 AND 3712207; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712201,37122,14,0,100,31,50,30,5000,10000,11,71595,6,0,0,0,0,0,0,0,0,0, 'Captain Arnath - flash heal'), +(3712202,37122,0,0,100,21,15000,20000,20000,25000,11,14515,4,0,0,0,0,0,0,0,0,0, 'Captain Arnath - dominate mind'), +(3712203,37122,16,0,100,31,71548,30,30000,35000,11,71548,6,0,0,0,0,0,0,0,0,0, 'Captain Arnath - power shield'), +(3712204,37122,0,0,100,3,5000,10000,9000,15000,11,71546,4,0,0,0,0,0,0,0,0,0, 'Captain Arnath - smite 10n'), +(3712205,37122,0,0,100,5,5000,10000,9000,15000,11,71547,4,0,0,0,0,0,0,0,0,0, 'Captain Arnath - smite 25n'), +(3712206,37122,0,0,100,9,5000,10000,9000,15000,11,71778,4,0,0,0,0,0,0,0,0,0, 'Captain Arnath - smite 10h'), +(3712207,37122,0,0,100,17,5000,10000,9000,15000,11,71779,4,0,0,0,0,0,0,0,0,0, 'Captain Arnath - smite 25h'); +-- Crok and Svalna need SD2 script +-- this is just a basic of spells +-- Crok Scourgebane (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712901 AND 3712904; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712901,37129,0,0,100,31,5000,7000,7000,9000,11,71489,1,0,0,0,0,0,0,0,0,0, 'Crock Scrougebane - deathstrike'), +(3712902,37129,0,0,100,31,7000,9000,10000,12000,11,71488,1,0,0,0,0,0,0,0,0,0, 'Crock Scrougebane - scourgestrike'), +(3712903,37129,0,0,100,21,10000,15000,10000,15000,11,71490,4,0,0,0,0,0,0,0,0,0, 'Crock Scrougebane - deathcoil'), +(3712904,37129,4,0,100,6,0,0,0,0,39,30,0,0,0,0,0,0,0,0,0,0, 'Crock Scrougebane - call for help'); +-- Svalna (need compare with YTDB) +DELETE FROM `creature_ai_scripts` WHERE `id` BETWEEN 3712601 AND 3712604; +INSERT INTO `creature_ai_scripts` (`id`,`creature_id`,`event_type`,`event_inverse_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action1_type`,`action1_param1`,`action1_param2`,`action1_param3`,`action2_type`,`action2_param1`,`action2_param2`,`action2_param3`,`action3_type`,`action3_param1`,`action3_param2`,`action3_param3`,`comment`) VALUES +(3712601,37126,4,0,100,6,0,0,0,0,11,71465,0,0,0,0,0,0,0,0,0,0, 'Sister Svalna - divine surge'), +(3712602,37126,0,0,100,11,15000,20000,20000,25000,11,71468,0,0,0,0,0,0,0,0,0,0, 'Sister Svalna - aether burst 10'), +(3712603,37126,0,0,100,21,15000,20000,20000,25000,11,71469,0,0,0,0,0,0,0,0,0,0, 'Sister Svalna - aether burst 25'), +(3712604,37126,0,0,100,31,25000,30000,60000,70000,11,70196,5,0,11,71463,0,0,0,0,0,0, 'Sister Svalna - sprear'); + +-- from Ulduar +-- PreSindragosa_Event. +DELETE FROM `spell_template` WHERE id=75001; +INSERT INTO `spell_template` (`id`, `attr`, `attr_ex`, `attr_ex2`, `attr_ex3`, `proc_flags`, `proc_chance`, `duration_index`, `effect0`, `effect0_implicit_target_a`, `effect0_implicit_target_b`, `effect0_radius_idx`, `effect0_apply_aura_name`, `effect0_misc_value`, `effect0_misc_value_b`, `effect0_trigger_spell`, `comments`) VALUES('75001','0','0','0','0','0','101','21','28','42','0','13','0','132001','64','0','Summon Dark Matter'); + +DELETE FROM `creature_template` WHERE (`entry`=132001); +INSERT INTO `creature_template` (`Entry`, `Name`, `SubName`, `IconName`, `MinLevel`, `MaxLevel`, `DifficultyEntry1`, `DifficultyEntry2`, `DifficultyEntry3`, `ModelId1`, `ModelId2`, `ModelId3`, `ModelId4`, `FactionAlliance`, `FactionHorde`, `Scale`, `Family`, `CreatureType`, `InhabitType`, `RegenerateStats`, `RacialLeader`, `NpcFlags`, `UnitFlags`, `DynamicFlags`, `ExtraFlags`, `CreatureTypeFlags`, `SpeedWalk`, `SpeedRun`, `UnitClass`, `Rank`, `Expansion`, `HealthMultiplier`, `PowerMultiplier`, `DamageMultiplier`, `DamageVariance`, `ArmorMultiplier`, `ExperienceMultiplier`, `MinLevelHealth`, `MaxLevelHealth`, `MinLevelMana`, `MaxLevelMana`, `MinMeleeDmg`, `MaxMeleeDmg`, `MinRangedDmg`, `MaxRangedDmg`, `Armor`, `MeleeAttackPower`, `RangedAttackPower`, `MeleeBaseAttackTime`, `RangedBaseAttackTime`, `DamageSchool`, `MinLootGold`, `MaxLootGold`, `LootId`, `PickpocketLootId`, `SkinningLootId`, `KillCredit1`, `KillCredit2`, `QuestItem1`, `QuestItem2`, `QuestItem3`, `QuestItem4`, `QuestItem5`, `QuestItem6`, `MechanicImmuneMask`, `ResistanceHoly`, `ResistanceFire`, `ResistanceNature`, `ResistanceFrost`, `ResistanceShadow`, `ResistanceArcane`, `PetSpellDataId`, `MovementType`, `MovementTemplateId`, `TrainerType`, `TrainerSpell`, `TrainerClass`, `TrainerRace`, `TrainerTemplateId`, `VendorTemplateId`, `EquipmentTemplateId`, `VehicleTemplateId`, `GossipMenuId`, `AIName`, `ScriptName`) VALUES +('132001','Unleashed Dark Matter','','','81','81','0','0','0','18050','0','0','0','4','6','1','0','10','3','2','0','0','32768','0','0','4160','1','1.14286','1','1','-1','10','1','3','1','1','1','290000','290000','0','0','436','654','349','523','10029','163','130','2000','2000','0','0','0','0','0','0','0','0','0','0','0','0','0','0','8193','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','EventAI',''); + +-- Creature id: 132001 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '132001'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=132001; +INSERT INTO `creature_ai_scripts` VALUES +('13200101','132001','11','0','100','30','0','0','0','0','17','32','292000','0','17','33','30000','0','17','24','292000','0','Set Max Health and Mana and Current Health at Spawn.'), +('13200102','132001','10','0','100','30','0','1000','0','0','38','0','0','0','13','100','6','0','0','0','0','0','Set Combat and Threat at OOC LOS 1000 yards.'), +('13200103','132001','12','0','100','30','5','5','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Force Despawn at target hp <5 Percent.'), +('13200104','132001','0','0','100','31','10000','10000','10000','10000','11','4507','1','2','0','0','0','0','0','0','0','0','Cast Taunt.'), +('13200105','132001','10','0','100','30','0','100','0','0','13','100','6','0','11','4507','6','10','39','20','0','0','Set Combat and Threat at OOC LOS 100 yards and Cast Taunt.'), +('13200106','132001','1','0','100','30','30000','30000','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Force Despawn in OOC Timer.'), +('13200107','132001','11','0','100','30','0','0','0','0','17','25','30000','0','0','0','0','0','0','0','0','0','Set Mana 30000 at spawn.'), +('13200108','132001','6','0','100','30','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Despawn at death.'), +('13200109','132001','0','0','100','31','3000','3000','7000','9000','11','75384','1','14','0','0','0','0','0','0','0','0','Cast Shadow Bolt.'), +('13200110','132001','0','0','100','31','2600','14700','16500','22400','11','73805','0','14','0','0','0','0','0','0','0','0','Cast Explosion.'), +('13200111','132001','11','0','100','30','0','0','0','0','2','6','0','0','0','0','0','0','0','0','0','0','Set Faction 6 at spawn.'), +('13200112','132001','2','0','100','30','50','0','0','0','17','24','292000','0','0','0','0','0','0','0','0','0','Get Health Full at 50% HP.'), +('13200113','132001','21','0','100','30','0','0','0','0','41','0','0','0','0','0','0','0','0','0','0','0','Force despawn Just Reached Home.'); +-- ERROR CreatureEventAI: Creature 132001 are using percentage event(13200103) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! + + +DELETE FROM `creature_ai_summons` WHERE `id` IN (1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580); +INSERT INTO `creature_ai_summons` VALUES +(1571, 4167.64, 2521.10, 211.033, 5.20468, 300000, 'Spider Sindragosa Ward.'), +(1572, 4153.39, 2509.87, 211.033, 5.1698, 300000, 'Spider Sindragosa Ward.'), +(1573, 4195.66, 2519.99, 211.033, 4.44643, 300000, 'Spider Sindragosa Ward.'), +(1574, 4214.11, 2501.91, 211.033, 3.91093, 300000, 'Spider Sindragosa Ward.'), +(1575, 4186.58, 2403.26, 211.033, 1.63162, 300000, 'Frostwarden Sindragosa Ward'), +(1576, 4182.35, 2403.33, 211.033, 1.71824, 300000, 'Frostwarden Sindragosa Ward'), +(1577, 4173.8, 2402.91, 211.033, 1.64624, 300000, 'Frostwarden Sindragosa Ward'), +(1578, 4173.62, 2564.28, 211.033, 4.77937, 300000, 'Frostwarden Sindragosa Ward'), +(1579, 4182.44, 2565.95, 211.033, 4.47787, 300000, 'Frostwarden Sindragosa Ward'), +(1580, 4189.71, 2565.48, 211.033, 4.59937, 300000, 'Frostwarden Sindragosa Ward'); + +-- Creature id: 37503 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '37503'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=37503; +INSERT INTO `creature_ai_scripts` VALUES +('3750301','37503','11','0','100','30','0','0','0','0','2','14','1','0','18','33554432','0','0','0','0','0','0','Spider Event Controller - Set Faction 14 and Set Unit_Flag Not Selectable.'), +('3750302','37503','0','0','100','31','180000','180000','180000','180000','34','10','2','0','41','2000','0','0','0','0','0','0','Spider Event Controller - Force Despawn and Stop Event.'), +('3750303','37503','17','0','100','30','0','1000','1000','0','38','0','0','0','0','0','0','0','0','0','0','0','Summoned all - Set In Combat.'), +('3750304','37503','0','0','100','31','60000','60000','60000','60000','32','37228','1','1578','32','37229','1','1579','32','37228','1','1580','Spider Event Controller - Summon Frostwarden Warrior and Sorceress'), +('3750305','37503','0','0','100','31','60000','60000','60000','60000','32','37228','1','1575','32','37229','1','1576','32','37228','1','1577','Spider Event Controller - Summon Frostwarden Warrior and Sorceress'), +('3750306','37503','0','0','100','31','3000','3000','20000','20000','32','37501','1','1754','0','0','0','0','0','0','0','0','Spider Event Controller - Summon Nerub Champion.'), +('3750307','37503','4','0','100','30','0','0','0','0','21','0','0','0','20','0','0','0','4','17167','0','0','Spider Event Controller - Preevent Stop Combat Movement and False Auto Attack and Play sound.'), +('3750308','37503','10','0','100','31','0','500','1000','1000','38','0','0','0','0','0','0','0','0','0','0','0','Spider Event Controller - Start Event'), +('3750309','37503','0','0','100','31','3000','3000','20000','20000','32','37501','1','1571','32','37502','1','1573','32','37501','1','1572','Spider Event Controller - Summon Nerub Champion and Webweaver.'); +-- ERROR CreatureEventAI: Event 3750306 Action 1 summons missing CreatureEventAI_Summon 1754 +-- ERROR CreatureEventAI: Creature 37503 are using event(3750303) with nonexistent creature template id (0) in param1, skipped. + +-- Creature id: 37502 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '37502'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=37502; +INSERT INTO `creature_ai_scripts` VALUES +('3750201','37502','0','0','100','31','0','0','2500','3000','11','71326','1','8','29','10','0','0','20','0','0','0','Nerub Webweaver - Cast Crypt Scarabs and Ranged Movement and False Auto Attack.'); + +-- Creature id: 37501 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '37501'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=37501; +INSERT INTO `creature_ai_scripts` VALUES +('3750101','37501','0','0','100','31','1000','1000','10000','10000','11','71801','1','10','0','0','0','0','0','0','0','0','Nerub Champion - Cast Rush.'); + +-- Creature id: 38199 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '38199'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=38199; +INSERT INTO `creature_ai_scripts` VALUES +('3819901','38199','11','0','100','30','0','0','0','0','18','33555078','0','0','11','71324','0','2','41','7000','0','0','Frost Blade - Cast Frost Blade and Set Unit_Flags and Force Despawn 7 seconds at Spawn.'); + +-- Creature id: 37228 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '37228'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=37228; +INSERT INTO `creature_ai_scripts` VALUES +('3722801','37228','0','0','100','31','3000','3000','15000','17000','11','71325','1','10','0','0','0','0','0','0','0','0','Frostwarden Warrior - Cast FrostBlade.'), +('3722802','37228','0','0','100','31','9000','9000','20000','20000','11','71317','1','2','0','0','0','0','0','0','0','0','Frostwarden Warrior - Cast Glacial Strike.'); + +-- Creature id: 37229 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '37229'; +DELETE FROM `creature_ai_scripts` WHERE creature_id=37229; +INSERT INTO `creature_ai_scripts` VALUES +('3722901','37229','0','0','100','31','4000','4000','11000','13000','11','71320','1','2','0','0','0','0','0','0','0','0','Frostwarden Sorceress - Cast Frost Nova.'), +('3722902','37229','0','0','100','31','7000','7000','16000','21000','11','71318','1','9','0','0','0','0','0','0','0','0','Frostwarden Sorceress - Cast Frostbolt.'), +('3722903','37229','0','0','100','31','9000','9000','23000','27000','11','71331','1','10','0','0','0','0','0','0','0','0','Frostwarden Sorceress - Cast Ice Tomb.'); + +DELETE FROM `creature_template_addon` WHERE `entry` IN (37501, 38197, 37502, 38198); + +UPDATE `db_script_string` SET `content_loc8` = 'Я пробудился...' WHERE `entry` = 2000009996; +UPDATE `db_script_string` SET `content_loc8` = 'В покои господина проникли!' WHERE `entry` = 2000009997; +UPDATE `db_script_string` SET `content_loc8` = 'Кто... идет?' WHERE `entry` = 2000009998; diff --git a/sql_mr/mr00640_mangos_icecrown.sql b/sql_mr/mr00640_mangos_icecrown.sql new file mode 100644 index 0000000000..42ea17a33d --- /dev/null +++ b/sql_mr/mr00640_mangos_icecrown.sql @@ -0,0 +1,22 @@ +-- +-- ICC start event. Mangos part. +-- + +-- The Damned +DELETE FROM creature_ai_scripts WHERE creature_id = 37011; +UPDATE creature_template SET AIName = '', ScriptName = 'npc_the_damned_lh' WHERE entry = 37011; + +-- Highlord Tirion Fordring +UPDATE creature_template SET ScriptName = 'npc_tirion_fordring_lh' WHERE entry = 37119; + +-- High Overlord Saurfang +UPDATE creature_template SET NpcFlags = 0 WHERE entry = 37187; +DELETE FROM creature WHERE id = 37187; +INSERT INTO creature (guid,id,map,spawnMask,phaseMask,modelid,equipment_id,position_x,position_y,position_z,orientation,spawntimesecs,spawndist,currentwaypoint,curhealth,curmana,DeathState,MovementType) VALUES +(600028, 37187, 631, 15, 64, 0, 0, -48.9097, 2211.06, 27.9859, 3.15905, 7200, 0, 0, 4183500, 0, 0, 0); + +-- Muradin Bronzebeard +UPDATE creature_template SET NpcFlags = 0 WHERE entry = 37200; +DELETE FROM creature WHERE id = 37200; +INSERT INTO creature (guid,id,map,spawnMask,phaseMask,modelid,equipment_id,position_x,position_y,position_z,orientation,spawntimesecs,spawndist,currentwaypoint,curhealth,curmana,DeathState,MovementType) VALUES +(600029, 37200, 631, 15, 128, 0, 0, -48.9097, 2211.06, 27.9859, 3.15905, 7200, 0, 0, 4183500, 0, 0, 0); diff --git a/sql_mr/mr00640_scriptdev2_icecrown.sql b/sql_mr/mr00640_scriptdev2_icecrown.sql new file mode 100644 index 0000000000..7a89592e2c --- /dev/null +++ b/sql_mr/mr00640_scriptdev2_icecrown.sql @@ -0,0 +1,34 @@ +-- +-- ICC start event. SD2 part. +-- + +DELETE FROM script_texts WHERE entry BETWEEN -1020521 AND -1020500; +INSERT INTO script_texts (entry, content_default, content_loc8, sound, type, emote, comment) VALUES +-- Highlord Tirion Fordring +(-1020500, 'This is our final stand. What happens here will echo through the ages. Regardless of outcome, they will know that we fought with honor. That we fought for the freedom and safety of our people!', 'Вот мы и на месте. То, что произойдёт здесь, войдёт в легенды. Не важно, каким будет исход. Для истории мы будем героями сражавшимися за свободу и покой своего народа!', 16653, 1, 22, 'Highlord Tirion Fordring - SAY_TIRION_INTRO_1'), +(-1020501, 'Remember, heroes, fear is your greatest enemy in these befouled halls. Steel your heart and your soul will shine brighter than a thousand suns. The enemy will falter at the sight of you. They will fall as the light of righteousness envelops them!', 'Помните герои - страх ваш самый опасный противник в этих проклятых залах. Скрепите свои сердца и ваши души воссияют ярче тысячи солнц. Завидев вас враг отступит, враг падёт, когда свет праведности коснётся его!', 16654, 1, 22, 'Highlord Tirion Fordring - SAY_TIRION_INTRO_2'), +(-1020502, 'Our march upon Icecrown Citadel begins now!', 'Наш поход на Цитадель Ледяной Короны начинается!', 16655, 1, 22, 'Highlord Tirion Fordring - SAY_TIRION_INTRO_3'), +(-1020503, 'ARTHAS! I swore that I would see you dead and the Scourge dismantled! I''m going to finish what I started at Light''s Hope!', 'АРТАС! Я поклялся, что ты умрёшь, а Плеть будет разбита. Я закончу то, что начал у часовни Последней надежды!', 16656, 1, 0, 'Highlord Tirion Fordring - SAY_TIRION_INTRO_4'), +(-1020504, 'The power of the Light knows no bounds, Saurfang. His soul is under great strain, but he lives - for now.', 'Сила Света не ведает преград, Саурфанг. Его душа безмерно страдает, и всё же пока он жив.', 16658, 1, 0, 'Highlord Tirion Fordring - SAY_TIRION_INTRO_H_5'), +(-1020505, 'By the Light, it must be so!', 'Да будет так, во имя Света!', 16657, 0, 5, 'Highlord Tirion Fordring - SAY_TIRION_INTRO_A_5'), +-- The Lich King +(-1020506, 'You now stand upon the hallowed ground of the Scourge. The Light won''t protect you here, paladin. Nothing will protect you...', 'Вы находитесь в самом сердце земель Плети. Здесь вас не защитит Свет, ничто вас не защитит...', 17230, 1, 22, 'The Lich King - SAY_LK_INTRO_1'), +(-1020507, 'You could have been my greatest champion, Fordring: A force of darkness that would wash over this world and deliver it into a new age of strife.', 'Ты бы мог стать величайшим из моих рыцарей Фордринг: той силой Тьмы, которая прокатилась бы по этому миру и перевернула страницу истории.', 17231, 1, 0, 'The Lich King - SAY_LK_INTRO_2'), +(-1020508, 'But that honor is no longer yours. Soon,I will have a new champion.', 'Но тебе уже не суждено им стать. Скоро у меня будет другой рыцарь.', 17232, 1, 0, 'The Lich King - SAY_LK_INTRO_3'), +(-1020509, 'The breaking of this one has been taxing. The atrocities I have committed upon his soul. He has resisted for so long, but he will bow down before his king soon.', 'Сломить его было очень трудно. Я подверг его душу ужасным мучениям. Он так долго сопротивлялся, но вскоре он склонится перед своим королём.', 17233, 1, 0, 'The Lich King - SAY_LK_INTRO_4'), +(-1020510, 'In the end, you will all serve me.', 'В конце концов все вы будете служить мне.', 17234, 1, 0, 'The Lich King - SAY_LK_INTRO_5'), +-- Highlord Bolvar Fordragon +(-1020511, 'NEVER! I... I will never... serve... you...', 'НИКОГДА! Я... никогда... не буду служить тебе...', 17078, 1, 0, 'Highlord Bolvar Fordragon - SAY_BOLVAR_INTRO_1'), +-- High Overlord Saurfang +(-1020512, 'The paladin still lives? Is it possible, Highlord? Could he have survived?', 'Паладин ещё жив? Верховный Лорд, возможно ли это?', 17107, 0, 6, 'High Overlord Saurfang - SAY_SAURFANG_INTRO_1'), +(-1020513, 'Then we must save him! If we rescue Bolvar Fordragon, we may quell the unrest between the Alliance and the Horde.', 'Мы должны спасти его! Если мы спасём Болвара Фолдрагона, напряжение между Ордой и Альянсом спадёт.', 17108, 0, 5, 'High Overlord Saurfang - SAY_SAURFANG_INTRO_2'), +(-1020514, 'Our mission is now clear: The Lich King will answer for his crimes and we will save Highlord Bolvar Fordragon!', 'Теперь наша задача ясна: мы заставим Короля-лича ответить за все злодеяния и спасём Паладина.', 17109, 0, 15, 'High Overlord Saurfang - SAY_SAURFANG_INTRO_3'), +(-1020515, 'Kor''kron, prepare Orgrim''s Hammer for its final voyage! Champions, our gunship will find a point to dock on the upper reaches of the citadel. Meet us there!', 'Коркрон, готовьте Молот Оргрима к последнему полёту. Герои! Мы попробуем подлететь к стене Цитадели и будем ждать вас там!', 17110, 1, 22, 'High Overlord Saurfang - SAY_SAURFANG_INTRO_4'), +-- Muradin Bronzebeard +(-1020516, 'Could it be, Lord Fordring? If Bolvar lives, mayhap there is hope fer peace between the Alliance and the Horde. We must reach the top o'' this cursed place and free the paladin!', 'Что же это? Если Болвар жив, то может есть надежда на мир между Альянсом и Ордой? Нужно попасть на верхушку этой проклятой башни и освободить Паладина.', 16980, 0, 6, 'Muradin Bronzebeard - SAY_MURADIN_INTRO_1'), +(-1020517, 'Prepare the Skybreaker fer an aerial assault on the citadel!', 'Подготовить Усмиритель Небес к воздушной атаке на Цитадель!', 16981, 1, 5, 'Muradin Bronzebeard - SAY_MURADIN_INTRO_2'), +(-1020518, 'Heroes, ye must fight yer way to a clear extraction point within Icecrown. We''ll try an'' rendezvous on the ramparts!', 'Герои, попытайтесь выбраться на бастион. Попробуем встретиться с вами там.', 16982, 1, 22, 'Muradin Bronzebeard - SAY_MURADIN_INTRO_3'), +-- Emotions +(-1020519, 'emote only', NULL, 0, 7, 5, 'EMOTE_EXCLAMATION'), +(-1020520, 'emote only', NULL, 0, 7, 397, 'EMOTE_POINT_NOSHEATHE'), +(-1020521, 'emote only', NULL, 0, 7, 1, 'EMOTE_TALK'); diff --git a/sql_mr/mr00707_mangos_dalaran_minigob.sql b/sql_mr/mr00707_mangos_dalaran_minigob.sql new file mode 100644 index 0000000000..14a6113129 --- /dev/null +++ b/sql_mr/mr00707_mangos_dalaran_minigob.sql @@ -0,0 +1,30 @@ + +SET @ENTRY_MINIGOB = 32838; +SET @GUID_MINIGOB = 54553; + +SET @EVENT_ID = 105; + +SET @MAIL_TEMPLATE = 264; +SET @MAIL_ITEM = 44817; + +-- mail loot +DELETE FROM `mail_loot_template` WHERE `entry` = @MAIL_TEMPLATE; +INSERT INTO `mail_loot_template` (`entry`, `item`) VALUES (@MAIL_TEMPLATE, @MAIL_ITEM); + +-- creature script +DELETE FROM `creature_ai_scripts` WHERE `creature_id` = @ENTRY_MINIGOB; +UPDATE `creature_template` SET AIName = '', `ScriptName`='npc_minigob_manabonk' WHERE `entry` = @ENTRY_MINIGOB; + +-- creature spawn +DELETE FROM `creature` WHERE `id` = @ENTRY_MINIGOB; +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +(@GUID_MINIGOB, @ENTRY_MINIGOB, 571, 1, 65535, 0, 0, 5854.42, 660.31, 647.512, 3.71924, 300, 0, 0, 3347, 8139, 0, 0); + +-- game event to spawn the npc +DELETE FROM `game_event_creature` WHERE `guid` = @GUID_MINIGOB; +INSERT INTO `game_event_creature` (`guid`, `event`) VALUES +(@GUID_MINIGOB, @EVENT_ID); + +DELETE FROM `game_event` WHERE `entry` = @EVENT_ID; +INSERT INTO `game_event` (`entry`, `start_time`, `end_time`, `occurence`, `length`, `holiday`, `description`) VALUES +(@EVENT_ID, '2014-08-19 00:10:00', '2020-12-31 01:00:00', 30, 5, 0, 'Dalaran: Minigob Manabonk'); diff --git a/sql_mr/mr00709_scriptdev2_dalaran_vendors.sql b/sql_mr/mr00709_scriptdev2_dalaran_vendors.sql new file mode 100644 index 0000000000..044d3fabfa --- /dev/null +++ b/sql_mr/mr00709_scriptdev2_dalaran_vendors.sql @@ -0,0 +1,17 @@ + +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN + (28714,28715,28718,28721,28723,28725,28726,28727,28989,28994,28997,29491,29523,33027); + +UPDATE `creature_template` SET AIName = '', `ScriptName`='npc_dalaran_vendor' WHERE `entry` IN + (28714,28715,28718,28721,28723,28725,28726,28727,28989,28994,28997,29491,29523,33027); + +INSERT INTO script_texts + (entry, content_default, content_loc8, sound, type, language, emote, comment) +VALUES + (-1020384, "Welcome.", "Добро пожаловать.", 0, 0, 0, 3, "SAY_VENDOR_1"), + (-1020385, "Welcome!", "Добро пожаловать!", 0, 0, 0, 3, "SAY_VENDOR_2"), + (-1020386, "Welcome. May I help you find something?", "Добро пожаловать. Могу ли я вам помочь что то найти?", 0, 0, 0, 3, "SAY_VENDOR_3"), + (-1020387, "Greetings.", "Приветствую.", 0, 0, 0, 3, "SAY_VENDOR_4"), + (-1020388, "Greetings, $C.", "Приветствую $C.", 0, 0, 0, 3, "SAY_VENDOR_5"), + (-1020389, "Greetings! Please have a look around.", "Приветствую! Пожалуйста, посмотрите вокруг.", 0, 0, 0, 3, "SAY_VENDOR_6"), + (-1020390, "Let me know if you need help finding anything, $C.", "Дайте мне знать, если вам нужна помощь найти что-нибудь, $C.", 0, 0, 0, 3, "SAY_VENDOR_7"); diff --git a/sql_mr/mt00001_mangos_Baleroc_AI.sql b/sql_mr/mt00001_mangos_Baleroc_AI.sql new file mode 100644 index 0000000000..45e0582e86 --- /dev/null +++ b/sql_mr/mt00001_mangos_Baleroc_AI.sql @@ -0,0 +1,63 @@ +-- Creature id: 53494 Boss Baleroc in Firelands. +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '53494'; +DELETE FROM creature_ai_scripts WHERE creature_id=53494; +INSERT INTO creature_ai_scripts VALUES +('5349401','53494','0','0','100','31','360000','360000','360000','360000','1','-534944','0','0','11','82395','0','2','0','0','0','0','Yell just Berserk and Cast Berserk.'), +('5349402','53494','21','0','100','30','0','0','0','0','41','6000','0','0','18','262790','0','0','11','8677','0','3','Force despawn and Set Unit Flag and cast Send Event(Resummon)'), +('5349403','53494','6','0','100','30','0','0','0','0','1','-534942','0','0','0','0','0','0','0','0','0','0','Yell jist death.'), +('5349404','53494','0','0','100','24','8000','8000','45000','45000','11','99516','5','38','11','99516','3','38','0','0','0','0','Cast Countdown(Only Heroic). Need Core support and script support target.'), +('5349405','53494','23','0','100','31','99352','1','4000','4000','11','99353','1','2','0','0','0','0','0','0','0','0','Cast Decimation Strike just has aura Decimation Blade. Need core support. Temp hack.'), +('5349406','53494','23','0','100','31','99350','1','4000','4000','11','99351','1','2','0','0','0','0','0','0','0','0','Cast Inferno Strike just has aura Inferno Blade. Need core support. Temp hack.'), +('5349407','53494','0','0','100','63','30000','30000','30000','32000','11','99350','0','1','11','99352','0','1','0','0','0','0','Cast Random Blades.'), +('5349408','53494','0','0','100','63','30000','30000','30000','32000','1','-534945','0','0','1','-534946','0','0','0','0','0','0','Random Yell just cast Blades.'), +('5349409','53494','0','0','100','31','10000','10000','34000','35000','1','-534943','0','0','11','99259','0','0','0','0','0','0','Cast Torment shard and Yell.'), +('5349410','53494','4','0','100','30','0','0','0','0','1','-534947','0','0','0','0','0','0','0','0','0','0','Yell Aggro'), +('5349411','53494','0','0','100','31','5000','5000','15000','15000','11','99252','1','2','11','99369','0','2','0','0','0','0','Cast Vital Flame on Hostile and Searing Soul on self.'); + + +-- Text id: -534941 +DELETE FROM creature_ai_texts WHERE entry=-534947; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-534947','You are forbidden from my master\'s domain, mortals.','24441','6','0','','0'); +-- Text id: -534942 +DELETE FROM creature_ai_texts WHERE entry=-534942; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-534942','Mortal filth... the master\\\'s keep is forbidden...','24444','6','0','','0'); + +-- Text id: -534943 +DELETE FROM creature_ai_texts WHERE entry=-534943; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-534943','Fool mortals. Hurl yourselves into your own demise!','24446','6','0','','0'); + +-- Text id: -534944 +DELETE FROM creature_ai_texts WHERE entry=-534944; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-534944','None shall pass!','24452','6','0','','0'); + +-- Text id: -534945 +DELETE FROM creature_ai_texts WHERE entry=-534945; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-534945','By the Firelord\'s command, you, too, shall perish!','24447','6','0','','0'); + +-- Text id: -534946 +DELETE FROM creature_ai_texts WHERE entry=-534946; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-534946','Burn beneath my molten fury!','24459','6','0','','0'); + +-- Script id: 1428 +DELETE FROM dbscripts_on_event WHERE id=1428; +INSERT INTO dbscripts_on_event VALUES +(1428,0,10,53494,692000000,0,0,0,0,0,0,0,95.1545,-63.2031,54.9362,3.14159,'Summon Baleroc'), +(1428,5,10,7273,600000,0,0,0,0,0,0,0,1698.13,1222.45,8.88,3.97,'YTDB.'), +(1428,0,10,10506,600000,0,0,0,0,0,0,0,323.17,93.81,101.64,3.18,'YTDB.'); + + + +-- Script id: 99259 +DELETE FROM dbscripts_on_spell WHERE id=99259; +INSERT INTO dbscripts_on_spell VALUES +(99259,0,10,53495,30000,0,0,0,0,0,0,0,64.7848,-54.0725,54.3531,6.07324,'Summon Torment Shards.'), +(99259,0,10,53495,30000,0,0,0,0,0,0,0,77.788,-56.5305,54.8829,0.011738,'Summon Torment Shards.'); + + + diff --git a/sql_mr/mt00002_mangos_Ultraxion_AI.sql b/sql_mr/mt00002_mangos_Ultraxion_AI.sql new file mode 100644 index 0000000000..b7db08e8f5 --- /dev/null +++ b/sql_mr/mt00002_mangos_Ultraxion_AI.sql @@ -0,0 +1,83 @@ +-- Creature id: 55294 +UPDATE creature_template SET AIName='EventAI' WHERE entry=55294; +DELETE FROM creature_ai_scripts WHERE creature_id=55294; +INSERT INTO creature_ai_scripts VALUES +('5529401','55294','11','0','100','30','0','0','0','0','1','-552944','0','0','18','130','0','0','0','0','0','0','Yell Intro 1 and Set Unit Flag.'), +('5529402','55294','1','0','100','30','13000','13000','69200000','69200000','1','-552945','0','0','0','0','0','0','0','0','0','0','Yell Intro 2.'), +('5529403','55294','1','0','100','31','11000','11000','69200000','69200000','19','130','0','0','18','32836','0','0','0','0','0','0','Remove Unit Flag and Set Unit Flag.'), +('5529404','55294','7','0','100','30','0','0','0','0','41','8000','0','0','11','106388','0','0','1','-552942','0','0','Despawn at Evade.'), +('5529405','55294','0','0','100','31','35000','36000','45500','45500','11','106371','1','1','1','-552949','0','0','0','0','0','0','Cast Hour of Twilight and Yell.'), +('5529406','55294','4','0','100','30','0','0','0','0','11','106372','0','0','1','-552941','0','0','21','0','1','0','Cast Unstable Monstrosity and Yell and Set Combat Movement False.'), +('5529407','55294','0','0','100','31','60000','60000','60000','60000','1','-552939','0','0','11','106372','0','4','0','0','0','0','Cast Unstable Monstrosity on self and Yell.'), +('5529408','55294','6','0','100','30','0','0','0','0','1','-552943','0','0','0','0','0','0','0','0','0','0','Yell at death.'), +('5529409','55294','0','0','100','30','360000','360000','23000','23000','1','-552942','0','0','11','106388','1','1','41','8000','0','0','Cast Twilight Eruption and Yell and Force Despawn(Hard Enrage)'), +('5529410','55294','5','0','100','31','1200','1200','0','0','1','-552946','-552947','-552948','0','0','0','0','0','0','0','0','Yell at Kill.'), +('5529411','55294','0','0','100','31','117000','130000','117000','130000','1','-552946','-552947','-552948','0','0','0','0','0','0','0','0','Random Yell in Timer Combat. Custom.'), +('5529412','55294','23','0','100','31','106372','1','6000','6000','11','109182','8','10','0','0','0','0','0','0','0','0','Cast Unstable Twilight has aura 106372. Temp Hack. Need core support.'), +('5529413','55294','9','0','100','31','60','100','3000','3000','11','106415','1','0','0','0','0','0','0','0','0','0','Cast Twilight Blast at Melee Range Ultraxion.'); + + +-- Text id: -552939 +DELETE FROM creature_ai_texts WHERE entry=-552939; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552939','Through the pain and fire my hatred burns!','26325','6','0','','0'); + +-- Text id: -552941 +DELETE FROM creature_ai_texts WHERE entry=-552941; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552941','Now is the hour of twilight!','26314','6','0','','0'); + +-- Text id: -552942 +DELETE FROM creature_ai_texts WHERE entry=-552942; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552942','I WILL DRAG YOU WITH ME INTO FLAME AND DARKNESS!','26315','6','0','','0'); + +-- Text id: -552943 +DELETE FROM creature_ai_texts WHERE entry=-552943; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552943','But...but...I am...Ul...trax...ionnnnnn...','26316','6','0','','0'); + +-- Text id: -552944 +DELETE FROM creature_ai_texts WHERE entry=-552944; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552944','I am the beginning of the end...the shadow which blots out the sun...the bell which tolls your doom...','26317','6','0','','0'); + +-- Text id: -552945 +DELETE FROM creature_ai_texts WHERE entry=-552945; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552945','For this moment ALONE was I made. Look upon your death, mortals, and despair!','26318','6','0','','0'); + +-- Text id: -552946 +DELETE FROM creature_ai_texts WHERE entry=-552946; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552946','Fall before Ultraxion!','26319','6','0','','0'); + +-- Text id: -552947 +DELETE FROM creature_ai_texts WHERE entry=-552947; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552947','Hahahahaha!','26321','6','0','','0'); + +-- Text id: -552948 +DELETE FROM creature_ai_texts WHERE entry=-552948; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552948','You have no hope!','26320','6','0','','0'); + +-- Text id: -552949 +DELETE FROM creature_ai_texts WHERE entry=-552949; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-552949','The final shred of light fades, and with it, your pitiful mortal existence!','26323','6','0','','0'); + +DELETE FROM db_script_string WHERE entry IN (2000009995); +INSERT INTO `db_script_string` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`, `sound`, `type`, `language`, `emote`, `comment`) values('2000009995','I sense a great disturbance in the balance approaching. The chaos of it burns my mind!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Я чувствую приближение Хаоса. Мой разум не в силах этого выдержать.','26148','0','0','0',NULL); +DELETE FROM `npc_text` WHERE (`ID`=56667); +INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `lang0`, `prob0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `lang1`, `prob1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `lang2`, `prob2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `lang3`, `prob3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `lang4`, `prob4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `lang5`, `prob5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `lang6`, `prob6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `lang7`, `prob7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`) values('56667','Help combat Ultraxion.',NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0',NULL,NULL,'0','0','0','0','0','0','0','0'); +DELETE FROM `gossip_menu` WHERE entry = 13322; +INSERT INTO `gossip_menu` (`entry`, `text_id`, `script_id`, `condition_id`) VALUES +(13322,'56667','0','0'); +DELETE FROM `gossip_menu_option` WHERE `menu_id` = 13322; +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `action_script_id`, `box_coded`, `box_money`, `box_text`, `condition_id`) VALUES +(13322,'0','0','I ready.','1','1','-1','0','13322','0','0',NULL,'0'); +DELETE FROM `dbscripts_on_gossip` WHERE id=13322; +INSERT INTO `dbscripts_on_gossip` (`id`, `delay`, `command`, `datalong`, `datalong2`, `buddy_entry`, `search_radius`, `data_flags`, `dataint`, `dataint2`, `dataint3`, `dataint4`, `x`, `y`, `z`, `o`, `comments`) values('13322','6','10','55294','692000000','0','0','0','0','0','0','0','-1699.75','-2384.89','345.579','3.27604','Summon Ultraxion.'); +INSERT INTO `dbscripts_on_gossip` (`id`, `delay`, `command`, `datalong`, `datalong2`, `buddy_entry`, `search_radius`, `data_flags`, `dataint`, `dataint2`, `dataint3`, `dataint4`, `x`, `y`, `z`, `o`, `comments`) values('13322','0','0','1','0','56665','50','4','2000009995','0','0','0','0','0','0','0','Say Ysera.'); +INSERT INTO `dbscripts_on_gossip` (`id`, `delay`, `command`, `datalong`, `datalong2`, `buddy_entry`, `search_radius`, `data_flags`, `dataint`, `dataint2`, `dataint3`, `dataint4`, `x`, `y`, `z`, `o`, `comments`) values('13322','10','3','0','0','55294','50000','8','0','0','0','0','-1699.75','-2384.89','345.579','3.27604','Move point Ultraxion.'); \ No newline at end of file diff --git a/sql_mr/mt00003_mangos_Arcurion_AI.sql b/sql_mr/mt00003_mangos_Arcurion_AI.sql new file mode 100644 index 0000000000..d3e431bd8b --- /dev/null +++ b/sql_mr/mt00003_mangos_Arcurion_AI.sql @@ -0,0 +1,71 @@ + +DELETE FROM `creature_template_addon` WHERE (`entry`=54590); +INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `b2_0_sheath`, `b2_1_pvp_state`, `emote`, `moveflags`, `auras`) VALUES +(54590, 0, 0, 1, 0, 0, 0, 10255); + +-- Text id: -1700 +DELETE FROM creature_ai_texts WHERE entry=-1700; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-1700','Nothing! Nothing....','25797','6','0','Arcurion Death','0'); + +-- Text id: -1701 +DELETE FROM creature_ai_texts WHERE entry=-1701; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-1701','None will survive!','25808','6','0','Arcurion Aggro','0'); + +-- Text id: -1702 +DELETE FROM creature_ai_texts WHERE entry=-1702; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-1702','The Hour of Twilight falls - the end of all things - you cannot stop it. You are nothing. NOTHING!','25801','6','0','Arcurion 30%.','0'); + +-- Text id: -1703 +DELETE FROM creature_ai_texts WHERE entry=-1703; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-1703','Mere mortals.','25803','6','0','Arcurion say kill 01','0'); + +-- Text id: -1704 +DELETE FROM creature_ai_texts WHERE entry=-1704; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-1704','The Aspects misplaced their trust.','25806','6','0','Arcurion say kill 02','0'); + +-- Text id: -1705 +DELETE FROM creature_ai_texts WHERE entry=-1705; +INSERT INTO `creature_ai_texts` (`entry`,`content_default`,`sound`,`type`,`language`,`comment`,`emote`) VALUES +('-1705','Your Shaman can\'t protect you.','25805','6','0','Arcurion say kill 03','0'); + + + +-- Creature id: 54590 +UPDATE `creature_template` SET `AIName` = 'EventAI', `ScriptName` = '' WHERE `entry` = '54590'; +DELETE FROM creature_ai_scripts WHERE creature_id=54590; +INSERT INTO creature_ai_scripts VALUES +('5459001','54590','16','2','100','7','103962','1','2000','2000','41','1000','0','0','0','0','0','0','0','0','0','0','Force Despawn at Missing aura Tide of Cold.'), +('5459002','54590','0','2','100','7','6000','6000','400000','400000','11','103962','0','2','21','0','0','0','0','0','0','0','Cast Timer Buff Tide of Cold and Combat Movement false.'), +('5459003','54590','10','0','100','7','0','20','2000','2000','28','0','10255','0','2','14','0','0','22','1','0','0','Remove Stoned and Set Faction 14 and Set Phase at MoveLineOfSight OOC.'), +('5459004','54590','4','1','100','7','0','0','0','0','1','-1701','0','0','11','102593','1','8','0','0','0','0','Yell Aggro and Cast Frost Hand.'), +('5459005','54590','5','1','100','7','5000','5000','0','0','1','-1703','-1704','-1705','0','0','0','0','0','0','0','0','Yell at Kill.'), +('5459006','54590','0','0','100','7','5000','5000','5000','5000','11','102593','1','8','0','0','0','0','0','0','0','0','Cast Frost Hand.'), +('5459007','54590','0','0','100','7','18000','20000','15000','17000','11','102582','8','2','0','0','0','0','0','0','0','0','Cast Frost Chain.'), +('5459008','54590','7','0','100','6','0','0','0','0','41','3000','0','0','0','0','0','0','0','0','0','0','Evade at Despawn.'), +('5459009','54590','2','1','100','7','37','33','2000','2000','22','2','0','0','21','0','0','0','0','0','0','0','Just HP Set Phase 2 and Combat Movement False.'), +('5459010','54590','0','2','100','7','2000','3000','400000','400000','1','-1702','0','0','11','104050','0','1','20','0','0','0','Phase 2 - cast Tide of Cold and AutoAttack False. Need core support spell.'), +('5459011','54590','6','0','100','6','0','0','0','0','1','-1700','0','0','0','0','0','0','0','0','0','0','Yell just died.'); + + + + +-- Creature id: 57197 +UPDATE creature_template SET AIName='EventAI' WHERE entry=57197; +DELETE FROM creature_ai_scripts WHERE creature_id=57197; +INSERT INTO creature_ai_scripts VALUES +('5719701','57197','11','0','100','6','0','0','0','0','12','54590','0','864000000','18','33587776','0','0','22','1','0','0','Summon Arcurion at Spawn and Set Unit Flag and Set Phase 1.'), +('5719702','57197','4','0','100','6','0','0','0','0','21','0','0','0','20','0','0','0','0','0','0','0','False Combat Movement and Auto Attack.'), +('5719703','57197','26','1','100','7','54590','2000','2000','0','22','2','0','0','0','0','0','0','0','0','0','0','Set Phase 2 at Despawn Arcurion.'), +('5719704','57197','1','2','100','7','10000','10000','864000000','864000000','12','54590','0','864000000','22','1','0','0','0','0','0','0','Phase 2 - summon Arcurion and Set Phase 1'), +('5719705','57197','25','0','100','7','54590','2000','2000','0','22','4','0','0','0','0','0','0','0','0','0','0','Set Phase 4 at Arcurion death.'); + + + + +DELETE FROM `creature` WHERE `id`=54590; + diff --git a/sql_mr/mt00650_mangos_stonecore.sql b/sql_mr/mt00650_mangos_stonecore.sql new file mode 100644 index 0000000000..e8f506ffb6 --- /dev/null +++ b/sql_mr/mt00650_mangos_stonecore.sql @@ -0,0 +1,18 @@ + +UPDATE `instance_template` SET `ScriptName` = 'instance_stonecore' WHERE `map` = 725; + +UPDATE `creature_template` SET `ScriptName` = 'mob_crystalspawn_giant' WHERE `entry` = 42810; +UPDATE `creature_template` SET `ScriptName` = 'mob_impp' WHERE `entry` = 43014; +UPDATE `creature_template` SET `ScriptName` = 'mob_millhouse_manastorm' WHERE `entry` = 43391; +UPDATE `creature_template` SET `ScriptName` = 'mob_rock_borer' WHERE `entry` IN (42845, 43917); + + +UPDATE `creature_template` SET `ScriptName` = 'boss_slabhide' WHERE `entry` = 43214; +UPDATE `creature_template` SET `ScriptName` = 'npc_stalactite' WHERE `entry` = 43159; + +UPDATE `creature_template` SET `ScriptName` = 'boss_ozruk' WHERE `entry` = 42188; +UPDATE `creature_template` SET `ScriptName` = 'npc_rupture' WHERE `entry` = 49597; + +UPDATE `creature_template` SET `ScriptName` = 'boss_corborus' WHERE `entry` = 43438; + +UPDATE `creature_template` SET `ScriptName` = 'boss_princeless_azil' WHERE `entry` = 42333; diff --git a/sql_mr/mt00664_scriptdev2_locales.sql b/sql_mr/mt00664_scriptdev2_locales.sql new file mode 100644 index 0000000000..2030dd842b --- /dev/null +++ b/sql_mr/mt00664_scriptdev2_locales.sql @@ -0,0 +1,17 @@ +-- custom_texts +ALTER TABLE `custom_texts` + ADD COLUMN `content_loc9` text AFTER `content_loc8`, + ADD COLUMN `content_loc10` text AFTER `content_loc9`, + ADD COLUMN `content_loc11` text AFTER `content_loc10`; + +-- gossip_texts +ALTER TABLE `gossip_texts` + ADD COLUMN `content_loc9` text AFTER `content_loc8`, + ADD COLUMN `content_loc10` text AFTER `content_loc9`, + ADD COLUMN `content_loc11` text AFTER `content_loc10`; + +-- script_texts +ALTER TABLE `script_texts` + ADD COLUMN `content_loc9` text AFTER `content_loc8`, + ADD COLUMN `content_loc10` text AFTER `content_loc9`, + ADD COLUMN `content_loc11` text AFTER `content_loc10`; diff --git a/sql_mr/readme.txt b/sql_mr/readme.txt new file mode 100644 index 0000000000..49b4c243b2 --- /dev/null +++ b/sql_mr/readme.txt @@ -0,0 +1,8 @@ +You should install these files if you want to fully functionality + +Instructions for CLEAN DBs: +1. + +Instructions for EXISTING DBs: +1. + diff --git a/sql_mr/scriptdev2_spell_comment_from_wowd.sql b/sql_mr/scriptdev2_spell_comment_from_wowd.sql new file mode 100644 index 0000000000..a5fec77d07 --- /dev/null +++ b/sql_mr/scriptdev2_spell_comment_from_wowd.sql @@ -0,0 +1,19 @@ +-- Insert comments to scriptdev2 boss_spell_table from WOWD database. +-- Change WOWD database name if you use this! + +CREATE ALGORITHM = TEMPTABLE VIEW `commentlist` +(`entry` ,`spell`, `comment`) +AS SELECT `scriptdev2`.`boss_spell_table`.`entry`, +`spellID_N10`, +CONCAT(`mangos`.`creature_template`.`name`, +' : ', +`mangos`.`wowd_spell`.`SpellName`) +FROM `scriptdev2`.`boss_spell_table` +INNER JOIN `mangos`.`creature_template` ON `mangos`.`creature_template`.`entry` = `scriptdev2`.`boss_spell_table`.`entry` +INNER JOIN `mangos`.`wowd_spell` ON `mangos`.`wowd_spell`.`id` = `scriptdev2`.`boss_spell_table`.`spellID_N10`; + +UPDATE `scriptdev2`.`boss_spell_table` SET `comment` = (SELECT DISTINCT `commentlist`.`comment` +FROM `commentlist` WHERE `scriptdev2`.`boss_spell_table`.`entry` = `commentlist`.`entry` +AND `scriptdev2`.`boss_spell_table`.`spellID_N10` = `commentlist`.`spell` +AND `scriptdev2`.`boss_spell_table`.`comment` IS NULL); +DROP VIEW `commentlist`; diff --git a/sql_mr/static_guids_policy.txt b/sql_mr/static_guids_policy.txt new file mode 100644 index 0000000000..8228e39aab --- /dev/null +++ b/sql_mr/static_guids_policy.txt @@ -0,0 +1,38 @@ +Static GUID distribution policy for mangosR2 branch +Attention! If your use new GUID's scope for some creatures/objects - first define it his here. + +# Trial of the Crusaders +Creature GUIDS 600000 - 600003 +# Event: Headless horseman +Creature GUIDS 600004 - 600027 +# Icecrown Citadel +Creature GUIDS 600028 - 600029 +# Ahn'kahet +Creature GUIDS 600047 - 600113 +# Stratholme +Creature GUIDS 600114 - 600125 +# Trial of the crusader +Creature GUIDS 600126 +# Quest 11542/11543 +Creature GUIDS 600127 - 600151 +# Quest 12813 +Creature GUIDS 600153 - 600154 + + +# Sunwell Plateau Doors +Gameobject GUIDS 600000 - 600004 +# Ahn'kahet +Gameobject GUIDS 600005 +# Quest 12470 +Gameobject GUIDS 600006 - 600012 +# Halls of Reflection - Captain Chest +Gameobject GUIDS 600013 - 600016 + + +Custom creature_template ids used for scripting purposes. By far the wrong way but keep in mind. +# Trial of the Crusader +Ids 7 - 9 +# Stratholme +Ids 10 - 15 +# Ruby Sanctum +Ids 16 diff --git a/system/MangosdRev.cpp b/system/MangosdRev.cpp new file mode 100644 index 0000000000..a7c8b1c66a --- /dev/null +++ b/system/MangosdRev.cpp @@ -0,0 +1,19 @@ +/* Copyright (C) 2006 - 2013 ScriptDev2 +* 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__ ) +# define MANGOS_DLL_EXPORT extern "C" +#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 9e0cab6a3f..620349e550 100644 --- a/system/ScriptLoader.cpp +++ b/system/ScriptLoader.cpp @@ -1,25 +1,27 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #include "precompiled.h" -//battlegrounds +// battlegrounds extern void AddSC_battleground(); +extern void AddSC_battlegroundSA(); +extern void AddSC_battlegroundIC(); -//custom +// custom +extern void AddSC_mob_teleguy(); +extern void AddSC_npc_arena_honor(); -//examples +// examples extern void AddSC_example_creature(); extern void AddSC_example_escort(); extern void AddSC_example_gossip_codebox(); extern void AddSC_example_misc(); -//world +// world extern void AddSC_areatrigger_scripts(); -extern void AddSC_boss_emeriss(); -extern void AddSC_boss_taerar(); -extern void AddSC_boss_ysondre(); +extern void AddSC_bosses_emerald_dragons(); extern void AddSC_generic_creature(); extern void AddSC_go_scripts(); extern void AddSC_guards(); @@ -27,34 +29,43 @@ extern void AddSC_item_scripts(); extern void AddSC_npc_professions(); extern void AddSC_npcs_special(); extern void AddSC_spell_scripts(); +extern void AddSC_pet_scripts(); +extern void AddSC_world_map_scripts(); +extern void AddSC_world_map_ebon_hold(); -//eastern kingdoms -extern void AddSC_blackrock_depths(); //blackrock_depths +// eastern kingdoms +extern void AddSC_ascendant_council(); // bastion_of_twilight +extern void AddSC_boss_chogall(); +extern void AddSC_boss_halfus_wyrmbreaker(); +extern void AddSC_boss_sinestra(); +extern void AddSC_boss_valiona_and_theralion(); +extern void AddSC_instance_bastion_of_twilight(); +extern void AddSC_boss_beauty(); // BM, blackrock_caverns +extern void AddSC_boss_corla(); +extern void AddSC_boss_karsh_steelbender(); +extern void AddSC_boss_lord_obsidius(); +extern void AddSC_boss_romogg(); +extern void AddSC_instance_blackrock_caverns(); +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_vael(); +extern void AddSC_boss_adramedes(); // BM, blackwing_descent +extern void AddSC_boss_chimaeron(); +extern void AddSC_boss_magmaw(); +extern void AddSC_boss_maloriak(); +extern void AddSC_boss_nefarian_descent(); +extern void AddSC_instance_blackwing_descent(); +extern void AddSC_omnotron_defense(); +extern void AddSC_boss_razorgore(); // blackwing_lair +extern void AddSC_boss_vaelastrasz(); extern void AddSC_boss_broodlord(); extern void AddSC_boss_firemaw(); extern void AddSC_boss_ebonroc(); @@ -62,30 +73,38 @@ extern void AddSC_boss_flamegor(); extern void AddSC_boss_chromaggus(); extern void AddSC_boss_nefarian(); extern void AddSC_boss_victor_nefarius(); -extern void AddSC_deadmines(); //deadmines +extern void AddSC_instance_blackwing_lair(); +extern void AddSC_boss_mr_smite(); // deadmines +extern void AddSC_deadmines(); extern void AddSC_instance_deadmines(); -extern void AddSC_gnomeregan(); //gnomeregan +extern void AddSC_gnomeregan(); // gnomeregan extern void AddSC_boss_thermaplugg(); extern void AddSC_instance_gnomeregan(); -extern void AddSC_boss_attumen(); //karazhan +extern void AddSC_boss_drahga_shadowburner(); // grim_batol +extern void AddSC_boss_erudax(); +extern void AddSC_boss_forgemaster_throngus(); +extern void AddSC_boss_general_umbriss(); +extern void AddSC_instance_grim_batol(); +extern void AddSC_boss_attumen(); // karazhan extern void AddSC_boss_curator(); extern void AddSC_boss_maiden_of_virtue(); extern void AddSC_boss_shade_of_aran(); extern void AddSC_boss_netherspite(); -extern void AddSC_boss_malchezaar(); +extern void AddSC_boss_nightbane(); +extern void AddSC_boss_prince_malchezaar(); extern void AddSC_boss_terestian_illhoof(); -extern void AddSC_netherspite_infernal(); extern void AddSC_boss_moroes(); extern void AddSC_bosses_opera(); +extern void AddSC_chess_event(); extern void AddSC_instance_karazhan(); extern void AddSC_karazhan(); -extern void AddSC_boss_felblood_kaelthas(); //magisters_terrace +extern void AddSC_boss_felblood_kaelthas(); // magisters_terrace extern void AddSC_boss_selin_fireheart(); extern void AddSC_boss_vexallus(); extern void AddSC_boss_priestess_delrissa(); extern void AddSC_instance_magisters_terrace(); extern void AddSC_magisters_terrace(); -extern void AddSC_boss_lucifron(); //molten_core +extern void AddSC_boss_lucifron(); // molten_core extern void AddSC_boss_magmadar(); extern void AddSC_boss_gehennas(); extern void AddSC_boss_garr(); @@ -97,55 +116,43 @@ extern void AddSC_boss_majordomo(); extern void AddSC_boss_ragnaros(); 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_ebon_hold(); // scarlet_enclave +extern void AddSC_boss_arcanist_doan(); // scarlet_monastery 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_theolenkrastinov(); -extern void AddSC_boss_illuciabarov(); -extern void AddSC_boss_instructormalicia(); +extern void AddSC_boss_darkmaster_gandling(); // scholomance extern void AddSC_boss_jandicebarov(); -extern void AddSC_boss_kormok(); -extern void AddSC_boss_lordalexeibarov(); -extern void AddSC_boss_lorekeeperpolkelt(); -extern void AddSC_boss_rasfrost(); -extern void AddSC_boss_theravenian(); -extern void AddSC_boss_vectus(); extern void AddSC_instance_scholomance(); -extern void AddSC_shadowfang_keep(); //shadowfang_keep +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(); extern void AddSC_stratholme(); -extern void AddSC_instance_sunken_temple(); //sunken_temple +extern void AddSC_instance_sunken_temple(); // sunken_temple extern void AddSC_sunken_temple(); -extern void AddSC_boss_brutallus(); //sunwell_plateau +extern void AddSC_boss_brutallus(); // sunwell_plateau +extern void AddSC_boss_eredar_twins(); +extern void AddSC_boss_felmyst(); extern void AddSC_boss_kalecgos(); +extern void AddSC_boss_kiljaeden(); +extern void AddSC_boss_muru(); extern void AddSC_instance_sunwell_plateau(); -extern void AddSC_boss_archaedas(); //uldaman +extern void AddSC_boss_commander_ulthok(); // throne_of_the_tides +extern void AddSC_boss_erunak_and_ghursha(); +extern void AddSC_boss_lady_nazjar(); +extern void AddSC_boss_ozumat(); +extern void AddSC_instance_throne_of_the_tides(); +extern void AddSC_boss_archaedas(); // uldaman extern void AddSC_instance_uldaman(); extern void AddSC_uldaman(); -extern void AddSC_boss_akilzon(); //zulaman +extern void AddSC_boss_akilzon(); // zulaman extern void AddSC_boss_halazzi(); extern void AddSC_boss_janalai(); extern void AddSC_boss_malacrass(); @@ -153,9 +160,7 @@ extern void AddSC_boss_nalorakk(); 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_arlokk(); // zulgurub extern void AddSC_boss_hakkar(); extern void AddSC_boss_hazzarah(); extern void AddSC_boss_jeklik(); @@ -166,19 +171,19 @@ 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(); extern void AddSC_elwynn_forest(); extern void AddSC_eversong_woods(); extern void AddSC_ghostlands(); +extern void AddSC_gilneas(); +extern void AddSC_gilneas_city(); extern void AddSC_hinterlands(); extern void AddSC_ironforge(); extern void AddSC_isle_of_queldanas(); @@ -191,53 +196,92 @@ extern void AddSC_stormwind_city(); extern void AddSC_stranglethorn_vale(); extern void AddSC_swamp_of_sorrows(); extern void AddSC_tirisfal_glades(); +extern void AddSC_twilight_highlands(); extern void AddSC_undercity(); +extern void AddSC_vashjir(); extern void AddSC_western_plaguelands(); extern void AddSC_westfall(); extern void AddSC_wetlands(); -//kalimdor -extern void AddSC_instance_blackfathom_deeps(); //blackfathom_deeps -extern void AddSC_boss_aeonus(); //COT, dark_portal +// kalimdor +extern void AddSC_instance_blackfathom_deeps(); // blackfathom_deeps +extern void AddSC_boss_aeonus(); // COT, dark_portal extern void AddSC_boss_chrono_lord_deja(); extern void AddSC_boss_temporus(); extern void AddSC_dark_portal(); extern void AddSC_instance_dark_portal(); -extern void AddSC_hyjal(); //COT, hyjal +extern void AddSC_boss_deathwing(); // COT, dragon_soul +extern void AddSC_boss_hagara(); +extern void AddSC_boss_morchok(); +extern void AddSC_boss_ultraxion(); +extern void AddSC_boss_warlord_zonozz(); +extern void AddSC_boss_warmaster_blackhorn(); +extern void AddSC_boss_yorsahj(); +extern void AddSC_dragon_soul(); +extern void AddSC_instance_dragon_soul(); +extern void AddSC_end_of_time(); // COT, end_of_time +extern void AddSC_instance_end_of_time(); +extern void AddSC_boss_archbishop_benedictus(); // COT, hour_of_twilight +extern void AddSC_boss_arcurion(); +extern void AddSC_boss_asira_dawnslayer(); +extern void AddSC_instance_hour_of_twilight(); +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(); //Culling of Stratholme +extern void AddSC_culling_of_stratholme(); // COT, culling_of_stratholme +extern void AddSC_boss_infinite_corruptor(); +extern void AddSC_boss_lord_epoch(); +extern void AddSC_boss_malganis(); +extern void AddSC_boss_meathook(); +extern void AddSC_boss_salramm(); +extern void AddSC_culling_of_stratholmeAI(); extern void AddSC_instance_culling_of_stratholme(); -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_onyxia(); //onyxias_lair +extern void AddSC_trash_culling_of_stratholme(); +extern void AddSC_boss_mannoroth_and_varothen(); // COT, well_of_eternity +extern void AddSC_boss_perotharn(); +extern void AddSC_boss_queen_azshara(); +extern void AddSC_instance_well_of_eternity(); +extern void AddSC_dire_maul(); // dire_maul +extern void AddSC_instance_dire_maul(); +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_razorfen_downs(); -extern void AddSC_instance_razorfen_kraul(); //razorfen_kraul -extern void AddSC_boss_ayamiss(); //ruins_of_ahnqiraj +extern void AddSC_razorfen_downs(); // razorfen_downs +extern void AddSC_boss_tuten_kash(); +extern void AddSC_instance_razorfen_kraul(); // razorfen_kraul +extern void AddSC_razorfen_kraul(); +extern void AddSC_boss_ayamiss(); // ruins_of_ahnqiraj +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_boss_cthun(); //temple_of_ahnqiraj +extern void AddSC_instance_ruins_of_ahnqiraj(); +extern void AddSC_boss_cthun(); // temple_of_ahnqiraj extern void AddSC_boss_fankriss(); extern void AddSC_boss_huhuran(); extern void AddSC_bug_trio(); extern void AddSC_boss_sartura(); extern void AddSC_boss_skeram(); extern void AddSC_boss_twinemperors(); +extern void AddSC_boss_viscidus(); extern void AddSC_mob_anubisath_sentinel(); extern void AddSC_instance_temple_of_ahnqiraj(); -extern void AddSC_instance_wailing_caverns(); // Wailing Caverns -extern void AddSC_zulfarrak(); //zulfarrak +extern void AddSC_boss_alakir(); // throne_of_the_four_winds +extern void AddSC_conclave_of_the_wind(); +extern void AddSC_instance_throne_of_the_four_winds(); +extern void AddSC_boss_altairus(); // vortex_pinnacle +extern void AddSC_boss_asaad(); +extern void AddSC_boss_grand_vizier_etan(); +extern void AddSC_instance_vortex_pinnacle(); +extern void AddSC_instance_wailing_caverns(); // wailing_caverns +extern void AddSC_wailing_caverns(); +extern void AddSC_boss_zumrah(); // zulfarrak extern void AddSC_instance_zulfarrak(); +extern void AddSC_zulfarrak(); extern void AddSC_ashenvale(); extern void AddSC_azshara(); @@ -246,10 +290,13 @@ extern void AddSC_bloodmyst_isle(); extern void AddSC_boss_azuregos(); extern void AddSC_darkshore(); extern void AddSC_desolace(); +extern void AddSC_durotar(); extern void AddSC_dustwallow_marsh(); extern void AddSC_felwood(); extern void AddSC_feralas(); +extern void AddSC_molten_front(); extern void AddSC_moonglade(); +extern void AddSC_mount_hyjal(); extern void AddSC_mulgore(); extern void AddSC_orgrimmar(); extern void AddSC_silithus(); @@ -259,30 +306,51 @@ extern void AddSC_teldrassil(); extern void AddSC_the_barrens(); extern void AddSC_thousand_needles(); extern void AddSC_thunder_bluff(); +extern void AddSC_uldum(); extern void AddSC_ungoro_crater(); extern void AddSC_winterspring(); -//northrend -extern void AddSC_boss_jedoga(); //ahnkahet +// maelstrom +extern void AddSC_instance_stonecore(); // stonecore +extern void AddSC_stonecore(); +extern void AddSC_boss_corborus(); +extern void AddSC_boss_ozruk(); +extern void AddSC_boss_priestess_azil(); +extern void AddSC_boss_slabhide(); + +extern void AddSC_deepholm(); +extern void AddSC_kezan(); +extern void AddSC_lost_isles(); + +// northrend +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(); extern void AddSC_instance_ahnkahet(); -extern void AddSC_boss_anubarak(); //azjol-nerub +extern void AddSC_boss_anubarak(); // azjol-nerub, azjol-nerub extern void AddSC_boss_hadronox(); extern void AddSC_boss_krikthir(); extern void AddSC_instance_azjol_nerub(); -extern void AddSC_boss_anubarak_trial(); //trial_of_the_crusader +extern void AddSC_trial_of_the_champion(); // CC, trial_of_the_champion +extern void AddSC_boss_argent_challenge(); +extern void AddSC_boss_black_knight(); +extern void AddSC_boss_grand_champions(); +extern void AddSC_instance_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(); extern void AddSC_instance_trial_of_the_crusader(); extern void AddSC_northrend_beasts(); extern void AddSC_trial_of_the_crusader(); extern void AddSC_twin_valkyr(); -extern void AddSC_boss_novos(); //draktharon_keep +extern void AddSC_boss_novos(); // draktharon_keep +extern void AddSC_boss_dred(); extern void AddSC_boss_tharonja(); extern void AddSC_boss_trollgore(); extern void AddSC_instance_draktharon_keep(); -extern void AddSC_boss_colossus(); //gundrak +extern void AddSC_boss_colossus(); // gundrak extern void AddSC_boss_eck(); extern void AddSC_boss_galdarah(); extern void AddSC_boss_moorabi(); @@ -291,16 +359,39 @@ extern void AddSC_instance_gundrak(); extern void AddSC_boss_bronjahm(); // ICC, forge_of_souls extern void AddSC_boss_devourer_of_souls(); extern void AddSC_instance_forge_of_souls(); -extern void AddSC_boss_gafrost(); // ICC, pit_of_saron +extern void AddSC_forge_of_souls(); +extern void AddSC_boss_falric(); // ICC, halls_of_reflection +extern void AddSC_boss_lich_king_hr(); +extern void AddSC_boss_marwyn(); +extern void AddSC_halls_of_reflection(); +extern void AddSC_instance_halls_of_reflection(); +extern void AddSC_boss_garfrost(); // ICC, pit_of_saron extern void AddSC_boss_krick_and_ick(); extern void AddSC_boss_tyrannus(); extern void AddSC_instance_pit_of_saron(); extern void AddSC_pit_of_saron(); -extern void AddSC_boss_anubrekhan(); //naxxramas +extern void AddSC_blood_prince_council(); // ICC, icecrown_citadel +extern void AddSC_boss_blood_queen_lanathel(); +extern void AddSC_boss_deathbringer_saurfang(); +extern void AddSC_boss_festergut(); +extern void AddSC_boss_lady_deathwhisper(); +extern void AddSC_boss_lord_marrowgar(); +extern void AddSC_boss_professor_putricide(); +extern void AddSC_boss_rotface(); +extern void AddSC_boss_sindragosa(); +extern void AddSC_boss_lich_king_icc(); +extern void AddSC_boss_valithria_dreamwalker(); +extern void AddSC_gunship_battle(); +extern void AddSC_instance_icecrown_citadel(); +extern void AddSC_icecrown_spire(); +extern void AddSC_icecrown_teleporter(); +extern void AddSC_icecrown_lights_hammer(); +extern void AddSC_boss_anubrekhan(); // naxxramas extern void AddSC_boss_four_horsemen(); extern void AddSC_boss_faerlina(); extern void AddSC_boss_gluth(); extern void AddSC_boss_gothik(); +extern void AddSC_boss_grobbulus(); extern void AddSC_boss_kelthuzad(); extern void AddSC_boss_loatheb(); extern void AddSC_boss_maexxna(); @@ -309,24 +400,40 @@ extern void AddSC_boss_heigan(); extern void AddSC_boss_patchwerk(); extern void AddSC_boss_razuvious(); extern void AddSC_boss_sapphiron(); +extern void AddSC_boss_thaddius(); extern void AddSC_instance_naxxramas(); -extern void AddSC_boss_anomalus(); //nexus +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(); extern void AddSC_boss_telestra(); extern void AddSC_instance_nexus(); -extern void AddSC_boss_sartharion(); //obsidian_sanctum +extern void AddSC_boss_drakos(); // nexus, oculus +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_bjarngrim(); //Ulduar, halls_of_lightning +extern void AddSC_boss_baltharus(); // ruby_sanctum +extern void AddSC_boss_halion(); +extern void AddSC_boss_saviana(); +extern void AddSC_boss_zarithrian(); +extern void AddSC_instance_ruby_sanctum(); +extern void AddSC_ruby_sanctum(); +extern void AddSC_boss_bjarngrim(); // ulduar, halls_of_lightning extern void AddSC_boss_ionar(); extern void AddSC_boss_loken(); extern void AddSC_boss_volkhan(); extern void AddSC_instance_halls_of_lightning(); -extern void AddSC_boss_maiden_of_grief(); //Ulduar, halls_of_stone +extern void AddSC_boss_maiden_of_grief(); // ulduar, halls_of_stone extern void AddSC_boss_sjonnir(); +extern void AddSC_boss_krystallus(); extern void AddSC_halls_of_stone(); extern void AddSC_instance_halls_of_stone(); -extern void AddSC_boss_assembly_of_iron(); //ulduar +extern void AddSC_boss_assembly_of_iron(); // ulduar, ulduar extern void AddSC_boss_algalon(); extern void AddSC_boss_auriaya(); extern void AddSC_boss_flame_leviathan(); @@ -341,41 +448,58 @@ extern void AddSC_boss_thorim(); extern void AddSC_boss_xt_002(); extern void AddSC_boss_yogg_saron(); extern void AddSC_instance_ulduar(); -extern void AddSC_boss_ingvar(); //utgarde_keep +extern void AddSC_ulduar(); +extern void AddSC_boss_ingvar(); // utgarde_keep, utgarde_keep extern void AddSC_boss_keleseth(); extern void AddSC_boss_skarvald_and_dalronn(); extern void AddSC_instance_utgarde_keep(); extern void AddSC_utgarde_keep(); -extern void AddSC_boss_gortok(); //utgarde_pinnacle +extern void AddSC_boss_gortok(); // utgarde_keep, utgarde_pinnacle extern void AddSC_boss_skadi(); extern void AddSC_boss_svala(); extern void AddSC_boss_ymiron(); extern void AddSC_instance_pinnacle(); -extern void AddSC_instance_violet_hold(); //violet_hold +extern void AddSC_boss_archavon(); // vault_of_archavon +extern void AddSC_boss_emalon(); +extern void AddSC_boss_koralon(); +extern void AddSC_boss_toravon(); +extern void AddSC_instance_vault_of_archavon(); +extern void AddSC_boss_erekem(); // violet_hold +extern void AddSC_boss_ichoron(); +extern void AddSC_instance_violet_hold(); extern void AddSC_violet_hold(); +extern void AddSC_boss_cyanigosa(); +extern void AddSC_boss_moragg(); +extern void AddSC_boss_xevozz(); +extern void AddSC_boss_zuramat(); +extern void AddSC_boss_lavanthor(); extern void AddSC_borean_tundra(); extern void AddSC_dalaran(); extern void AddSC_dragonblight(); +extern void AddSC_grizzly_hills(); extern void AddSC_howling_fjord(); extern void AddSC_icecrown(); extern void AddSC_sholazar_basin(); extern void AddSC_storm_peaks(); +extern void AddSC_wintergrasp(); extern void AddSC_zuldrak(); -//outland -extern void AddSC_boss_exarch_maladaar(); //auchindoun, auchenai_crypts -extern void AddSC_boss_nexusprince_shaffar(); //auchindoun, mana_tombs +// outland +extern void AddSC_boss_exarch_maladaar(); // auchindoun, auchenai_crypts +extern void AddSC_boss_shirrak(); +extern void AddSC_boss_nexusprince_shaffar(); // auchindoun, mana_tombs extern void AddSC_boss_pandemonius(); -extern void AddSC_boss_darkweaver_syth(); //auchindoun, sethekk_halls +extern void AddSC_boss_anzu(); // auchindoun, sethekk_halls +extern void AddSC_boss_darkweaver_syth(); extern void AddSC_boss_talon_king_ikiss(); extern void AddSC_instance_sethekk_halls(); -extern void AddSC_boss_ambassador_hellmaw(); //auchindoun, shadow_labyrinth +extern void AddSC_boss_ambassador_hellmaw(); // auchindoun, shadow_labyrinth extern void AddSC_boss_blackheart_the_inciter(); extern void AddSC_boss_grandmaster_vorpil(); extern void AddSC_boss_murmur(); extern void AddSC_instance_shadow_labyrinth(); -extern void AddSC_black_temple(); //black_temple +extern void AddSC_black_temple(); // black_temple extern void AddSC_boss_illidan(); extern void AddSC_boss_shade_of_akama(); extern void AddSC_boss_supremus(); @@ -386,48 +510,50 @@ extern void AddSC_boss_teron_gorefiend(); extern void AddSC_boss_najentus(); extern void AddSC_boss_illidari_council(); extern void AddSC_instance_black_temple(); -extern void AddSC_boss_fathomlord_karathress(); //CR, serpent_shrine +extern void AddSC_boss_fathomlord_karathress(); // CR, serpent_shrine extern void AddSC_boss_hydross_the_unstable(); extern void AddSC_boss_lady_vashj(); extern void AddSC_boss_leotheras_the_blind(); extern void AddSC_boss_morogrim_tidewalker(); extern void AddSC_boss_the_lurker_below(); extern void AddSC_instance_serpentshrine_cavern(); -extern void AddSC_boss_hydromancer_thespia(); //CR, steam_vault +extern void AddSC_boss_ahune(); // CR, slave_pens +extern void AddSC_boss_hydromancer_thespia(); // CR, steam_vault extern void AddSC_boss_mekgineer_steamrigger(); extern void AddSC_boss_warlord_kalithresh(); extern void AddSC_instance_steam_vault(); -extern void AddSC_boss_hungarfen(); //CR, Underbog -extern void AddSC_boss_gruul(); //gruuls_lair +extern void AddSC_boss_hungarfen(); // CR, Underbog +extern void AddSC_boss_gruul(); // gruuls_lair extern void AddSC_boss_high_king_maulgar(); extern void AddSC_instance_gruuls_lair(); -extern void AddSC_boss_broggok(); //HC, blood_furnace +extern void AddSC_boss_broggok(); // HC, blood_furnace extern void AddSC_boss_kelidan_the_breaker(); extern void AddSC_boss_the_maker(); extern void AddSC_instance_blood_furnace(); -extern void AddSC_boss_nazan_and_vazruden(); //HC, hellfire_ramparts +extern void AddSC_boss_nazan_and_vazruden(); // HC, hellfire_ramparts extern void AddSC_boss_omor_the_unscarred(); extern void AddSC_boss_watchkeeper_gargolmar(); extern void AddSC_instance_ramparts(); -extern void AddSC_boss_magtheridon(); //HC, magtheridons_lair +extern void AddSC_boss_magtheridon(); // HC, magtheridons_lair extern void AddSC_instance_magtheridons_lair(); -extern void AddSC_boss_grand_warlock_nethekurse(); //HC, shattered_halls +extern void AddSC_boss_grand_warlock_nethekurse(); // HC, shattered_halls 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_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_high_botanist_freywinn(); // TK, botanica extern void AddSC_boss_laj(); extern void AddSC_boss_warp_splinter(); -extern void AddSC_boss_kaelthas(); //TK, the_eye -extern void AddSC_boss_void_reaver(); +extern void AddSC_boss_alar(); // TK, the_eye 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(); @@ -444,22 +570,24 @@ extern void AddSC_zangarmarsh(); void AddScripts() { - //battlegrounds + // battlegrounds AddSC_battleground(); + AddSC_battlegroundSA(); + AddSC_battlegroundIC(); - //custom + // custom + AddSC_mob_teleguy(); + AddSC_npc_arena_honor(); - //examples + // examples AddSC_example_creature(); AddSC_example_escort(); AddSC_example_gossip_codebox(); AddSC_example_misc(); - //world + // world AddSC_areatrigger_scripts(); - AddSC_boss_emeriss(); - AddSC_boss_taerar(); - AddSC_boss_ysondre(); + AddSC_bosses_emerald_dragons(); AddSC_generic_creature(); AddSC_go_scripts(); AddSC_guards(); @@ -467,34 +595,43 @@ void AddScripts() AddSC_npc_professions(); AddSC_npcs_special(); AddSC_spell_scripts(); + AddSC_pet_scripts(); + AddSC_world_map_scripts(); + AddSC_world_map_ebon_hold(); - //eastern kingdoms - AddSC_blackrock_depths(); //blackrock_depths + // eastern kingdoms + AddSC_ascendant_council(); // bastion_of_twilight + AddSC_boss_chogall(); + AddSC_boss_halfus_wyrmbreaker(); + AddSC_boss_sinestra(); + AddSC_boss_valiona_and_theralion(); + AddSC_instance_bastion_of_twilight(); + AddSC_boss_beauty(); // BM, blackrock_caverns + AddSC_boss_corla(); + AddSC_boss_karsh_steelbender(); + AddSC_boss_lord_obsidius(); + AddSC_boss_romogg(); + AddSC_instance_blackrock_caverns(); + 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_vael(); + AddSC_boss_adramedes(); // BM, blackwing_descent + AddSC_boss_chimaeron(); + AddSC_boss_magmaw(); + AddSC_boss_maloriak(); + AddSC_boss_nefarian_descent(); + AddSC_instance_blackwing_descent(); + AddSC_omnotron_defense(); + AddSC_boss_razorgore(); // blackwing_lair + AddSC_boss_vaelastrasz(); AddSC_boss_broodlord(); AddSC_boss_firemaw(); AddSC_boss_ebonroc(); @@ -502,30 +639,38 @@ void AddScripts() AddSC_boss_chromaggus(); AddSC_boss_nefarian(); AddSC_boss_victor_nefarius(); - AddSC_deadmines(); //deadmines + AddSC_instance_blackwing_lair(); + AddSC_deadmines(); // deadmines + AddSC_boss_mr_smite(); AddSC_instance_deadmines(); - AddSC_gnomeregan(); //gnomeregan + AddSC_gnomeregan(); // gnomeregan AddSC_boss_thermaplugg(); AddSC_instance_gnomeregan(); - AddSC_boss_attumen(); //karazhan + AddSC_boss_drahga_shadowburner(); // grim_batol + AddSC_boss_erudax(); + AddSC_boss_forgemaster_throngus(); + AddSC_boss_general_umbriss(); + AddSC_instance_grim_batol(); + AddSC_boss_attumen(); // karazhan AddSC_boss_curator(); AddSC_boss_maiden_of_virtue(); AddSC_boss_shade_of_aran(); AddSC_boss_netherspite(); - AddSC_boss_malchezaar(); + AddSC_boss_nightbane(); + AddSC_boss_prince_malchezaar(); AddSC_boss_terestian_illhoof(); - AddSC_netherspite_infernal(); AddSC_boss_moroes(); AddSC_bosses_opera(); + AddSC_chess_event(); AddSC_instance_karazhan(); AddSC_karazhan(); - AddSC_boss_felblood_kaelthas(); //magisters_terrace + AddSC_boss_felblood_kaelthas(); // magisters_terrace AddSC_boss_selin_fireheart(); AddSC_boss_vexallus(); AddSC_boss_priestess_delrissa(); AddSC_instance_magisters_terrace(); AddSC_magisters_terrace(); - AddSC_boss_lucifron(); //molten_core + AddSC_boss_lucifron(); // molten_core AddSC_boss_magmadar(); AddSC_boss_gehennas(); AddSC_boss_garr(); @@ -537,55 +682,43 @@ void AddScripts() AddSC_boss_ragnaros(); AddSC_instance_molten_core(); AddSC_molten_core(); - AddSC_ebon_hold(); //scarlet_enclave - AddSC_boss_arcanist_doan(); //scarlet_monastery - AddSC_boss_azshir_the_sleepless(); - AddSC_boss_bloodmage_thalnos(); + AddSC_ebon_hold(); // scarlet_enclave + AddSC_boss_arcanist_doan(); // scarlet_monastery 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_theolenkrastinov(); - AddSC_boss_illuciabarov(); - AddSC_boss_instructormalicia(); + AddSC_boss_darkmaster_gandling(); // scholomance AddSC_boss_jandicebarov(); - AddSC_boss_kormok(); - AddSC_boss_lordalexeibarov(); - AddSC_boss_lorekeeperpolkelt(); - AddSC_boss_rasfrost(); - AddSC_boss_theravenian(); - AddSC_boss_vectus(); AddSC_instance_scholomance(); - AddSC_shadowfang_keep(); //shadowfang_keep + 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(); AddSC_stratholme(); - AddSC_instance_sunken_temple(); //sunken_temple + AddSC_instance_sunken_temple(); // sunken_temple AddSC_sunken_temple(); - AddSC_boss_brutallus(); //sunwell_plateau + AddSC_boss_brutallus(); // sunwell_plateau + AddSC_boss_eredar_twins(); + AddSC_boss_felmyst(); AddSC_boss_kalecgos(); + AddSC_boss_kiljaeden(); + AddSC_boss_muru(); AddSC_instance_sunwell_plateau(); - AddSC_boss_archaedas(); //uldaman + AddSC_boss_commander_ulthok(); // throne_of_the_tides + AddSC_boss_erunak_and_ghursha(); + AddSC_boss_lady_nazjar(); + AddSC_boss_ozumat(); + AddSC_instance_throne_of_the_tides(); + AddSC_boss_archaedas(); // uldaman AddSC_instance_uldaman(); AddSC_uldaman(); - AddSC_boss_akilzon(); //zulaman + AddSC_boss_akilzon(); // zulaman AddSC_boss_halazzi(); AddSC_boss_janalai(); AddSC_boss_malacrass(); @@ -593,9 +726,7 @@ void AddScripts() AddSC_instance_zulaman(); AddSC_zulaman(); AddSC_boss_zuljin(); - AddSC_boss_arlokk(); //zulgurub - AddSC_boss_gahzranka(); - AddSC_boss_grilek(); + AddSC_boss_arlokk(); // zulgurub AddSC_boss_hakkar(); AddSC_boss_hazzarah(); AddSC_boss_jeklik(); @@ -606,19 +737,19 @@ 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(); AddSC_elwynn_forest(); AddSC_eversong_woods(); AddSC_ghostlands(); + AddSC_gilneas(); + AddSC_gilneas_city(); AddSC_hinterlands(); AddSC_ironforge(); AddSC_isle_of_queldanas(); @@ -631,52 +762,91 @@ void AddScripts() AddSC_stranglethorn_vale(); AddSC_swamp_of_sorrows(); AddSC_tirisfal_glades(); + AddSC_twilight_highlands(); AddSC_undercity(); + AddSC_vashjir(); AddSC_western_plaguelands(); AddSC_westfall(); AddSC_wetlands(); - //kalimdor + // kalimdor AddSC_instance_blackfathom_deeps(); // blackfathom deeps - AddSC_boss_aeonus(); // Opening the Dark Portal + AddSC_boss_aeonus(); // CoT, dark_portal AddSC_boss_chrono_lord_deja(); AddSC_boss_temporus(); AddSC_dark_portal(); AddSC_instance_dark_portal(); - AddSC_hyjal(); // Battle of Mount Hyjal + AddSC_boss_deathwing(); // CoT, dragon_soul + AddSC_boss_hagara(); + AddSC_boss_morchok(); + AddSC_boss_ultraxion(); + AddSC_boss_warlord_zonozz(); + AddSC_boss_warmaster_blackhorn(); + AddSC_boss_yorsahj(); + AddSC_dragon_soul(); + AddSC_instance_dragon_soul(); + AddSC_end_of_time(); // CoT, end_of_time + AddSC_instance_end_of_time(); + AddSC_boss_archbishop_benedictus(); // CoT, hour_of_twilight + AddSC_boss_arcurion(); + AddSC_boss_asira_dawnslayer(); + AddSC_instance_hour_of_twilight(); + AddSC_hyjal(); // CoT, hyjal AddSC_boss_archimonde(); AddSC_instance_mount_hyjal(); - AddSC_boss_captain_skarloc(); // Escape from Durnholde Keep - 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(); // Culling of Stratholme + AddSC_boss_infinite_corruptor(); + AddSC_boss_lord_epoch(); + AddSC_boss_malganis(); + AddSC_boss_meathook(); + AddSC_boss_salramm(); + AddSC_culling_of_stratholmeAI(); + AddSC_culling_of_stratholme(); // CoT, culling_of_stratholme AddSC_instance_culling_of_stratholme(); - AddSC_boss_celebras_the_cursed(); //maraudon - AddSC_boss_landslide(); - AddSC_boss_noxxion(); - AddSC_boss_ptheradras(); - AddSC_boss_onyxia(); //onyxias_lair + AddSC_trash_culling_of_stratholme(); + AddSC_boss_mannoroth_and_varothen(); // CoT, well_of_eternity + AddSC_boss_perotharn(); + AddSC_boss_queen_azshara(); + AddSC_instance_well_of_eternity(); + AddSC_dire_maul(); // dire_maul + AddSC_instance_dire_maul(); + AddSC_boss_noxxion(); // maraudon + AddSC_boss_onyxia(); // onyxias_lair AddSC_instance_onyxias_lair(); - AddSC_boss_amnennar_the_coldbringer(); //razorfen_downs - AddSC_razorfen_downs(); - AddSC_instance_razorfen_kraul(); //razorfen_kraul - AddSC_boss_ayamiss(); //ruins_of_ahnqiraj + AddSC_razorfen_downs(); // razorfen_downs + AddSC_boss_tuten_kash(); + AddSC_instance_razorfen_kraul(); // razorfen_kraul + AddSC_razorfen_kraul(); + AddSC_boss_ayamiss(); // ruins_of_ahnqiraj + AddSC_boss_buru(); AddSC_boss_kurinnaxx(); + AddSC_boss_ossirian(); AddSC_boss_moam(); + AddSC_boss_rajaxx(); AddSC_ruins_of_ahnqiraj(); - AddSC_boss_cthun(); //temple_of_ahnqiraj + AddSC_instance_ruins_of_ahnqiraj(); + AddSC_boss_cthun(); // temple_of_ahnqiraj AddSC_boss_fankriss(); AddSC_boss_huhuran(); AddSC_bug_trio(); AddSC_boss_sartura(); AddSC_boss_skeram(); AddSC_boss_twinemperors(); + AddSC_boss_viscidus(); AddSC_mob_anubisath_sentinel(); AddSC_instance_temple_of_ahnqiraj(); - AddSC_instance_wailing_caverns(); // Wailing Caverns - AddSC_zulfarrak(); //zulfarrak + AddSC_boss_alakir(); // throne_of_the_four_winds + AddSC_conclave_of_the_wind(); + AddSC_instance_throne_of_the_four_winds(); + AddSC_boss_altairus(); // vortex_pinnacle + AddSC_boss_asaad(); + AddSC_boss_grand_vizier_etan(); + AddSC_instance_vortex_pinnacle(); + AddSC_instance_wailing_caverns(); // wailing_caverns + AddSC_wailing_caverns(); + AddSC_boss_zumrah(); // zulfarrak + AddSC_zulfarrak(); AddSC_instance_zulfarrak(); AddSC_ashenvale(); @@ -686,10 +856,13 @@ void AddScripts() AddSC_boss_azuregos(); AddSC_darkshore(); AddSC_desolace(); + AddSC_durotar(); AddSC_dustwallow_marsh(); AddSC_felwood(); AddSC_feralas(); + AddSC_molten_front(); AddSC_moonglade(); + AddSC_mount_hyjal(); AddSC_mulgore(); AddSC_orgrimmar(); AddSC_silithus(); @@ -699,48 +872,92 @@ void AddScripts() AddSC_the_barrens(); AddSC_thousand_needles(); AddSC_thunder_bluff(); + AddSC_uldum(); AddSC_ungoro_crater(); AddSC_winterspring(); - //northrend - AddSC_boss_jedoga(); //ahnkahet + // maelstrom + AddSC_instance_stonecore(); + AddSC_stonecore(); + AddSC_boss_corborus(); // stonecore + AddSC_boss_ozruk(); + AddSC_boss_priestess_azil(); + AddSC_boss_slabhide(); + + AddSC_deepholm(); + AddSC_kezan(); + AddSC_lost_isles(); + + // northrend + AddSC_boss_amanitar(); // azjol-nerub, ahnkahet + AddSC_boss_jedoga(); AddSC_boss_nadox(); AddSC_boss_taldaram(); AddSC_boss_volazj(); AddSC_instance_ahnkahet(); - AddSC_boss_anubarak(); //azjol-nerub + AddSC_boss_anubarak(); // azjol-nerub, azjol-nerub AddSC_boss_hadronox(); AddSC_boss_krikthir(); AddSC_instance_azjol_nerub(); - AddSC_boss_anubarak_trial(); //trial_of_the_crusader + AddSC_boss_grand_champions(); // CC, trial_of_the_champion + AddSC_instance_trial_of_the_champion(); + AddSC_trial_of_the_champion(); + AddSC_boss_argent_challenge(); + AddSC_boss_black_knight(); + AddSC_boss_anubarak_trial(); // CC, trial_of_the_crusader + AddSC_boss_faction_champions(); AddSC_boss_jaraxxus(); AddSC_instance_trial_of_the_crusader(); AddSC_northrend_beasts(); AddSC_trial_of_the_crusader(); AddSC_twin_valkyr(); - AddSC_boss_novos(); //draktharon_keep + AddSC_boss_novos(); // draktharon_keep + AddSC_boss_dred(); AddSC_boss_tharonja(); AddSC_boss_trollgore(); AddSC_instance_draktharon_keep(); - AddSC_boss_colossus(); //gundrak + AddSC_boss_colossus(); // gundrak AddSC_boss_eck(); AddSC_boss_galdarah(); AddSC_boss_moorabi(); AddSC_boss_sladran(); AddSC_instance_gundrak(); - AddSC_boss_bronjahm(); // ICC, forge_of_souls + AddSC_boss_bronjahm(); // ICC, FH, forge_of_souls AddSC_boss_devourer_of_souls(); AddSC_instance_forge_of_souls(); - AddSC_boss_gafrost(); // ICC, pit_of_saron + AddSC_forge_of_souls(); + AddSC_boss_falric(); // ICC, FH, halls_of_reflection + AddSC_boss_lich_king_hr(); + AddSC_boss_marwyn(); + AddSC_halls_of_reflection(); + AddSC_instance_halls_of_reflection(); + AddSC_boss_garfrost(); // ICC, FH, pit_of_saron AddSC_boss_krick_and_ick(); AddSC_boss_tyrannus(); AddSC_instance_pit_of_saron(); AddSC_pit_of_saron(); - AddSC_boss_anubrekhan(); //naxxramas + AddSC_blood_prince_council(); // ICC, icecrown_citadel + AddSC_boss_blood_queen_lanathel(); + AddSC_boss_deathbringer_saurfang(); + AddSC_boss_festergut(); + AddSC_boss_lady_deathwhisper(); + AddSC_boss_lord_marrowgar(); + AddSC_boss_professor_putricide(); + AddSC_boss_rotface(); + AddSC_boss_sindragosa(); + AddSC_boss_lich_king_icc(); + AddSC_boss_valithria_dreamwalker(); + AddSC_gunship_battle(); + AddSC_instance_icecrown_citadel(); + AddSC_icecrown_spire(); + AddSC_icecrown_teleporter(); + AddSC_icecrown_lights_hammer(); + AddSC_boss_anubrekhan(); // naxxramas AddSC_boss_four_horsemen(); AddSC_boss_faerlina(); AddSC_boss_gluth(); AddSC_boss_gothik(); + AddSC_boss_grobbulus(); AddSC_boss_kelthuzad(); AddSC_boss_loatheb(); AddSC_boss_maexxna(); @@ -749,24 +966,40 @@ void AddScripts() AddSC_boss_patchwerk(); AddSC_boss_razuvious(); AddSC_boss_sapphiron(); + AddSC_boss_thaddius(); AddSC_instance_naxxramas(); - AddSC_boss_anomalus(); //nexus + AddSC_boss_malygos(); // nexus, eye_of_eternity + AddSC_instance_eye_of_eternity(); + AddSC_boss_anomalus(); // nexus, nexus AddSC_boss_keristrasza(); AddSC_boss_ormorok(); AddSC_boss_telestra(); AddSC_instance_nexus(); - AddSC_boss_sartharion(); //obsidian_sanctum + AddSC_boss_drakos(); // nexus, oculus + 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_bjarngrim(); //Ulduar, halls_of_lightning + AddSC_boss_baltharus(); // ruby_sanctum + AddSC_boss_halion(); + AddSC_boss_saviana(); + AddSC_boss_zarithrian(); + AddSC_instance_ruby_sanctum(); + AddSC_ruby_sanctum(); + AddSC_boss_bjarngrim(); // ulduar, halls_of_lightning AddSC_boss_ionar(); AddSC_boss_loken(); AddSC_boss_volkhan(); AddSC_instance_halls_of_lightning(); - AddSC_boss_maiden_of_grief(); //Ulduar, halls_of_stone + AddSC_boss_maiden_of_grief(); // ulduar, halls_of_stone AddSC_boss_sjonnir(); + AddSC_boss_krystallus(); AddSC_halls_of_stone(); AddSC_instance_halls_of_stone(); - AddSC_boss_assembly_of_iron(); //ulduar + AddSC_boss_assembly_of_iron(); // ulduar, ulduar AddSC_boss_algalon(); AddSC_boss_auriaya(); AddSC_boss_flame_leviathan(); @@ -781,41 +1014,58 @@ void AddScripts() AddSC_boss_xt_002(); AddSC_boss_yogg_saron(); AddSC_instance_ulduar(); - AddSC_boss_ingvar(); //utgarde_keep + AddSC_ulduar(); + AddSC_boss_ingvar(); // UK, utgarde_keep AddSC_boss_keleseth(); AddSC_boss_skarvald_and_dalronn(); AddSC_instance_utgarde_keep(); AddSC_utgarde_keep(); - AddSC_boss_gortok(); //utgarde_pinnacle + AddSC_boss_gortok(); // UK, utgarde_pinnacle AddSC_boss_skadi(); AddSC_boss_svala(); AddSC_boss_ymiron(); AddSC_instance_pinnacle(); - AddSC_instance_violet_hold(); //violet_hold + AddSC_boss_archavon(); // vault_of_archavon + AddSC_boss_emalon(); + AddSC_boss_koralon(); + AddSC_boss_toravon(); + AddSC_instance_vault_of_archavon(); + AddSC_boss_erekem(); // violet_hold + AddSC_boss_ichoron(); + AddSC_instance_violet_hold(); AddSC_violet_hold(); + AddSC_boss_cyanigosa(); + AddSC_boss_moragg(); + AddSC_boss_xevozz(); + AddSC_boss_zuramat(); + AddSC_boss_lavanthor(); AddSC_borean_tundra(); AddSC_dalaran(); AddSC_dragonblight(); + AddSC_grizzly_hills(); AddSC_howling_fjord(); AddSC_icecrown(); AddSC_sholazar_basin(); AddSC_storm_peaks(); + AddSC_wintergrasp(); AddSC_zuldrak(); - //outland - AddSC_boss_exarch_maladaar(); //auchindoun, auchenai_crypts - AddSC_boss_nexusprince_shaffar(); //auchindoun, mana_tombs + // outland + AddSC_boss_exarch_maladaar(); // auchindoun, auchenai_crypts + AddSC_boss_shirrak(); + AddSC_boss_nexusprince_shaffar(); // auchindoun, mana_tombs AddSC_boss_pandemonius(); - AddSC_boss_darkweaver_syth(); //auchindoun, sethekk_halls + AddSC_boss_anzu(); // auchindoun, sethekk_halls + AddSC_boss_darkweaver_syth(); AddSC_boss_talon_king_ikiss(); AddSC_instance_sethekk_halls(); - AddSC_boss_ambassador_hellmaw(); //auchindoun, shadow_labyrinth + AddSC_boss_ambassador_hellmaw(); // auchindoun, shadow_labyrinth AddSC_boss_blackheart_the_inciter(); AddSC_boss_grandmaster_vorpil(); AddSC_boss_murmur(); AddSC_instance_shadow_labyrinth(); - AddSC_black_temple(); //black_temple + AddSC_black_temple(); // black_temple AddSC_boss_illidan(); AddSC_boss_shade_of_akama(); AddSC_boss_supremus(); @@ -826,48 +1076,50 @@ void AddScripts() AddSC_boss_najentus(); AddSC_boss_illidari_council(); AddSC_instance_black_temple(); - AddSC_boss_fathomlord_karathress(); //CR, serpent_shrine + AddSC_boss_fathomlord_karathress(); // CR, serpent_shrine AddSC_boss_hydross_the_unstable(); AddSC_boss_lady_vashj(); AddSC_boss_leotheras_the_blind(); AddSC_boss_morogrim_tidewalker(); AddSC_boss_the_lurker_below(); AddSC_instance_serpentshrine_cavern(); - AddSC_boss_hydromancer_thespia(); //CR, steam_vault + AddSC_boss_ahune(); // CR, slave_pens + AddSC_boss_hydromancer_thespia(); // CR, steam_vault AddSC_boss_mekgineer_steamrigger(); AddSC_boss_warlord_kalithresh(); AddSC_instance_steam_vault(); - AddSC_boss_hungarfen(); //CR, Underbog - AddSC_boss_gruul(); //gruuls_lair + AddSC_boss_hungarfen(); // CR, Underbog + AddSC_boss_gruul(); // gruuls_lair AddSC_boss_high_king_maulgar(); AddSC_instance_gruuls_lair(); - AddSC_boss_broggok(); //HC, blood_furnace + AddSC_boss_broggok(); // HC, blood_furnace AddSC_boss_kelidan_the_breaker(); AddSC_boss_the_maker(); AddSC_instance_blood_furnace(); - AddSC_boss_nazan_and_vazruden(); //HC, hellfire_ramparts + AddSC_boss_nazan_and_vazruden(); // HC, hellfire_ramparts AddSC_boss_omor_the_unscarred(); AddSC_boss_watchkeeper_gargolmar(); AddSC_instance_ramparts(); - AddSC_boss_magtheridon(); //HC, magtheridons_lair + AddSC_boss_magtheridon(); // HC, magtheridons_lair AddSC_instance_magtheridons_lair(); - AddSC_boss_grand_warlock_nethekurse(); //HC, shattered_halls + AddSC_boss_grand_warlock_nethekurse(); // HC, shattered_halls AddSC_boss_warbringer_omrogg(); AddSC_boss_warchief_kargath_bladefist(); AddSC_instance_shattered_halls(); - AddSC_arcatraz(); //TK, arcatraz + 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_high_botanist_freywinn(); // TK, botanica AddSC_boss_laj(); AddSC_boss_warp_splinter(); - AddSC_boss_kaelthas(); //TK, the_eye - AddSC_boss_void_reaver(); + AddSC_boss_alar(); // TK, the_eye AddSC_boss_high_astromancer_solarian(); + 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 3414f7f83d..8f2a11e37d 100644 --- a/system/ScriptLoader.h +++ b/system/ScriptLoader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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 244f69bebc..e276c262af 100644 --- a/system/system.cpp +++ b/system/system.cpp @@ -1,9 +1,10 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #include "precompiled.h" #include "system.h" +#include "../config.h" #include "ProgressBar.h" #include "ObjectMgr.h" #include "Database/DatabaseEnv.h" @@ -23,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) @@ -32,140 +33,31 @@ void SystemMgr::LoadVersion() strSD2Version = pFields[0].GetCppString(); - outstring_log("Loading %s", strSD2Version.c_str()); - outstring_log(""); - delete pResult; } else - { - error_log("SD2: Missing `sd2_db_version` information."); - outstring_log(""); - } + script_error_log("Missing `sd2_db_version` information."); + + // Setup version info and display it + if (strSD2Version.empty()) + strSD2Version.append("ScriptDev2 "); + + strSD2Version.append(SD2_FULLVERSION); + + outstring_log("Loading %s", strSD2Version.c_str()); + // outstring_log(""); } 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() @@ -195,7 +87,7 @@ void SystemMgr::LoadScriptWaypoints() if (pResult) { - barGoLink bar(pResult->GetRowCount()); + BarGoLink bar(pResult->GetRowCount()); uint32 uiNodeCount = 0; do @@ -225,18 +117,19 @@ void SystemMgr::LoadScriptWaypoints() m_mPointMoveMap[uiEntry].push_back(pTemp); ++uiNodeCount; - } while (pResult->NextRow()); + } + while (pResult->NextRow()); delete pResult; - outstring_log(""); + // outstring_log(""); outstring_log(">> Loaded %u Script Waypoint nodes.", uiNodeCount); } else { - barGoLink bar(1); + BarGoLink bar(1); bar.step(); - outstring_log(""); + // outstring_log(""); outstring_log(">> Loaded 0 Script Waypoints. DB table `script_waypoint` is empty."); } } diff --git a/system/system.h b/system/system.h index c0f3be7bfb..e718650d59 100644 --- a/system/system.h +++ b/system/system.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2010 ScriptDev2 +/* Copyright (C) 2006 - 2013 ScriptDev2 * 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 from database +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,30 +19,6 @@ extern std::string strSD2Version; //version info from #define TEXT_SOURCE_GOSSIP_START TEXT_SOURCE_RANGE*3 #define TEXT_SOURCE_GOSSIP_END TEXT_SOURCE_RANGE*4 + 1 -//TODO: find better namings and definitions. -//N=Neutral, A=Alliance, H=Horde. -//NEUTRAL or FRIEND = Hostility to player surroundings (not a good definition) -//ACTIVE or PASSIVE = Hostility to environment surroundings. -enum eEscortFaction -{ - FACTION_ESCORT_A_NEUTRAL_PASSIVE = 10, - FACTION_ESCORT_H_NEUTRAL_PASSIVE = 33, - FACTION_ESCORT_N_NEUTRAL_PASSIVE = 113, - - FACTION_ESCORT_A_NEUTRAL_ACTIVE = 231, - FACTION_ESCORT_H_NEUTRAL_ACTIVE = 232, - FACTION_ESCORT_N_NEUTRAL_ACTIVE = 250, - - FACTION_ESCORT_N_FRIEND_PASSIVE = 290, - FACTION_ESCORT_N_FRIEND_ACTIVE = 495, - - FACTION_ESCORT_A_PASSIVE = 774, - FACTION_ESCORT_H_PASSIVE = 775, - - FACTION_ESCORT_N_ACTIVE = 1986, - FACTION_ESCORT_H_ACTIVE = 2046 -}; - struct ScriptPointMove { uint32 uiCreatureEntry; @@ -53,14 +29,6 @@ struct ScriptPointMove uint32 uiWaitTime; }; -struct StringTextData -{ - uint32 uiSoundId; - uint8 uiType; - uint32 uiLanguage; - uint32 uiEmote; -}; - #define pSystemMgr SystemMgr::Instance() class SystemMgr @@ -71,29 +39,16 @@ class SystemMgr static SystemMgr& Instance(); - //Maps and lists - typedef UNORDERED_MAP TextDataMap; typedef UNORDERED_MAP > PointMoveMap; - //Database + // Database void LoadVersion(); void LoadScriptTexts(); void LoadScriptTextsCustom(); void LoadScriptGossipTexts(); void LoadScriptWaypoints(); - //Retrive from storage - StringTextData const* GetTextData(int32 uiTextId) const - { - TextDataMap::const_iterator itr = m_mTextDataMap.find(uiTextId); - - if (itr == m_mTextDataMap.end()) - return NULL; - - return &itr->second; - } - - std::vector const &GetPointMoveList(uint32 uiCreatureEntry) const + std::vector const& GetPointMoveList(uint32 uiCreatureEntry) const { static std::vector vEmpty; @@ -106,8 +61,7 @@ class SystemMgr } protected: - TextDataMap m_mTextDataMap; //additional data for text strings - PointMoveMap m_mPointMoveMap; //coordinates for waypoints + PointMoveMap m_mPointMoveMap; // coordinates for waypoints }; #endif